forked from Rust-related/RustPython
Merge branch 'master' of https://github.com/rustpython/rustpython
This commit is contained in:
16
.travis.yml
16
.travis.yml
@@ -12,8 +12,9 @@ before_cache:
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- name: Run Rust tests
|
||||
- name: Run Rust tests(linux)
|
||||
language: rust
|
||||
os: linux
|
||||
rust: stable
|
||||
cache: cargo
|
||||
script:
|
||||
@@ -24,6 +25,19 @@ matrix:
|
||||
# See: https://docs.travis-ci.com/user/caching/#caches-and-build-matrices
|
||||
- JOBCACHE=1
|
||||
|
||||
- name: Run Rust tests(osx)
|
||||
language: rust
|
||||
os: osx
|
||||
rust: stable
|
||||
cache: cargo
|
||||
script:
|
||||
- cargo build --verbose --all
|
||||
- cargo test --verbose --all
|
||||
env:
|
||||
# Prevention of cache corruption.
|
||||
# See: https://docs.travis-ci.com/user/caching/#caches-and-build-matrices
|
||||
- JOBCACHE=11
|
||||
|
||||
# To test the snippets, we use Travis' Python environment (because
|
||||
# installing rust ourselves is a lot easier than installing Python)
|
||||
- name: Python test snippets
|
||||
|
||||
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -731,6 +731,16 @@ dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.2.1"
|
||||
@@ -1168,6 +1178,7 @@ dependencies = [
|
||||
"num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -2102,6 +2113,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718"
|
||||
"checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"
|
||||
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
||||
|
||||
171
Lib/imghdr.py
Normal file
171
Lib/imghdr.py
Normal file
@@ -0,0 +1,171 @@
|
||||
"""Recognize image file formats based on their first few bytes."""
|
||||
|
||||
#from os import PathLike
|
||||
|
||||
__all__ = ["what"]
|
||||
|
||||
# should replace using FileIO into file
|
||||
from io import FileIO
|
||||
#-------------------------#
|
||||
# Recognize image headers #
|
||||
#-------------------------#
|
||||
|
||||
def what(file, h=None):
|
||||
f = None
|
||||
try:
|
||||
if h is None:
|
||||
# if isinstance(file, (str, PathLike))
|
||||
if isinstance(file, str): # FIXME(corona10): RustPython doesn't support PathLike yet.
|
||||
f = FileIO(file, 'rb')
|
||||
h = f.read(32)
|
||||
else:
|
||||
location = file.tell()
|
||||
h = file.read(32)
|
||||
file.seek(location)
|
||||
for tf in tests:
|
||||
res = tf(h, f)
|
||||
if res:
|
||||
return res
|
||||
finally:
|
||||
if f: f.close()
|
||||
return None
|
||||
|
||||
|
||||
#---------------------------------#
|
||||
# Subroutines per image file type #
|
||||
#---------------------------------#
|
||||
|
||||
tests = []
|
||||
|
||||
def test_jpeg(h, f):
|
||||
"""JPEG data in JFIF or Exif format"""
|
||||
if h[6:10] in (b'JFIF', b'Exif'):
|
||||
return 'jpeg'
|
||||
|
||||
tests.append(test_jpeg)
|
||||
|
||||
def test_png(h, f):
|
||||
if h.startswith(b'\211PNG\r\n\032\n'):
|
||||
return 'png'
|
||||
|
||||
tests.append(test_png)
|
||||
|
||||
def test_gif(h, f):
|
||||
"""GIF ('87 and '89 variants)"""
|
||||
if h[:6] in (b'GIF87a', b'GIF89a'):
|
||||
return 'gif'
|
||||
|
||||
tests.append(test_gif)
|
||||
|
||||
def test_tiff(h, f):
|
||||
"""TIFF (can be in Motorola or Intel byte order)"""
|
||||
if h[:2] in (b'MM', b'II'):
|
||||
return 'tiff'
|
||||
|
||||
tests.append(test_tiff)
|
||||
|
||||
def test_rgb(h, f):
|
||||
"""SGI image library"""
|
||||
if h.startswith(b'\001\332'):
|
||||
return 'rgb'
|
||||
|
||||
tests.append(test_rgb)
|
||||
|
||||
def test_pbm(h, f):
|
||||
"""PBM (portable bitmap)"""
|
||||
if len(h) >= 3 and \
|
||||
h[0] == ord(b'P') and h[1] in b'14' and h[2] in b' \t\n\r':
|
||||
return 'pbm'
|
||||
|
||||
tests.append(test_pbm)
|
||||
|
||||
def test_pgm(h, f):
|
||||
"""PGM (portable graymap)"""
|
||||
if len(h) >= 3 and \
|
||||
h[0] == ord(b'P') and h[1] in b'25' and h[2] in b' \t\n\r':
|
||||
return 'pgm'
|
||||
|
||||
tests.append(test_pgm)
|
||||
|
||||
def test_ppm(h, f):
|
||||
"""PPM (portable pixmap)"""
|
||||
if len(h) >= 3 and \
|
||||
h[0] == ord(b'P') and h[1] in b'36' and h[2] in b' \t\n\r':
|
||||
return 'ppm'
|
||||
|
||||
tests.append(test_ppm)
|
||||
|
||||
def test_rast(h, f):
|
||||
"""Sun raster file"""
|
||||
if h.startswith(b'\x59\xA6\x6A\x95'):
|
||||
return 'rast'
|
||||
|
||||
tests.append(test_rast)
|
||||
|
||||
def test_xbm(h, f):
|
||||
"""X bitmap (X10 or X11)"""
|
||||
if h.startswith(b'#define '):
|
||||
return 'xbm'
|
||||
|
||||
tests.append(test_xbm)
|
||||
|
||||
def test_bmp(h, f):
|
||||
if h.startswith(b'BM'):
|
||||
return 'bmp'
|
||||
|
||||
tests.append(test_bmp)
|
||||
|
||||
def test_webp(h, f):
|
||||
if h.startswith(b'RIFF') and h[8:12] == b'WEBP':
|
||||
return 'webp'
|
||||
|
||||
tests.append(test_webp)
|
||||
|
||||
def test_exr(h, f):
|
||||
if h.startswith(b'\x76\x2f\x31\x01'):
|
||||
return 'exr'
|
||||
|
||||
tests.append(test_exr)
|
||||
|
||||
#--------------------#
|
||||
# Small test program #
|
||||
#--------------------#
|
||||
|
||||
def test():
|
||||
import sys
|
||||
recursive = 0
|
||||
if sys.argv[1:] and sys.argv[1] == '-r':
|
||||
del sys.argv[1:2]
|
||||
recursive = 1
|
||||
try:
|
||||
if sys.argv[1:]:
|
||||
testall(sys.argv[1:], recursive, 1)
|
||||
else:
|
||||
testall(['.'], recursive, 1)
|
||||
except KeyboardInterrupt:
|
||||
sys.stderr.write('\n[Interrupted]\n')
|
||||
sys.exit(1)
|
||||
|
||||
def testall(list, recursive, toplevel):
|
||||
import sys
|
||||
import os
|
||||
for filename in list:
|
||||
if os.path.isdir(filename):
|
||||
print(filename + '/:', end=' ')
|
||||
if recursive or toplevel:
|
||||
print('recursing down:')
|
||||
import glob
|
||||
names = glob.glob(os.path.join(filename, '*'))
|
||||
testall(names, recursive, 0)
|
||||
else:
|
||||
print('*** directory (use -r) ***')
|
||||
else:
|
||||
print(filename + ':', end=' ')
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
print(what(filename))
|
||||
except OSError:
|
||||
print('*** not found ***')
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
|
||||
@@ -19,8 +20,11 @@ benchmarks = [
|
||||
['benchmarks/mandelbrot.py'],
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize('exe', pythons)
|
||||
@pytest.mark.parametrize('args', benchmarks)
|
||||
exe_ids = ['cpython', 'rustpython']
|
||||
benchmark_ids = [benchmark[0].split('/')[-1] for benchmark in benchmarks]
|
||||
|
||||
@pytest.mark.parametrize('exe', pythons, ids=exe_ids)
|
||||
@pytest.mark.parametrize('args', benchmarks, ids=benchmark_ids)
|
||||
def test_bench(exe, args, benchmark):
|
||||
def bench():
|
||||
subprocess.run([exe] + args)
|
||||
|
||||
@@ -204,8 +204,25 @@ impl SymbolTableAnalyzer {
|
||||
// all is well
|
||||
}
|
||||
SymbolScope::Unknown => {
|
||||
if symbol.is_assigned {
|
||||
// Try hard to figure out what the scope of this symbol is.
|
||||
|
||||
if symbol.is_assigned || symbol.is_parameter {
|
||||
symbol.scope = SymbolScope::Local;
|
||||
} else {
|
||||
// TODO: comment this out and make it work properly:
|
||||
/*
|
||||
let found_in_outer_scope = self
|
||||
.tables
|
||||
.iter()
|
||||
.any(|t| t.symbols.contains_key(&symbol.name));
|
||||
if found_in_outer_scope {
|
||||
// Symbol is in some outer scope.
|
||||
|
||||
} else {
|
||||
// Well, it must be a global then :)
|
||||
// symbol.scope = SymbolScope::Global;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -713,7 +730,10 @@ impl SymbolTableBuilder {
|
||||
});
|
||||
}
|
||||
}
|
||||
SymbolUsage::Parameter | SymbolUsage::Assigned => {
|
||||
SymbolUsage::Parameter => {
|
||||
symbol.is_parameter = true;
|
||||
}
|
||||
SymbolUsage::Assigned => {
|
||||
symbol.is_assigned = true;
|
||||
}
|
||||
SymbolUsage::Global => {
|
||||
|
||||
@@ -24,7 +24,7 @@ pub enum Top {
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Program {
|
||||
pub statements: Vec<Statement>,
|
||||
pub statements: Suite,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -40,6 +40,7 @@ pub struct Located<T> {
|
||||
}
|
||||
|
||||
pub type Statement = Located<StatementType>;
|
||||
pub type Suite = Vec<Statement>;
|
||||
|
||||
/// Abstract syntax tree nodes for python statements.
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -90,39 +91,39 @@ pub enum StatementType {
|
||||
},
|
||||
If {
|
||||
test: Expression,
|
||||
body: Vec<Statement>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
body: Suite,
|
||||
orelse: Option<Suite>,
|
||||
},
|
||||
While {
|
||||
test: Expression,
|
||||
body: Vec<Statement>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
body: Suite,
|
||||
orelse: Option<Suite>,
|
||||
},
|
||||
With {
|
||||
is_async: bool,
|
||||
items: Vec<WithItem>,
|
||||
body: Vec<Statement>,
|
||||
body: Suite,
|
||||
},
|
||||
For {
|
||||
is_async: bool,
|
||||
target: Box<Expression>,
|
||||
iter: Box<Expression>,
|
||||
body: Vec<Statement>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
body: Suite,
|
||||
orelse: Option<Suite>,
|
||||
},
|
||||
Raise {
|
||||
exception: Option<Expression>,
|
||||
cause: Option<Expression>,
|
||||
},
|
||||
Try {
|
||||
body: Vec<Statement>,
|
||||
body: Suite,
|
||||
handlers: Vec<ExceptHandler>,
|
||||
orelse: Option<Vec<Statement>>,
|
||||
finalbody: Option<Vec<Statement>>,
|
||||
orelse: Option<Suite>,
|
||||
finalbody: Option<Suite>,
|
||||
},
|
||||
ClassDef {
|
||||
name: String,
|
||||
body: Vec<Statement>,
|
||||
body: Suite,
|
||||
bases: Vec<Expression>,
|
||||
keywords: Vec<Keyword>,
|
||||
decorator_list: Vec<Expression>,
|
||||
@@ -131,7 +132,7 @@ pub enum StatementType {
|
||||
is_async: bool,
|
||||
name: String,
|
||||
args: Box<Parameters>,
|
||||
body: Vec<Statement>,
|
||||
body: Suite,
|
||||
decorator_list: Vec<Expression>,
|
||||
returns: Option<Expression>,
|
||||
},
|
||||
@@ -331,7 +332,7 @@ pub struct ExceptHandler {
|
||||
pub location: Location,
|
||||
pub typ: Option<Expression>,
|
||||
pub name: Option<String>,
|
||||
pub body: Vec<Statement>,
|
||||
pub body: Suite,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
||||
@@ -31,22 +31,22 @@ Program: ast::Program = {
|
||||
};
|
||||
|
||||
// A file line either has a declaration, or an empty newline:
|
||||
FileLine: Vec<ast::Statement> = {
|
||||
FileLine: ast::Suite = {
|
||||
Statement,
|
||||
"\n" => vec![],
|
||||
};
|
||||
|
||||
Suite: Vec<ast::Statement> = {
|
||||
Suite: ast::Suite = {
|
||||
SimpleStatement,
|
||||
"\n" indent <s:Statement+> dedent => s.into_iter().flatten().collect(),
|
||||
};
|
||||
|
||||
Statement: Vec<ast::Statement> = {
|
||||
Statement: ast::Suite = {
|
||||
SimpleStatement,
|
||||
<s:CompoundStatement> => vec![s],
|
||||
};
|
||||
|
||||
SimpleStatement: Vec<ast::Statement> = {
|
||||
SimpleStatement: ast::Suite = {
|
||||
<s1:SmallStatement> <s2:(";" SmallStatement)*> ";"? "\n" => {
|
||||
let mut statements = vec![s1];
|
||||
statements.extend(s2.into_iter().map(|e| e.1));
|
||||
@@ -365,7 +365,7 @@ ForStatement: ast::Statement = {
|
||||
};
|
||||
|
||||
TryStatement: ast::Statement = {
|
||||
<location:@L> "try" ":" <body:Suite> <handlers:ExceptClause*> <else_suite:("else" ":" Suite)?> <finally:("finally" ":" Suite)?> => {
|
||||
<location:@L> "try" ":" <body:Suite> <handlers:ExceptClause+> <else_suite:("else" ":" Suite)?> <finally:("finally" ":" Suite)?> => {
|
||||
let orelse = else_suite.map(|s| s.2);
|
||||
let finalbody = finally.map(|s| s.2);
|
||||
ast::Statement {
|
||||
@@ -378,6 +378,20 @@ TryStatement: ast::Statement = {
|
||||
},
|
||||
}
|
||||
},
|
||||
<location:@L> "try" ":" <body:Suite> <finally:("finally" ":" Suite)> => {
|
||||
let handlers = vec![];
|
||||
let orelse = None;
|
||||
let finalbody = Some(finally.2);
|
||||
ast::Statement {
|
||||
location,
|
||||
node: ast::StatementType::Try {
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
finalbody,
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
ExceptClause: ast::ExceptHandler = {
|
||||
|
||||
1
py_code_object/.gitignore
vendored
1
py_code_object/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
target
|
||||
241
py_code_object/Cargo.lock
generated
241
py_code_object/Cargo.lock
generated
@@ -1,241 +0,0 @@
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "py_code_object"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustpython_vm 0.1.0",
|
||||
"serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustpython_vm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_codegen"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_codegen_internals"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_codegen 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
||||
"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
|
||||
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
|
||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||
"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
|
||||
"checksum serde_codegen 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c5d8a33087d8984f9535daa62a6498a08f6476050b00ab9339dd847e4c25cc"
|
||||
"checksum serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "afad7924a009f859f380e4a2e3a509a845c2ac66435fcead74a4d983b21ae806"
|
||||
"checksum serde_derive 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "ce44e5f4264b39e9d29c875357b7cc3ebdfb967bb9e22bfb5e44ffa400af5306"
|
||||
"checksum serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "67f7d2e9edc3523a9c8ec8cd6ec481b3a27810aafee3e625d311febd3e656b4c"
|
||||
"checksum syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)" = "58fd09df59565db3399efbba34ba8a2fec1307511ebd245d0061ff9d42691673"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
@@ -1,13 +0,0 @@
|
||||
[package]
|
||||
name = "py_code_object"
|
||||
version = "0.1.0"
|
||||
authors = ["Shing Lyu <shing.lyu@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
env_logger = "0.3"
|
||||
serde = "0.8.22"
|
||||
serde_derive = "0.8"
|
||||
serde_json = "0.8"
|
||||
rustpython_vm = {path = "../vm"}
|
||||
@@ -1,3 +0,0 @@
|
||||
This crate contains the Rust representation of the CPython PyCodeObject.
|
||||
|
||||
It has to be compatible with CPython output, so when you edit this crate please run the test suite in `vm/`.
|
||||
219
py_code_object/python_compiler/Cargo.lock
generated
219
py_code_object/python_compiler/Cargo.lock
generated
@@ -1,219 +0,0 @@
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpython"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/dgrunwald/rust-cpython.git#50e96c9755630604eab09587c8976a8a9c096a7d"
|
||||
dependencies = [
|
||||
"libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"python3-sys 0.2.0 (git+https://github.com/dgrunwald/rust-cpython.git)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "python27-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python3-sys"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/dgrunwald/rust-cpython.git#50e96c9755630604eab09587c8976a8a9c096a7d"
|
||||
dependencies = [
|
||||
"libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python_compiler"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cpython 0.2.0 (git+https://github.com/dgrunwald/rust-cpython.git)",
|
||||
"python27-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
||||
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
|
||||
"checksum cpython 0.2.0 (git+https://github.com/dgrunwald/rust-cpython.git)" = "<none>"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
"checksum libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)" = "ac8ebf8343a981e2fa97042b14768f02ed3e1d602eac06cae6166df3c8ced206"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
||||
"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
|
||||
"checksum python27-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4daec30bfe241e55f2c905cee2badf176ae2be49d9bddf4267103fea780238c3"
|
||||
"checksum python3-sys 0.2.0 (git+https://github.com/dgrunwald/rust-cpython.git)" = "<none>"
|
||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
|
||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
|
||||
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
@@ -1,11 +0,0 @@
|
||||
[package]
|
||||
name = "python_compiler"
|
||||
version = "0.1.0"
|
||||
authors = ["Shing Lyu <shing.lyu@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cpython = { git = "https://github.com/dgrunwald/rust-cpython.git" }
|
||||
|
||||
[dependencies.python27-sys]
|
||||
version = "*"
|
||||
@@ -1,7 +0,0 @@
|
||||
extern crate python_compiler;
|
||||
|
||||
use python_compiler::python_compiler::compile;
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", compile());
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
extern crate cpython;
|
||||
extern crate python27_sys;
|
||||
|
||||
pub mod python_compiler;
|
||||
@@ -1,35 +0,0 @@
|
||||
use cpython::Python;
|
||||
use cpython::ObjectProtocol; //for call method
|
||||
use cpython::PyObject;
|
||||
use cpython::PyDict;
|
||||
use python27_sys::PyCodeObject;
|
||||
|
||||
|
||||
//pub fn compile() -> PyObject {
|
||||
pub fn compile(){
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let locals = PyDict::new(py);
|
||||
// TODO: read the filename from commandline
|
||||
//locals.set_item(py, "filename", "../tests/function.py").unwrap();
|
||||
|
||||
let load_file = "\
|
||||
import os
|
||||
print(os.getcwd())
|
||||
filename = '../tests/function.py'
|
||||
with open(filename, 'rU') as f:\
|
||||
code = f.read()\
|
||||
";
|
||||
py.run(load_file, None, Some(&locals)).unwrap();
|
||||
let code = py.eval("compile(code, \"foo\", \"exec\")", None, Some(&locals)).unwrap();
|
||||
//println!("{:?}", code.getattr(py, "co_name").unwrap());
|
||||
//println!("{:?}", code.getattr(py, "co_filename").unwrap());
|
||||
//println!("{:?}", code.getattr(py, "co_code").unwrap());
|
||||
//println!("{:?}", code.getattr(py, "co_freevars").unwrap());
|
||||
//println!("{:?}", code.getattr(py, "co_cellvars").unwrap());
|
||||
println!("{:?}", code.getattr(py, "co_consts").unwrap());
|
||||
//let consts = code.getattr(py, "co_consts").unwrap();
|
||||
//println!("{:?}", consts.get_item(py, 0).unwrap().getattr(py, "co_code"));
|
||||
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
|
||||
// A function which takes CPython bytecode (from json) and transforms
|
||||
// this into RustPython bytecode. This to decouple RustPython from CPython
|
||||
// internal bytecode representations.
|
||||
|
||||
use rustpython_vm::bytecode;
|
||||
use py_code_object::{PyCodeObject, NativeType};
|
||||
|
||||
pub fn convert(cpython_bytecode: PyCodeObject) -> bytecode::CodeObject {
|
||||
let mut c = Converter::new();
|
||||
c.convert(cpython_bytecode);
|
||||
c.code2
|
||||
}
|
||||
|
||||
|
||||
// TODO: think of an appropriate name for this thing:
|
||||
pub struct Converter {
|
||||
code: Option<PyCodeObject>,
|
||||
code2: bytecode::CodeObject,
|
||||
}
|
||||
|
||||
impl Converter {
|
||||
pub fn new() -> Converter {
|
||||
Converter {
|
||||
code: None,
|
||||
code2: bytecode::CodeObject::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert(&mut self, code: PyCodeObject) {
|
||||
// self.code = Some(code);
|
||||
for op_code in &code.co_code {
|
||||
self.dispatch(&code, op_code);
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch(&mut self, code: &PyCodeObject, op_code: &(usize, String, Option<usize>)) {
|
||||
debug!("Converting op code: {:?}", op_code);
|
||||
match (op_code.1.as_ref(), op_code.2) {
|
||||
("LOAD_CONST", Some(consti)) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
let cons = &code.co_consts[consti];
|
||||
let value = match cons {
|
||||
// NativeType::Boolean { value } => { bytecode::Constant::Boolean { true } },
|
||||
NativeType::Int { 0: value } => { bytecode::Constant::Integer { value: *value } },
|
||||
NativeType::Str { 0: ref value } => { bytecode::Constant::String { value: value.clone() } }
|
||||
NativeType::NoneType => { bytecode::Constant::None }
|
||||
_ => { panic!("Not impl {:?}", cons); }
|
||||
};
|
||||
self.emit(bytecode::Instruction::LoadConst { value: value });
|
||||
},
|
||||
|
||||
// TODO: universal stack element type
|
||||
("LOAD_CONST", None) => {
|
||||
self.emit(bytecode::Instruction::LoadConst { value: bytecode::Constant::None });
|
||||
},
|
||||
("POP_TOP", None) => {
|
||||
self.emit(bytecode::Instruction::Pop);
|
||||
},
|
||||
("STORE_NAME", Some(namei)) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
let name = code.co_names[namei].clone();
|
||||
self.emit(bytecode::Instruction::StoreName { name });
|
||||
},
|
||||
("LOAD_NAME", Some(namei)) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
let name = code.co_names[namei].clone();
|
||||
self.emit(bytecode::Instruction::LoadName { name });
|
||||
},
|
||||
("LOAD_GLOBAL", Some(namei)) => {
|
||||
// We need to load the underlying value the name points to, but stuff like
|
||||
// AssertionError is in the names right after compile, so we load the string
|
||||
// instead for now
|
||||
// let curr_frame = self.curr_frame();
|
||||
// let name = &curr_frame.code.co_names[namei];
|
||||
},
|
||||
|
||||
("BUILD_LIST", Some(count)) => {
|
||||
self.emit(bytecode::Instruction::BuildList { size: count });
|
||||
},
|
||||
|
||||
("BUILD_SLICE", Some(count)) => {
|
||||
assert!(count == 2 || count == 3);
|
||||
self.emit(bytecode::Instruction::BuildSlice { size: count });
|
||||
},
|
||||
|
||||
("GET_ITER", None) => {
|
||||
self.emit(bytecode::Instruction::GetIter);
|
||||
},
|
||||
|
||||
("FOR_ITER", Some(delta)) => {
|
||||
self.emit(bytecode::Instruction::ForIter);
|
||||
},
|
||||
|
||||
("COMPARE_OP", Some(cmp_op_i)) => {
|
||||
let op = match cmp_op_i {
|
||||
0 => bytecode::ComparisonOperator::Less,
|
||||
1 => bytecode::ComparisonOperator::LessOrEqual,
|
||||
2 => bytecode::ComparisonOperator::Equal,
|
||||
3 => bytecode::ComparisonOperator::NotEqual,
|
||||
4 => bytecode::ComparisonOperator::Greater,
|
||||
5 => bytecode::ComparisonOperator::GreaterOrEqual,
|
||||
_ => { panic!("Not impl {:?}", cmp_op_i); }
|
||||
};
|
||||
self.emit(bytecode::Instruction::CompareOperation { op: op} );
|
||||
},
|
||||
("POP_JUMP_IF_TRUE", Some(ref target)) => {
|
||||
self.emit(bytecode::Instruction::JumpIf { target: *target} );
|
||||
}
|
||||
/*
|
||||
("POP_JUMP_IF_FALSE", Some(ref target)) => {
|
||||
// Convert into two internal bytecodes:
|
||||
self.emit(bytecode::Instruction::UnaryOperation { op: bytecode::UnaryOperation::Not } );
|
||||
self.emit(bytecode::Instruction::JumpIf { target: target} );
|
||||
}*/
|
||||
/*
|
||||
("JUMP_FORWARD", Some(ref delta)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let last_offset = curr_frame.get_bytecode_offset().unwrap();
|
||||
curr_frame.lasti = curr_frame.labels.get(&(last_offset + delta)).unwrap().clone();
|
||||
None
|
||||
},
|
||||
("JUMP_ABSOLUTE", Some(ref target)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone();
|
||||
None
|
||||
},
|
||||
("BREAK_LOOP", None) => {
|
||||
// Do we still need to return the why if we use unwind from jsapy?
|
||||
self.unwind("break".to_string());
|
||||
None //?
|
||||
},
|
||||
*/
|
||||
("RAISE_VARARGS", Some(argc)) => {
|
||||
self.emit(bytecode::Instruction::Raise { argc: argc });
|
||||
}
|
||||
/*
|
||||
("INPLACE_ADD", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: BinaryOperator::Add });
|
||||
},
|
||||
|
||||
("STORE_SUBSCR", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let tos = curr_frame.stack.pop().unwrap();
|
||||
let tos1 = curr_frame.stack.pop().unwrap();
|
||||
let tos2 = curr_frame.stack.pop().unwrap();
|
||||
match (tos1.deref(), tos.deref()) {
|
||||
(&NativeType::List(ref refl), &NativeType::Int(index)) => {
|
||||
refl.borrow_mut()[index as usize] = (*tos2).clone();
|
||||
},
|
||||
(&NativeType::Str(_), &NativeType::Int(_)) => {
|
||||
// TODO: raise TypeError: 'str' object does not support item assignment
|
||||
panic!("TypeError: 'str' object does not support item assignment")
|
||||
},
|
||||
_ => panic!("TypeError in STORE_SUBSCR")
|
||||
}
|
||||
curr_frame.stack.push(tos1);
|
||||
},
|
||||
*/
|
||||
("BINARY_ADD", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: bytecode::BinaryOperator::Add });
|
||||
},
|
||||
("BINARY_POWER", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: bytecode::BinaryOperator::Power });
|
||||
},
|
||||
("BINARY_MULTIPLY", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: bytecode::BinaryOperator::Multiply });
|
||||
},
|
||||
("BINARY_TRUE_DIVIDE", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: bytecode::BinaryOperator::Divide });
|
||||
},
|
||||
("BINARY_MODULO", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: bytecode::BinaryOperator::Modulo });
|
||||
},
|
||||
("BINARY_SUBTRACT", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: bytecode::BinaryOperator::Subtract });
|
||||
},
|
||||
("BINARY_SUBSCR", None) => {
|
||||
self.emit(bytecode::Instruction::BinaryOperation { op: bytecode::BinaryOperator::Subscript });
|
||||
},
|
||||
("ROT_TWO", None) => {
|
||||
self.emit(bytecode::Instruction::Rotate { amount: 2 });
|
||||
}
|
||||
("UNARY_NEGATIVE", None) => {
|
||||
self.emit(bytecode::Instruction::UnaryOperation { op: bytecode::UnaryOperator::Minus });
|
||||
},
|
||||
("UNARY_POSITIVE", None) => {
|
||||
self.emit(bytecode::Instruction::UnaryOperation { op: bytecode::UnaryOperator::Plus });
|
||||
},
|
||||
/*
|
||||
("PRINT_ITEM", None) => {
|
||||
// TODO: Print without the (...)
|
||||
println!("{:?}", curr_frame.stack.pop().unwrap());
|
||||
},
|
||||
("PRINT_NEWLINE", None) => {
|
||||
print!("\n");
|
||||
},*/
|
||||
/*
|
||||
("MAKE_FUNCTION", Some(argc)) => {
|
||||
// https://docs.python.org/3.4/library/dis.html#opcode-MAKE_FUNCTION
|
||||
self.emit(bytecode::Instruction::MakeFunction { });
|
||||
},
|
||||
*/
|
||||
("CALL_FUNCTION", Some(argc)) => {
|
||||
let kw_count = (argc >> 8) as u8;
|
||||
let pos_count = (argc & 0xFF) as usize;
|
||||
self.emit(bytecode::Instruction::CallFunction { count: pos_count });
|
||||
},
|
||||
("RETURN_VALUE", None) => {
|
||||
self.emit(bytecode::Instruction::ReturnValue);
|
||||
},
|
||||
/*
|
||||
("SETUP_LOOP", Some(delta)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let curr_offset = curr_frame.get_bytecode_offset().unwrap();
|
||||
curr_frame.blocks.push(Block {
|
||||
block_type: "loop".to_string(),
|
||||
handler: *curr_frame.labels.get(&(curr_offset + delta)).unwrap(),
|
||||
});
|
||||
},
|
||||
*/
|
||||
("POP_BLOCK", None) => {
|
||||
self.emit(bytecode::Instruction::PopBlock);
|
||||
}
|
||||
("SetLineno", _) | ("LABEL", _)=> {
|
||||
// Skip
|
||||
},
|
||||
(name, _) => {
|
||||
panic!("Unrecongnizable op code: {}", name);
|
||||
}
|
||||
} // end match
|
||||
} // end dispatch function
|
||||
|
||||
fn emit(&mut self, instruction: bytecode::Instruction) {
|
||||
self.code2.instructions.push(instruction);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum NativeType{
|
||||
NoneType,
|
||||
Boolean(bool),
|
||||
Int(i32),
|
||||
Float(f64),
|
||||
Str(String),
|
||||
Unicode(String),
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
List(RefCell<Vec<NativeType>>),
|
||||
Tuple(Vec<NativeType>),
|
||||
Iter(Vec<NativeType>), // TODO: use Iterator instead
|
||||
Code(PyCodeObject),
|
||||
Function(Function),
|
||||
Slice(Option<i32>, Option<i32>, Option<i32>), // start, stop, step
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
NativeFunction(fn(Vec<Rc<NativeType>>) -> NativeType ),
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PyCodeObject {
|
||||
pub co_consts: Vec<NativeType>,
|
||||
pub co_names: Vec<String>,
|
||||
// TODO: use vector of bytecode objects instead of strings?
|
||||
pub co_code: Vec<(usize, String, Option<usize>)>, //size, name, args
|
||||
pub co_varnames: Vec<String>,
|
||||
}
|
||||
|
||||
impl PyCodeObject {
|
||||
pub fn new() -> PyCodeObject {
|
||||
PyCodeObject {
|
||||
co_consts: Vec::<NativeType>::new(),
|
||||
co_names: Vec::<String>::new(),
|
||||
co_code: Vec::<(usize, String, Option<usize>)>::new(), //size, name, args
|
||||
co_varnames: Vec::<String>::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Function {
|
||||
pub code: PyCodeObject
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(code: PyCodeObject) -> Function {
|
||||
Function {
|
||||
code: code
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
extern crate env_logger;
|
||||
extern crate py_code_object;
|
||||
extern crate rustpython_vm;
|
||||
extern crate serde_json;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod convert;
|
||||
|
||||
use rustpython_vm::evaluate;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use py_code_object::PyCodeObject;
|
||||
|
||||
fn main() {
|
||||
env_logger::init().unwrap();
|
||||
// TODO: read this from args
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let filename = &args[1];
|
||||
|
||||
let mut f = File::open(filename).unwrap();
|
||||
// println!("Read file");
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s).unwrap();
|
||||
// println!("Read string");
|
||||
// TODO: Extract this so we don't depend on json
|
||||
let cpython_code: PyCodeObject = match serde_json::from_str(&s) {
|
||||
Ok(c) => c,
|
||||
Err(_) => panic!("Fail to parse the bytecode")
|
||||
};
|
||||
|
||||
let code = convert::convert(cpython_code);
|
||||
|
||||
evaluate(code);
|
||||
}
|
||||
@@ -1,653 +0,0 @@
|
||||
|
||||
// extern crate py_code_object;
|
||||
use std::collections::HashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::ops::Deref;
|
||||
|
||||
|
||||
const CMP_OP: &'static [&'static str] = &[">",
|
||||
"<=",
|
||||
"==",
|
||||
"!=",
|
||||
">",
|
||||
">=",
|
||||
"in",
|
||||
"not in",
|
||||
"is",
|
||||
"is not",
|
||||
"exception match",
|
||||
"BAD"
|
||||
];
|
||||
|
||||
impl Frame {
|
||||
/// Get the current bytecode offset calculated from curr_frame.lasti
|
||||
fn get_bytecode_offset(&self) -> Option<usize> {
|
||||
// Linear search the labels HashMap, inefficient. Consider build a reverse HashMap
|
||||
let mut last_offset = None;
|
||||
for (offset, instr_idx) in self.labels.iter() {
|
||||
if *instr_idx == self.lasti {
|
||||
last_offset = Some(*offset)
|
||||
}
|
||||
}
|
||||
last_offset
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct VirtualMachine{
|
||||
frames: Vec<Frame>,
|
||||
}
|
||||
|
||||
impl VirtualMachine {
|
||||
fn unwind(&mut self, reason: String) {
|
||||
let curr_frame = self.curr_frame();
|
||||
let curr_block = curr_frame.blocks[curr_frame.blocks.len()-1].clone(); // use last?
|
||||
curr_frame.why = reason; // Why do we need this?
|
||||
debug!("block status: {:?}, {:?}", curr_block.block_type, curr_frame.why);
|
||||
match (curr_block.block_type.as_ref(), curr_frame.why.as_ref()) {
|
||||
("loop", "break") => {
|
||||
curr_frame.lasti = curr_block.handler; //curr_frame.labels[curr_block.handler]; // Jump to the end
|
||||
// Return the why as None
|
||||
curr_frame.blocks.pop();
|
||||
},
|
||||
("loop", "none") => (), //skipped
|
||||
_ => panic!("block stack operation not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
// Can we get rid of the code parameter?
|
||||
|
||||
fn make_frame(&self, code: PyCodeObject, callargs: HashMap<String, Rc<NativeType>>, globals: Option<HashMap<String, Rc<NativeType>>>) -> Frame {
|
||||
//populate the globals and locals
|
||||
let mut labels = HashMap::new();
|
||||
let mut curr_offset = 0;
|
||||
for (idx, op) in code.co_code.iter().enumerate() {
|
||||
labels.insert(curr_offset, idx);
|
||||
curr_offset += op.0;
|
||||
}
|
||||
//TODO: This is wrong, check https://github.com/nedbat/byterun/blob/31e6c4a8212c35b5157919abff43a7daa0f377c6/byterun/pyvm2.py#L95
|
||||
let globals = match globals {
|
||||
Some(g) => g,
|
||||
None => HashMap::new(),
|
||||
};
|
||||
let mut locals = globals;
|
||||
locals.extend(callargs);
|
||||
|
||||
//TODO: move this into the __builtin__ module when we have a module type
|
||||
locals.insert("print".to_string(), Rc::new(NativeType::NativeFunction(builtins::print)));
|
||||
locals.insert("len".to_string(), Rc::new(NativeType::NativeFunction(builtins::len)));
|
||||
Frame {
|
||||
code: code,
|
||||
stack: vec![],
|
||||
blocks: vec![],
|
||||
// save the callargs as locals
|
||||
globals: locals.clone(),
|
||||
locals: locals,
|
||||
labels: labels,
|
||||
lasti: 0,
|
||||
return_value: NativeType::NoneType,
|
||||
why: "none".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
// The Option<i32> is the return value of the frame, remove when we have implemented frame
|
||||
// TODO: read the op codes directly from the internal code object
|
||||
fn run_frame(&mut self, frame: Frame) -> NativeType {
|
||||
self.frames.push(frame);
|
||||
|
||||
//let mut why = None;
|
||||
// Change this to a loop for jump
|
||||
loop {
|
||||
//while curr_frame.lasti < curr_frame.code.co_code.len() {
|
||||
let op_code = {
|
||||
let curr_frame = self.curr_frame();
|
||||
if curr_frame.code.co_code.len() == 0 { panic!("Trying to run an empty frame. Check if the bytecode is empty"); }
|
||||
let op_code = curr_frame.code.co_code[curr_frame.lasti].clone();
|
||||
curr_frame.lasti += 1;
|
||||
op_code
|
||||
};
|
||||
let why = self.dispatch(op_code);
|
||||
/*if curr_frame.blocks.len() > 0 {
|
||||
self.manage_block_stack(&why);
|
||||
}
|
||||
*/
|
||||
if let Some(_) = why {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let return_value = {
|
||||
//let curr_frame = self.frames.last_mut().unwrap();
|
||||
self.curr_frame().return_value.clone()
|
||||
};
|
||||
self.pop_frame();
|
||||
return_value
|
||||
}
|
||||
|
||||
pub fn run_code(&mut self, code: PyCodeObject) {
|
||||
let frame = self.make_frame(code, HashMap::new(), None);
|
||||
self.run_frame(frame);
|
||||
// check if there are any leftover frame, fail if any
|
||||
}
|
||||
|
||||
fn dispatch(&mut self, op_code: (usize, String, Option<usize>)) -> Option<String> {
|
||||
match (op_code.1.as_ref(), op_code.2) {
|
||||
("LOAD_CONST", Some(consti)) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
let curr_frame = self.curr_frame();
|
||||
curr_frame.stack.push(Rc::new(curr_frame.code.co_consts[consti].clone()));
|
||||
None
|
||||
},
|
||||
|
||||
// TODO: universal stack element type
|
||||
("LOAD_CONST", None) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
self.curr_frame().stack.push(Rc::new(NativeType::NoneType));
|
||||
None
|
||||
},
|
||||
("POP_TOP", None) => {
|
||||
self.curr_frame().stack.pop();
|
||||
None
|
||||
},
|
||||
("LOAD_FAST", Some(var_num)) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
let curr_frame = self.curr_frame();
|
||||
let ref name = curr_frame.code.co_varnames[var_num];
|
||||
curr_frame.stack.push(curr_frame.locals.get::<str>(name).unwrap().clone());
|
||||
None
|
||||
},
|
||||
("STORE_NAME", Some(namei)) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
let curr_frame = self.curr_frame();
|
||||
curr_frame.locals.insert(curr_frame.code.co_names[namei].clone(), curr_frame.stack.pop().unwrap().clone());
|
||||
None
|
||||
},
|
||||
("LOAD_NAME", Some(namei)) => {
|
||||
// println!("Loading const at index: {}", consti);
|
||||
let curr_frame = self.curr_frame();
|
||||
if let Some(code) = curr_frame.locals.get::<str>(&curr_frame.code.co_names[namei]) {
|
||||
curr_frame.stack.push(code.clone());
|
||||
}
|
||||
else {
|
||||
panic!("Can't find symbol {:?} in the current frame", &curr_frame.code.co_names[namei]);
|
||||
}
|
||||
None
|
||||
},
|
||||
("LOAD_GLOBAL", Some(namei)) => {
|
||||
// We need to load the underlying value the name points to, but stuff like
|
||||
// AssertionError is in the names right after compile, so we load the string
|
||||
// instead for now
|
||||
let curr_frame = self.curr_frame();
|
||||
let name = &curr_frame.code.co_names[namei];
|
||||
curr_frame.stack.push(curr_frame.globals.get::<str>(name).unwrap().clone());
|
||||
None
|
||||
},
|
||||
|
||||
("BUILD_LIST", Some(count)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let mut vec = vec!();
|
||||
for _ in 0..count {
|
||||
vec.push((*curr_frame.stack.pop().unwrap()).clone());
|
||||
}
|
||||
vec.reverse();
|
||||
curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(vec))));
|
||||
None
|
||||
},
|
||||
|
||||
("BUILD_SLICE", Some(count)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
assert!(count == 2 || count == 3);
|
||||
let mut vec = vec!();
|
||||
for _ in 0..count {
|
||||
vec.push(curr_frame.stack.pop().unwrap());
|
||||
}
|
||||
vec.reverse();
|
||||
let mut out:Vec<Option<i32>> = vec.into_iter().map(|x| match *x {
|
||||
NativeType::Int(n) => Some(n),
|
||||
NativeType::NoneType => None,
|
||||
_ => panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x),
|
||||
}).collect();
|
||||
|
||||
if out.len() == 2 {
|
||||
out.push(None);
|
||||
}
|
||||
assert!(out.len() == 3);
|
||||
// TODO: assert the stop start and step are NativeType::Int
|
||||
// See https://users.rust-lang.org/t/how-do-you-assert-enums/1187/8
|
||||
curr_frame.stack.push(Rc::new(NativeType::Slice(out[0], out[1], out[2])));
|
||||
None
|
||||
},
|
||||
|
||||
("GET_ITER", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let tos = curr_frame.stack.pop().unwrap();
|
||||
let iter = match *tos {
|
||||
//TODO: is this clone right?
|
||||
// Return a Iterator instead vvv
|
||||
NativeType::Tuple(ref vec) => NativeType::Iter(vec.clone()),
|
||||
NativeType::List(ref vec) => NativeType::Iter(vec.borrow().clone()),
|
||||
_ => panic!("TypeError: object is not iterable")
|
||||
};
|
||||
curr_frame.stack.push(Rc::new(iter));
|
||||
None
|
||||
},
|
||||
|
||||
("FOR_ITER", Some(delta)) => {
|
||||
// This function should be rewrote to use Rust native iterator
|
||||
let curr_frame = self.curr_frame();
|
||||
let tos = curr_frame.stack.pop().unwrap();
|
||||
let result = match *tos {
|
||||
NativeType::Iter(ref v) => {
|
||||
if v.len() > 0 {
|
||||
Some(v.clone()) // Unnessary clone here
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => panic!("FOR_ITER: Not an iterator")
|
||||
};
|
||||
if let Some(vec) = result {
|
||||
let (first, rest) = vec.split_first().unwrap();
|
||||
// Unnessary clone here
|
||||
curr_frame.stack.push(Rc::new(NativeType::Iter(rest.to_vec())));
|
||||
curr_frame.stack.push(Rc::new(first.clone()));
|
||||
}
|
||||
else {
|
||||
// Iterator was already poped in the first line of this function
|
||||
let last_offset = curr_frame.get_bytecode_offset().unwrap();
|
||||
curr_frame.lasti = curr_frame.labels.get(&(last_offset + delta)).unwrap().clone();
|
||||
|
||||
}
|
||||
None
|
||||
},
|
||||
|
||||
("COMPARE_OP", Some(cmp_op_i)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v1 = curr_frame.stack.pop().unwrap();
|
||||
let v2 = curr_frame.stack.pop().unwrap();
|
||||
match CMP_OP[cmp_op_i] {
|
||||
// To avoid branch explotion, use an array of callables instead
|
||||
"==" => {
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Boolean(v2i == v1i)));
|
||||
},
|
||||
(&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f == v1f)));
|
||||
},
|
||||
(&NativeType::Str(ref v1s), &NativeType::Str(ref v2s)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Boolean(v2s == v1s)));
|
||||
},
|
||||
(&NativeType::Int(ref v1i), &NativeType::Float(ref v2f)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f == &(*v1i as f64))));
|
||||
},
|
||||
(&NativeType::List(ref l1), &NativeType::List(ref l2)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Boolean(l2 == l1)));
|
||||
},
|
||||
_ => panic!("TypeError in COMPARE_OP: can't compare {:?} with {:?}", v1, v2)
|
||||
};
|
||||
}
|
||||
">" => {
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Boolean(v2i < v1i)));
|
||||
},
|
||||
(&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f < v1f)));
|
||||
},
|
||||
_ => panic!("TypeError in COMPARE_OP")
|
||||
};
|
||||
}
|
||||
_ => panic!("Unimplemented COMPARE_OP operator")
|
||||
|
||||
}
|
||||
None
|
||||
|
||||
},
|
||||
("POP_JUMP_IF_TRUE", Some(ref target)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v = curr_frame.stack.pop().unwrap();
|
||||
if *v == NativeType::Boolean(true) {
|
||||
curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone();
|
||||
}
|
||||
None
|
||||
|
||||
}
|
||||
("POP_JUMP_IF_FALSE", Some(ref target)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v = curr_frame.stack.pop().unwrap();
|
||||
if *v == NativeType::Boolean(false) {
|
||||
curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone();
|
||||
}
|
||||
None
|
||||
|
||||
}
|
||||
("JUMP_FORWARD", Some(ref delta)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let last_offset = curr_frame.get_bytecode_offset().unwrap();
|
||||
curr_frame.lasti = curr_frame.labels.get(&(last_offset + delta)).unwrap().clone();
|
||||
None
|
||||
},
|
||||
("JUMP_ABSOLUTE", Some(ref target)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone();
|
||||
None
|
||||
},
|
||||
("BREAK_LOOP", None) => {
|
||||
// Do we still need to return the why if we use unwind from jsapy?
|
||||
self.unwind("break".to_string());
|
||||
None //?
|
||||
},
|
||||
("RAISE_VARARGS", Some(argc)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
// let (exception, params, traceback) = match argc {
|
||||
let exception = match argc {
|
||||
1 => curr_frame.stack.pop().unwrap(),
|
||||
0 | 2 | 3 => panic!("Not implemented!"),
|
||||
_ => panic!("Invalid parameter for RAISE_VARARGS, must be between 0 to 3")
|
||||
};
|
||||
panic!("{:?}", exception);
|
||||
}
|
||||
("INPLACE_ADD", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let tos = curr_frame.stack.pop().unwrap();
|
||||
let tos1 = curr_frame.stack.pop().unwrap();
|
||||
match (tos.deref(), tos1.deref()) {
|
||||
(&NativeType::Int(ref tosi), &NativeType::Int(ref tos1i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Int(tos1i + tosi)));
|
||||
},
|
||||
_ => panic!("TypeError in BINARY_ADD")
|
||||
}
|
||||
None
|
||||
},
|
||||
|
||||
("STORE_SUBSCR", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let tos = curr_frame.stack.pop().unwrap();
|
||||
let tos1 = curr_frame.stack.pop().unwrap();
|
||||
let tos2 = curr_frame.stack.pop().unwrap();
|
||||
match (tos1.deref(), tos.deref()) {
|
||||
(&NativeType::List(ref refl), &NativeType::Int(index)) => {
|
||||
refl.borrow_mut()[index as usize] = (*tos2).clone();
|
||||
},
|
||||
(&NativeType::Str(_), &NativeType::Int(_)) => {
|
||||
// TODO: raise TypeError: 'str' object does not support item assignment
|
||||
panic!("TypeError: 'str' object does not support item assignment")
|
||||
},
|
||||
_ => panic!("TypeError in STORE_SUBSCR")
|
||||
}
|
||||
curr_frame.stack.push(tos1);
|
||||
None
|
||||
},
|
||||
|
||||
("BINARY_ADD", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v1 = curr_frame.stack.pop().unwrap();
|
||||
let v2 = curr_frame.stack.pop().unwrap();
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Int(v2i + v1i)));
|
||||
}
|
||||
(&NativeType::Float(ref v1f), &NativeType::Int(ref v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Float(*v2i as f64 + v1f)));
|
||||
}
|
||||
(&NativeType::Int(ref v1i), &NativeType::Float(ref v2f)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Float(v2f + *v1i as f64)));
|
||||
}
|
||||
(&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Float(v2f + v1f)));
|
||||
}
|
||||
(&NativeType::Str(ref str1), &NativeType::Str(ref str2)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Str(format!("{}{}", str2, str1))));
|
||||
}
|
||||
(&NativeType::List(ref l1), &NativeType::List(ref l2)) => {
|
||||
let mut new_l = l2.clone();
|
||||
// TODO: remove unnessary copy
|
||||
new_l.borrow_mut().append(&mut l1.borrow().clone());
|
||||
curr_frame.stack.push(Rc::new(NativeType::List(new_l)));
|
||||
|
||||
}
|
||||
_ => panic!("TypeError in BINARY_ADD")
|
||||
}
|
||||
None
|
||||
},
|
||||
("BINARY_POWER", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v1 = curr_frame.stack.pop().unwrap();
|
||||
let v2 = curr_frame.stack.pop().unwrap();
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(v1i), &NativeType::Int(v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Int(v2i.pow(v1i as u32))));
|
||||
}
|
||||
(&NativeType::Float(v1f), &NativeType::Int(v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Float((v2i as f64).powf(v1f))));
|
||||
}
|
||||
(&NativeType::Int(v1i), &NativeType::Float(v2f)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Float(v2f.powi(v1i))));
|
||||
}
|
||||
(&NativeType::Float(v1f), &NativeType::Float(v2f)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Float(v2f.powf(v1f))));
|
||||
}
|
||||
_ => panic!("TypeError in BINARY_POWER")
|
||||
}
|
||||
None
|
||||
},
|
||||
("BINARY_MULTIPLY", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v1 = curr_frame.stack.pop().unwrap();
|
||||
let v2 = curr_frame.stack.pop().unwrap();
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(v1i), &NativeType::Int(v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Int(v2i * v1i)));
|
||||
},
|
||||
/*
|
||||
(NativeType::Float(v1f), NativeType::Int(v2i)) => {
|
||||
curr_frame.stack.push(NativeType::Float((v2i as f64) * v1f));
|
||||
},
|
||||
(NativeType::Int(v1i), NativeType::Float(v2f)) => {
|
||||
curr_frame.stack.push(NativeType::Float(v2f * (v1i as f64)));
|
||||
},
|
||||
(NativeType::Float(v1f), NativeType::Float(v2f)) => {
|
||||
curr_frame.stack.push(NativeType::Float(v2f * v1f));
|
||||
},
|
||||
*/
|
||||
//TODO: String multiply
|
||||
_ => panic!("TypeError in BINARY_MULTIPLY")
|
||||
}
|
||||
None
|
||||
},
|
||||
("BINARY_TRUE_DIVIDE", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v1 = curr_frame.stack.pop().unwrap();
|
||||
let v2 = curr_frame.stack.pop().unwrap();
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(v1i), &NativeType::Int(v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Int(v2i / v1i)));
|
||||
},
|
||||
_ => panic!("TypeError in BINARY_DIVIDE")
|
||||
}
|
||||
None
|
||||
},
|
||||
("BINARY_MODULO", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v1 = curr_frame.stack.pop().unwrap();
|
||||
let v2 = curr_frame.stack.pop().unwrap();
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(v1i), &NativeType::Int(v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Int(v2i % v1i)));
|
||||
},
|
||||
_ => panic!("TypeError in BINARY_MODULO")
|
||||
}
|
||||
None
|
||||
},
|
||||
("BINARY_SUBTRACT", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let v1 = curr_frame.stack.pop().unwrap();
|
||||
let v2 = curr_frame.stack.pop().unwrap();
|
||||
match (v1.deref(), v2.deref()) {
|
||||
(&NativeType::Int(v1i), &NativeType::Int(v2i)) => {
|
||||
curr_frame.stack.push(Rc::new(NativeType::Int(v2i - v1i)));
|
||||
},
|
||||
_ => panic!("TypeError in BINARY_SUBSTRACT")
|
||||
}
|
||||
None
|
||||
},
|
||||
|
||||
("BINARY_SUBSCR", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let tos = curr_frame.stack.pop().unwrap();
|
||||
let tos1 = curr_frame.stack.pop().unwrap();
|
||||
debug!("tos: {:?}, tos1: {:?}", tos, tos1);
|
||||
match (tos1.deref(), tos.deref()) {
|
||||
(&NativeType::List(ref l), &NativeType::Int(ref index)) => {
|
||||
let pos_index = (index + l.borrow().len() as i32) % l.borrow().len() as i32;
|
||||
curr_frame.stack.push(Rc::new(l.borrow()[pos_index as usize].clone()))
|
||||
},
|
||||
(&NativeType::List(ref l), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => {
|
||||
let start = match opt_start {
|
||||
&Some(start) => ((start + l.borrow().len() as i32) % l.borrow().len() as i32) as usize,
|
||||
&None => 0,
|
||||
};
|
||||
let stop = match opt_stop {
|
||||
&Some(stop) => ((stop + l.borrow().len() as i32) % l.borrow().len() as i32) as usize,
|
||||
&None => l.borrow().len() as usize,
|
||||
};
|
||||
let step = match opt_step {
|
||||
//Some(step) => step as usize,
|
||||
&None => 1 as usize,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
// TODO: we could potentially avoid this copy and use slice
|
||||
curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(l.borrow()[start..stop].to_vec()))));
|
||||
},
|
||||
(&NativeType::Tuple(ref t), &NativeType::Int(ref index)) => curr_frame.stack.push(Rc::new(t[*index as usize].clone())),
|
||||
(&NativeType::Str(ref s), &NativeType::Int(ref index)) => {
|
||||
let idx = (index + s.len() as i32) % s.len() as i32;
|
||||
curr_frame.stack.push(Rc::new(NativeType::Str(s.chars().nth(idx as usize).unwrap().to_string())));
|
||||
},
|
||||
(&NativeType::Str(ref s), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => {
|
||||
let start = match opt_start {
|
||||
&Some(start) if start > s.len() as i32 => s.len(),
|
||||
&Some(start) if start <= s.len() as i32 => ((start + s.len() as i32) % s.len() as i32) as usize,
|
||||
&Some(_) => panic!("Bad start index for string slicing"),
|
||||
&Some(start) => ((start + s.len() as i32) % s.len() as i32) as usize,
|
||||
&None => 0,
|
||||
};
|
||||
let stop = match opt_stop {
|
||||
&Some(stop) if stop > s.len() as i32 => s.len(),
|
||||
&Some(stop) if stop <= s.len() as i32 => ((stop + s.len() as i32) % s.len() as i32) as usize, // Do we need this modding?
|
||||
&Some(_) => panic!("Bad stop index for string slicing"),
|
||||
&None => s.len() as usize,
|
||||
};
|
||||
let step = match opt_step {
|
||||
//Some(step) => step as usize,
|
||||
&None => 1 as usize,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
curr_frame.stack.push(Rc::new(NativeType::Str(s[start..stop].to_string())));
|
||||
},
|
||||
// TODO: implement other Slice possibilities
|
||||
_ => panic!("TypeError: indexing type {:?} with index {:?} is not supported (yet?)", tos1, tos)
|
||||
};
|
||||
None
|
||||
},
|
||||
("ROT_TWO", None) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let tos = curr_frame.stack.pop().unwrap();
|
||||
let tos1 = curr_frame.stack.pop().unwrap();
|
||||
curr_frame.stack.push(tos);
|
||||
curr_frame.stack.push(tos1);
|
||||
None
|
||||
}
|
||||
("CALL_FUNCTION", Some(argc)) => {
|
||||
let kw_count = (argc >> 8) as u8;
|
||||
let pos_count = (argc & 0xFF) as u8;
|
||||
// Pop the arguments based on argc
|
||||
let mut kw_args = HashMap::new();
|
||||
let mut pos_args = Vec::new();
|
||||
{
|
||||
let curr_frame = self.curr_frame();
|
||||
for _ in 0..kw_count {
|
||||
let native_val = curr_frame.stack.pop().unwrap();
|
||||
let native_key = curr_frame.stack.pop().unwrap();
|
||||
if let (ref val, &NativeType::Str(ref key)) = (native_val, native_key.deref()) {
|
||||
|
||||
kw_args.insert(key.clone(), val.clone());
|
||||
}
|
||||
else {
|
||||
panic!("Incorrect type found while building keyword argument list")
|
||||
}
|
||||
}
|
||||
for _ in 0..pos_count {
|
||||
pos_args.push(curr_frame.stack.pop().unwrap());
|
||||
}
|
||||
}
|
||||
let locals = {
|
||||
// FIXME: no clone here
|
||||
self.curr_frame().locals.clone()
|
||||
};
|
||||
|
||||
let func = {
|
||||
match self.curr_frame().stack.pop().unwrap().deref() {
|
||||
&NativeType::Function(ref func) => {
|
||||
// pop argc arguments
|
||||
// argument: name, args, globals
|
||||
// build the callargs hashmap
|
||||
pos_args.reverse();
|
||||
let mut callargs = HashMap::new();
|
||||
for (name, val) in func.code.co_varnames.iter().zip(pos_args) {
|
||||
callargs.insert(name.to_string(), val);
|
||||
}
|
||||
// merge callargs with kw_args
|
||||
let return_value = {
|
||||
let frame = self.make_frame(func.code.clone(), callargs, Some(locals));
|
||||
self.run_frame(frame)
|
||||
};
|
||||
self.curr_frame().stack.push(Rc::new(return_value));
|
||||
},
|
||||
&NativeType::NativeFunction(func) => {
|
||||
pos_args.reverse();
|
||||
let return_value = func(pos_args);
|
||||
self.curr_frame().stack.push(Rc::new(return_value));
|
||||
},
|
||||
_ => panic!("The item on the stack should be a code object")
|
||||
}
|
||||
};
|
||||
None
|
||||
},
|
||||
("RETURN_VALUE", None) => {
|
||||
// Hmmm... what is this used?
|
||||
// I believe we need to push this to the next frame
|
||||
self.curr_frame().return_value = (*self.curr_frame().stack.pop().unwrap()).clone();
|
||||
Some("return".to_string())
|
||||
},
|
||||
("SETUP_LOOP", Some(delta)) => {
|
||||
let curr_frame = self.curr_frame();
|
||||
let curr_offset = curr_frame.get_bytecode_offset().unwrap();
|
||||
curr_frame.blocks.push(Block {
|
||||
block_type: "loop".to_string(),
|
||||
handler: *curr_frame.labels.get(&(curr_offset + delta)).unwrap(),
|
||||
});
|
||||
None
|
||||
},
|
||||
("POP_BLOCK", None) => {
|
||||
self.curr_frame().blocks.pop();
|
||||
None
|
||||
}
|
||||
("SetLineno", _) | ("LABEL", _)=> {
|
||||
// Skip
|
||||
None
|
||||
},
|
||||
(name, _) => {
|
||||
panic!("Unrecongnizable op code: {}", name);
|
||||
}
|
||||
} // end match
|
||||
} // end dispatch function
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tuple_serialization(){
|
||||
let tuple = NativeType::Tuple(vec![NativeType::Int(1),NativeType::Int(2)]);
|
||||
println!("{}", serde_json::to_string(&tuple).unwrap());
|
||||
}
|
||||
@@ -441,10 +441,10 @@ fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> Result<(), Com
|
||||
Ok(value) => {
|
||||
// Save non-None values as "_"
|
||||
|
||||
use rustpython_vm::pyobject::{IdProtocol, IntoPyObject};
|
||||
use rustpython_vm::pyobject::IdProtocol;
|
||||
|
||||
if !value.is(&vm.get_none()) {
|
||||
let key = objstr::PyString::from("_").into_pyobject(vm);
|
||||
let key = "_";
|
||||
scope.globals.set_item(key, value, vm).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,3 +155,12 @@ assert T4.t1.__doc__ == "t1"
|
||||
|
||||
cm = classmethod(lambda cls: cls)
|
||||
assert cm.__func__(int) is int
|
||||
|
||||
assert str(super(int, 5)) == "<super: <class 'int'>, <int object>>"
|
||||
|
||||
class T5(int):
|
||||
pass
|
||||
|
||||
assert str(super(int, T5(5))) == "<super: <class 'int'>, <T5 object>>"
|
||||
|
||||
#assert str(super(type, None)) == "<super: <class 'type'>, NULL>"
|
||||
|
||||
@@ -39,9 +39,17 @@ v = Value()
|
||||
assert f'{v}' == 'foo'
|
||||
assert f'{v!r}' == 'bar'
|
||||
assert f'{v!s}' == 'baz'
|
||||
assert f'{v!a}' == 'bar'
|
||||
|
||||
# advanced expressions:
|
||||
|
||||
assert f'{True or True}' == 'True'
|
||||
assert f'{1 == 1}' == 'True'
|
||||
assert f'{"0" if True else "1"}' == '0'
|
||||
|
||||
# Test ascii representation of unicodes:
|
||||
v = "\u262e"
|
||||
assert f'>{v}' == '>\u262e'
|
||||
assert f'>{v!r}' == ">'\u262e'"
|
||||
assert f'>{v!s}' == '>\u262e'
|
||||
assert f'>{v!a}' == r">'\u262e'"
|
||||
|
||||
BIN
tests/snippets/imghdrdata/python.bmp
Normal file
BIN
tests/snippets/imghdrdata/python.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
tests/snippets/imghdrdata/python.exr
Normal file
BIN
tests/snippets/imghdrdata/python.exr
Normal file
Binary file not shown.
BIN
tests/snippets/imghdrdata/python.gif
Normal file
BIN
tests/snippets/imghdrdata/python.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 610 B |
BIN
tests/snippets/imghdrdata/python.jpg
Normal file
BIN
tests/snippets/imghdrdata/python.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 543 B |
3
tests/snippets/imghdrdata/python.pbm
Normal file
3
tests/snippets/imghdrdata/python.pbm
Normal file
@@ -0,0 +1,3 @@
|
||||
P4
|
||||
16 16
|
||||
ûñ¿úßÕ±[ñ¥a_ÁX°°ðððð?ÿÿ
|
||||
BIN
tests/snippets/imghdrdata/python.pgm
Normal file
BIN
tests/snippets/imghdrdata/python.pgm
Normal file
Binary file not shown.
BIN
tests/snippets/imghdrdata/python.png
Normal file
BIN
tests/snippets/imghdrdata/python.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1020 B |
BIN
tests/snippets/imghdrdata/python.ppm
Normal file
BIN
tests/snippets/imghdrdata/python.ppm
Normal file
Binary file not shown.
BIN
tests/snippets/imghdrdata/python.ras
Normal file
BIN
tests/snippets/imghdrdata/python.ras
Normal file
Binary file not shown.
BIN
tests/snippets/imghdrdata/python.sgi
Normal file
BIN
tests/snippets/imghdrdata/python.sgi
Normal file
Binary file not shown.
BIN
tests/snippets/imghdrdata/python.tiff
Normal file
BIN
tests/snippets/imghdrdata/python.tiff
Normal file
Binary file not shown.
BIN
tests/snippets/imghdrdata/python.webp
Normal file
BIN
tests/snippets/imghdrdata/python.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 432 B |
6
tests/snippets/imghdrdata/python.xbm
Normal file
6
tests/snippets/imghdrdata/python.xbm
Normal file
@@ -0,0 +1,6 @@
|
||||
#define python_width 16
|
||||
#define python_height 16
|
||||
static char python_bits[] = {
|
||||
0xDF, 0xFE, 0x8F, 0xFD, 0x5F, 0xFB, 0xAB, 0xFE, 0xB5, 0x8D, 0xDA, 0x8F,
|
||||
0xA5, 0x86, 0xFA, 0x83, 0x1A, 0x80, 0x0D, 0x80, 0x0D, 0x80, 0x0F, 0xE0,
|
||||
0x0F, 0xF8, 0x0F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, };
|
||||
@@ -1,5 +1,8 @@
|
||||
from testutils import assert_raises
|
||||
|
||||
assert -3 // 2 == -2
|
||||
assert -3 % 2 == 1
|
||||
|
||||
a = 4
|
||||
|
||||
#print(a ** 3)
|
||||
|
||||
@@ -83,6 +83,13 @@ assert str(math.frexp(0.0)) == str((+0.0, 0))
|
||||
assert str(math.frexp(-0.0)) == str((-0.0, 0))
|
||||
assert math.frexp(1) == (0.5, 1)
|
||||
assert math.frexp(1.5) == (0.75, 1)
|
||||
assert_raises(TypeError, lambda: math.frexp(None))
|
||||
|
||||
assert str(math.ldexp(+0.0, 0)) == str(0.0)
|
||||
assert str(math.ldexp(-0.0, 0)) == str(-0.0)
|
||||
assert math.ldexp(0.5, 1) == 1
|
||||
assert math.ldexp(0.75, 1) == 1.5
|
||||
assert_raises(TypeError, lambda: math.ldexp(None, None))
|
||||
|
||||
assert math.frexp(float('inf')) == (float('inf'), 0)
|
||||
assert str(math.frexp(float('nan'))) == str((float('nan'), 0))
|
||||
@@ -97,3 +104,17 @@ assert math.gcd(1, -1) == 1
|
||||
assert math.gcd(-1, -1) == 1
|
||||
assert math.gcd(125, -255) == 5
|
||||
assert_raises(TypeError, lambda: math.gcd(1.1, 2))
|
||||
|
||||
assert math.factorial(0) == 1
|
||||
assert math.factorial(1) == 1
|
||||
assert math.factorial(2) == 2
|
||||
assert math.factorial(3) == 6
|
||||
assert math.factorial(10) == 3628800
|
||||
assert math.factorial(20) == 2432902008176640000
|
||||
assert_raises(ValueError, lambda: math.factorial(-1))
|
||||
|
||||
assert math.modf(1.25) == (0.25, 1.0)
|
||||
assert math.modf(-1.25) == (-0.25, -1.0)
|
||||
assert math.modf(2.56) == (0.56, 2.0)
|
||||
assert math.modf(-2.56) == (-0.56, -2.0)
|
||||
assert math.modf(1) == (0.0, 1.0)
|
||||
|
||||
@@ -30,3 +30,9 @@ fi.read()
|
||||
fi.close()
|
||||
with assertRaises(ValueError):
|
||||
fi.read()
|
||||
|
||||
with FileIO('README.md') as fio:
|
||||
nres = fio.read(1)
|
||||
assert len(nres) == 1
|
||||
nres = fio.read(2)
|
||||
assert len(nres) == 2
|
||||
@@ -183,3 +183,21 @@ assert_matches_seq(it, [1, 2])
|
||||
|
||||
it = i([1, 2, 3], None, None, 3)
|
||||
assert_matches_seq(it, [1])
|
||||
|
||||
# itertools.filterfalse
|
||||
it = itertools.filterfalse(lambda x: x%2, range(10))
|
||||
assert 0 == next(it)
|
||||
assert 2 == next(it)
|
||||
assert 4 == next(it)
|
||||
assert 6 == next(it)
|
||||
assert 8 == next(it)
|
||||
with assertRaises(StopIteration):
|
||||
next(it)
|
||||
|
||||
l = [0, 1, None, False, True, [], {}]
|
||||
it = itertools.filterfalse(None, l)
|
||||
assert 0 == next(it)
|
||||
assert None == next(it)
|
||||
assert False == next(it)
|
||||
assert [] == next(it)
|
||||
assert {} == next(it)
|
||||
@@ -232,6 +232,11 @@ with TestWithTempDir() as tmpdir:
|
||||
os.stat(fname, follow_symlinks=False).st_ino == os.stat(symlink_file, follow_symlinks=False).st_ino
|
||||
os.stat(fname, follow_symlinks=False).st_mode == os.stat(symlink_file, follow_symlinks=False).st_mode
|
||||
|
||||
# os.chmod
|
||||
if os.name != "nt":
|
||||
os.chmod(fname, 0o666)
|
||||
assert oct(os.stat(fname).st_mode) == '0o100666'
|
||||
|
||||
# os.path
|
||||
assert os.path.exists(fname) == True
|
||||
assert os.path.exists("NO_SUCH_FILE") == False
|
||||
|
||||
27
tests/snippets/test_imghdr.py
Normal file
27
tests/snippets/test_imghdr.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# unittest for modified imghdr.py
|
||||
# Should be replace it into https://github.com/python/cpython/blob/master/Lib/test/test_imghdr.py
|
||||
import os
|
||||
import imghdr
|
||||
|
||||
|
||||
TEST_FILES = (
|
||||
#('python.png', 'png'),
|
||||
('python.gif', 'gif'),
|
||||
('python.bmp', 'bmp'),
|
||||
('python.ppm', 'ppm'),
|
||||
('python.pgm', 'pgm'),
|
||||
('python.pbm', 'pbm'),
|
||||
('python.jpg', 'jpeg'),
|
||||
('python.ras', 'rast'),
|
||||
#('python.sgi', 'rgb'),
|
||||
('python.tiff', 'tiff'),
|
||||
('python.xbm', 'xbm'),
|
||||
('python.webp', 'webp'),
|
||||
('python.exr', 'exr'),
|
||||
)
|
||||
|
||||
resource_dir = os.path.join(os.path.dirname(__file__), 'imghdrdata')
|
||||
|
||||
for fname, expected in TEST_FILES:
|
||||
res = imghdr.what(os.path.join(resource_dir, fname))
|
||||
assert res == expected
|
||||
@@ -7,6 +7,7 @@ x = time.gmtime(1000)
|
||||
assert x.tm_year == 1970
|
||||
assert x.tm_min == 16
|
||||
assert x.tm_sec == 40
|
||||
assert x.tm_isdst == 0
|
||||
|
||||
s = time.strftime('%Y-%m-%d-%H-%M-%S', x)
|
||||
# print(s)
|
||||
|
||||
@@ -238,3 +238,21 @@ try:
|
||||
raise NameError from ex
|
||||
except NameError as ex2:
|
||||
pass
|
||||
|
||||
|
||||
# the else clause requires at least one except clause:
|
||||
with assertRaises(SyntaxError):
|
||||
exec("""
|
||||
try:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
""")
|
||||
|
||||
|
||||
# Try requires at least except or finally (or both)
|
||||
with assertRaises(SyntaxError):
|
||||
exec("""
|
||||
try:
|
||||
pass
|
||||
""")
|
||||
|
||||
@@ -29,6 +29,7 @@ num-bigint = { version = "0.2", features = ["serde"] }
|
||||
num-traits = "=0.2.6"
|
||||
num-integer = "=0.1.39"
|
||||
num-rational = "0.2.1"
|
||||
num-iter = "0.1"
|
||||
rand = "0.5"
|
||||
log = "0.3"
|
||||
rustpython-derive = {path = "../derive", version = "0.1.0"}
|
||||
|
||||
@@ -60,8 +60,15 @@ fn builtin_any(iterable: PyIterable<bool>, vm: &VirtualMachine) -> PyResult<bool
|
||||
|
||||
fn builtin_ascii(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let repr = vm.to_repr(&obj)?;
|
||||
let ascii = to_ascii(&repr.value);
|
||||
Ok(ascii)
|
||||
}
|
||||
|
||||
/// Convert a string to ascii compatible, escaping unicodes into escape
|
||||
/// sequences.
|
||||
pub fn to_ascii(value: &str) -> String {
|
||||
let mut ascii = String::new();
|
||||
for c in repr.value.chars() {
|
||||
for c in value.chars() {
|
||||
if c.is_ascii() {
|
||||
ascii.push(c)
|
||||
} else {
|
||||
@@ -74,7 +81,7 @@ fn builtin_ascii(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
ascii.push_str(&hex)
|
||||
}
|
||||
}
|
||||
Ok(ascii)
|
||||
ascii
|
||||
}
|
||||
|
||||
fn builtin_bin(x: PyIntRef, _vm: &VirtualMachine) -> String {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::obj::objbool;
|
||||
use crate::obj::objstr::PyString;
|
||||
use crate::pyhash;
|
||||
use crate::pyobject::{IdProtocol, PyObjectRef, PyResult};
|
||||
use crate::pyobject::{IdProtocol, IntoPyObject, PyObjectRef, PyResult};
|
||||
use crate::vm::VirtualMachine;
|
||||
use num_bigint::ToBigInt;
|
||||
/// Ordered dictionary implementation.
|
||||
@@ -53,12 +53,12 @@ impl<T: Clone> Dict<T> {
|
||||
&mut self,
|
||||
hash_index: HashIndex,
|
||||
hash_value: HashValue,
|
||||
key: &PyObjectRef,
|
||||
key: PyObjectRef,
|
||||
value: T,
|
||||
) {
|
||||
let entry = DictEntry {
|
||||
hash: hash_value,
|
||||
key: key.clone(),
|
||||
key,
|
||||
value,
|
||||
};
|
||||
let entry_index = self.entries.len();
|
||||
@@ -73,7 +73,12 @@ impl<T: Clone> Dict<T> {
|
||||
}
|
||||
|
||||
/// Store a key
|
||||
pub fn insert(&mut self, vm: &VirtualMachine, key: &PyObjectRef, value: T) -> PyResult<()> {
|
||||
pub fn insert<K: DictKey + IntoPyObject + Copy>(
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
key: K,
|
||||
value: T,
|
||||
) -> PyResult<()> {
|
||||
match self.lookup(vm, key)? {
|
||||
LookupResult::Existing(index) => {
|
||||
// Update existing key
|
||||
@@ -89,13 +94,13 @@ impl<T: Clone> Dict<T> {
|
||||
hash_value,
|
||||
} => {
|
||||
// New key:
|
||||
self.unchecked_push(hash_index, hash_value, key, value);
|
||||
self.unchecked_push(hash_index, hash_value, key.into_pyobject(vm)?, value);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains<K: DictKey>(&self, vm: &VirtualMachine, key: &K) -> PyResult<bool> {
|
||||
pub fn contains<K: DictKey + Copy>(&self, vm: &VirtualMachine, key: K) -> PyResult<bool> {
|
||||
if let LookupResult::Existing(_) = self.lookup(vm, key)? {
|
||||
Ok(true)
|
||||
} else {
|
||||
@@ -113,7 +118,7 @@ impl<T: Clone> Dict<T> {
|
||||
|
||||
/// Retrieve a key
|
||||
#[cfg_attr(feature = "flame-it", flame("Dict"))]
|
||||
pub fn get<K: DictKey>(&self, vm: &VirtualMachine, key: &K) -> PyResult<Option<T>> {
|
||||
pub fn get<K: DictKey + Copy>(&self, vm: &VirtualMachine, key: K) -> PyResult<Option<T>> {
|
||||
if let LookupResult::Existing(index) = self.lookup(vm, key)? {
|
||||
Ok(Some(self.unchecked_get(index)))
|
||||
} else {
|
||||
@@ -156,7 +161,7 @@ impl<T: Clone> Dict<T> {
|
||||
LookupResult::NewIndex {
|
||||
hash_value,
|
||||
hash_index,
|
||||
} => self.unchecked_push(hash_index, hash_value, &key, value),
|
||||
} => self.unchecked_push(hash_index, hash_value, key.clone(), value),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
@@ -201,7 +206,7 @@ impl<T: Clone> Dict<T> {
|
||||
|
||||
/// Lookup the index for the given key.
|
||||
#[cfg_attr(feature = "flame-it", flame("Dict"))]
|
||||
fn lookup<K: DictKey>(&self, vm: &VirtualMachine, key: &K) -> PyResult<LookupResult> {
|
||||
fn lookup<K: DictKey + Copy>(&self, vm: &VirtualMachine, key: K) -> PyResult<LookupResult> {
|
||||
let hash_value = key.do_hash(vm)?;
|
||||
let perturb = hash_value;
|
||||
let mut hash_index: HashIndex = hash_value;
|
||||
@@ -244,7 +249,7 @@ impl<T: Clone> Dict<T> {
|
||||
}
|
||||
|
||||
/// Retrieve and delete a key
|
||||
pub fn pop<K: DictKey>(&mut self, vm: &VirtualMachine, key: &K) -> PyResult<Option<T>> {
|
||||
pub fn pop<K: DictKey + Copy>(&mut self, vm: &VirtualMachine, key: K) -> PyResult<Option<T>> {
|
||||
if let LookupResult::Existing(index) = self.lookup(vm, key)? {
|
||||
let value = self.unchecked_get(index);
|
||||
self.unchecked_delete(index);
|
||||
@@ -280,26 +285,26 @@ enum LookupResult {
|
||||
/// - PyObjectRef -> arbitrary python type used as key
|
||||
/// - str -> string reference used as key, this is often used internally
|
||||
pub trait DictKey {
|
||||
fn do_hash(&self, vm: &VirtualMachine) -> PyResult<HashValue>;
|
||||
fn do_is(&self, other: &PyObjectRef) -> bool;
|
||||
fn do_eq(&self, vm: &VirtualMachine, other_key: &PyObjectRef) -> PyResult<bool>;
|
||||
fn do_hash(self, vm: &VirtualMachine) -> PyResult<HashValue>;
|
||||
fn do_is(self, other: &PyObjectRef) -> bool;
|
||||
fn do_eq(self, vm: &VirtualMachine, other_key: &PyObjectRef) -> PyResult<bool>;
|
||||
}
|
||||
|
||||
/// Implement trait for PyObjectRef such that we can use python objects
|
||||
/// to index dictionaries.
|
||||
impl DictKey for PyObjectRef {
|
||||
fn do_hash(&self, vm: &VirtualMachine) -> PyResult<HashValue> {
|
||||
impl DictKey for &PyObjectRef {
|
||||
fn do_hash(self, vm: &VirtualMachine) -> PyResult<HashValue> {
|
||||
let raw_hash = vm._hash(self)?;
|
||||
let mut hasher = DefaultHasher::new();
|
||||
raw_hash.hash(&mut hasher);
|
||||
Ok(hasher.finish() as HashValue)
|
||||
}
|
||||
|
||||
fn do_is(&self, other: &PyObjectRef) -> bool {
|
||||
fn do_is(self, other: &PyObjectRef) -> bool {
|
||||
self.is(other)
|
||||
}
|
||||
|
||||
fn do_eq(&self, vm: &VirtualMachine, other_key: &PyObjectRef) -> PyResult<bool> {
|
||||
fn do_eq(self, vm: &VirtualMachine, other_key: &PyObjectRef) -> PyResult<bool> {
|
||||
let result = vm._eq(self.clone(), other_key.clone())?;
|
||||
objbool::boolval(vm, result)
|
||||
}
|
||||
@@ -307,8 +312,35 @@ impl DictKey for PyObjectRef {
|
||||
|
||||
/// Implement trait for the str type, so that we can use strings
|
||||
/// to index dictionaries.
|
||||
impl DictKey for String {
|
||||
fn do_hash(&self, _vm: &VirtualMachine) -> PyResult<HashValue> {
|
||||
impl DictKey for &str {
|
||||
fn do_hash(self, _vm: &VirtualMachine) -> PyResult<HashValue> {
|
||||
// follow a similar route as the hashing of PyStringRef
|
||||
let raw_hash = pyhash::hash_value(&self.to_string()).to_bigint().unwrap();
|
||||
let raw_hash = pyhash::hash_bigint(&raw_hash);
|
||||
let mut hasher = DefaultHasher::new();
|
||||
raw_hash.hash(&mut hasher);
|
||||
Ok(hasher.finish() as HashValue)
|
||||
}
|
||||
|
||||
fn do_is(self, _other: &PyObjectRef) -> bool {
|
||||
// No matter who the other pyobject is, we are never the same thing, since
|
||||
// we are a str, not a pyobject.
|
||||
false
|
||||
}
|
||||
|
||||
fn do_eq(self, vm: &VirtualMachine, other_key: &PyObjectRef) -> PyResult<bool> {
|
||||
if let Some(py_str_value) = other_key.payload::<PyString>() {
|
||||
Ok(py_str_value.value == self)
|
||||
} else {
|
||||
// Fall back to PyString implementation.
|
||||
let s = vm.new_str(self.to_string());
|
||||
s.do_eq(vm, other_key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DictKey for &String {
|
||||
fn do_hash(self, _vm: &VirtualMachine) -> PyResult<HashValue> {
|
||||
// follow a similar route as the hashing of PyStringRef
|
||||
let raw_hash = pyhash::hash_value(self).to_bigint().unwrap();
|
||||
let raw_hash = pyhash::hash_bigint(&raw_hash);
|
||||
@@ -317,13 +349,13 @@ impl DictKey for String {
|
||||
Ok(hasher.finish() as HashValue)
|
||||
}
|
||||
|
||||
fn do_is(&self, _other: &PyObjectRef) -> bool {
|
||||
fn do_is(self, _other: &PyObjectRef) -> bool {
|
||||
// No matter who the other pyobject is, we are never the same thing, since
|
||||
// we are a str, not a pyobject.
|
||||
false
|
||||
}
|
||||
|
||||
fn do_eq(&self, vm: &VirtualMachine, other_key: &PyObjectRef) -> PyResult<bool> {
|
||||
fn do_eq(self, vm: &VirtualMachine, other_key: &PyObjectRef) -> PyResult<bool> {
|
||||
if let Some(py_str_value) = other_key.payload::<PyString>() {
|
||||
Ok(&py_str_value.value == self)
|
||||
} else {
|
||||
@@ -364,9 +396,9 @@ mod tests {
|
||||
assert_eq!(2, dict.len());
|
||||
|
||||
assert_eq!(true, dict.contains(&vm, &key1).unwrap());
|
||||
assert_eq!(true, dict.contains(&vm, &"x".to_string()).unwrap());
|
||||
assert_eq!(true, dict.contains(&vm, "x").unwrap());
|
||||
|
||||
let val = dict.get(&vm, &"x".to_string()).unwrap().unwrap();
|
||||
let val = dict.get(&vm, "x").unwrap().unwrap();
|
||||
vm._eq(val, value2)
|
||||
.expect("retrieved value must be equal to inserted value.");
|
||||
}
|
||||
@@ -389,8 +421,8 @@ mod tests {
|
||||
|
||||
fn check_hash_equivalence(text: &str) {
|
||||
let vm: VirtualMachine = Default::default();
|
||||
let value1 = text.to_string();
|
||||
let value2 = vm.new_str(value1.clone());
|
||||
let value1 = text;
|
||||
let value2 = vm.new_str(value1.to_string());
|
||||
|
||||
let hash1 = value1.do_hash(&vm).expect("Hash should not fail.");
|
||||
let hash2 = value2.do_hash(&vm).expect("Hash should not fail.");
|
||||
|
||||
@@ -17,17 +17,14 @@ pub fn eval(vm: &VirtualMachine, source: &str, scope: Scope, source_path: &str)
|
||||
mod tests {
|
||||
use super::eval;
|
||||
use super::VirtualMachine;
|
||||
use crate::pyobject::IdProtocol;
|
||||
|
||||
#[test]
|
||||
fn test_print_42() {
|
||||
let source = String::from("print('Hello world')");
|
||||
let vm: VirtualMachine = Default::default();
|
||||
let vm = VirtualMachine::default();
|
||||
let vars = vm.new_scope_with_builtins();
|
||||
let _result = eval(&vm, &source, vars, "<unittest>");
|
||||
|
||||
// TODO: check result?
|
||||
//assert_eq!(
|
||||
// parse_ast,
|
||||
// );
|
||||
let result = eval(&vm, &source, vars, "<unittest>").expect("this should pass");
|
||||
assert!(result.is(&vm.ctx.none()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,12 +285,12 @@ impl Frame {
|
||||
let dict: PyDictRef =
|
||||
obj.downcast().expect("Need a dictionary to build a map.");
|
||||
for (key, value) in dict {
|
||||
map_obj.set_item(key, value, vm).unwrap();
|
||||
map_obj.set_item(&key, value, vm).unwrap();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (key, value) in self.pop_multiple(2 * size).into_iter().tuples() {
|
||||
map_obj.set_item(key, value, vm).unwrap();
|
||||
map_obj.set_item(&key, value, vm).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -666,7 +666,7 @@ impl Frame {
|
||||
let value = match conversion {
|
||||
Some(Str) => vm.to_str(&self.pop_value())?.into_object(),
|
||||
Some(Repr) => vm.to_repr(&self.pop_value())?.into_object(),
|
||||
Some(Ascii) => self.pop_value(), // TODO
|
||||
Some(Ascii) => vm.to_ascii(&self.pop_value())?,
|
||||
None => self.pop_value(),
|
||||
};
|
||||
|
||||
@@ -946,14 +946,14 @@ impl Frame {
|
||||
let idx = self.pop_value();
|
||||
let obj = self.pop_value();
|
||||
let value = self.pop_value();
|
||||
obj.set_item(idx, value, vm)?;
|
||||
obj.set_item(&idx, value, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn execute_delete_subscript(&self, vm: &VirtualMachine) -> FrameResult {
|
||||
let idx = self.pop_value();
|
||||
let obj = self.pop_value();
|
||||
obj.del_item(idx, vm)?;
|
||||
obj.del_item(&idx, vm)?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@@ -1062,7 +1062,7 @@ impl Frame {
|
||||
bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref),
|
||||
// TODO: Subscript should probably have its own op
|
||||
bytecode::BinaryOperator::Subscript => a_ref.get_item(b_ref, vm),
|
||||
bytecode::BinaryOperator::Subscript => a_ref.get_item(&b_ref, vm),
|
||||
bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref),
|
||||
bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref),
|
||||
|
||||
@@ -12,7 +12,7 @@ use super::objbool;
|
||||
use super::objiter;
|
||||
use super::objstr;
|
||||
use super::objtype;
|
||||
use crate::dictdatatype;
|
||||
use crate::dictdatatype::{self, DictKey};
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::PyClassImpl;
|
||||
|
||||
@@ -200,19 +200,45 @@ impl PyDictRef {
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
self.entries.borrow_mut().insert(vm, &key, value)
|
||||
self.inner_setitem_fast(&key, value, vm)
|
||||
}
|
||||
|
||||
/// Set item variant which can be called with multiple
|
||||
/// key types, such as str to name a notable one.
|
||||
fn inner_setitem_fast<K: DictKey + IntoPyObject + Copy>(
|
||||
&self,
|
||||
key: K,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
self.entries.borrow_mut().insert(vm, key, value)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("PyDictRef"))]
|
||||
fn inner_getitem(self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(value) = self.entries.borrow().get(vm, &key)? {
|
||||
return Ok(value);
|
||||
if let Some(value) = self.inner_getitem_option(&key, vm)? {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(vm.new_key_error(key.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an optional inner item, or an error (can be key error as well)
|
||||
fn inner_getitem_option<K: DictKey + IntoPyObject + Copy>(
|
||||
&self,
|
||||
key: K,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
if let Some(value) = self.entries.borrow().get(vm, key)? {
|
||||
return Ok(Some(value));
|
||||
}
|
||||
|
||||
if let Some(method_or_err) = vm.get_method(self.clone().into_object(), "__missing__") {
|
||||
let method = method_or_err?;
|
||||
return vm.invoke(&method, vec![key]);
|
||||
Ok(Some(vm.invoke(&method, vec![key.into_pyobject(vm)?])?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Err(vm.new_key_error(key.clone()))
|
||||
}
|
||||
|
||||
fn get(
|
||||
@@ -318,18 +344,44 @@ impl PyDictRef {
|
||||
self.entries.borrow().size()
|
||||
}
|
||||
|
||||
pub fn get_item_option<T: IntoPyObject>(
|
||||
/// This function can be used to get an item without raising the
|
||||
/// KeyError, so we can simply check upon the result being Some
|
||||
/// python value, or None.
|
||||
/// Note that we can pass any type which implements the DictKey
|
||||
/// trait. Notable examples are String and PyObjectRef.
|
||||
pub fn get_item_option<T: IntoPyObject + DictKey + Copy>(
|
||||
&self,
|
||||
key: T,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
match self.get_item(key, vm) {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(exc) => {
|
||||
if objtype::isinstance(&exc, &vm.ctx.exceptions.key_error) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(exc)
|
||||
// Test if this object is a true dict, or mabye a subclass?
|
||||
// If it is a dict, we can directly invoke inner_get_item_option,
|
||||
// and prevent the creation of the KeyError exception.
|
||||
// Also note, that we prevent the creation of a full PyString object
|
||||
// if we lookup local names (which happens all of the time).
|
||||
if self.typ().is(&vm.ctx.dict_type()) {
|
||||
// We can take the short path here!
|
||||
match self.inner_getitem_option(key, vm) {
|
||||
Err(exc) => {
|
||||
if objtype::isinstance(&exc, &vm.ctx.exceptions.key_error) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(exc)
|
||||
}
|
||||
}
|
||||
Ok(x) => Ok(x),
|
||||
}
|
||||
} else {
|
||||
// Fall back to full get_item with KeyError checking
|
||||
|
||||
match self.get_item(key, vm) {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(exc) => {
|
||||
if objtype::isinstance(&exc, &vm.ctx.exceptions.key_error) {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(exc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,20 +389,26 @@ impl PyDictRef {
|
||||
}
|
||||
|
||||
impl ItemProtocol for PyDictRef {
|
||||
fn get_item<T: IntoPyObject>(&self, key: T, vm: &VirtualMachine) -> PyResult {
|
||||
fn get_item<T: IntoPyObject + DictKey + Copy>(&self, key: T, vm: &VirtualMachine) -> PyResult {
|
||||
self.as_object().get_item(key, vm)
|
||||
}
|
||||
|
||||
fn set_item<T: IntoPyObject>(
|
||||
fn set_item<T: IntoPyObject + DictKey + Copy>(
|
||||
&self,
|
||||
key: T,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
self.as_object().set_item(key, value, vm)
|
||||
if self.typ().is(&vm.ctx.dict_type()) {
|
||||
self.inner_setitem_fast(key, value, vm)
|
||||
.map(|_| vm.ctx.none())
|
||||
} else {
|
||||
// Fall back to slow path if we are in a dict subclass:
|
||||
self.as_object().set_item(key, value, vm)
|
||||
}
|
||||
}
|
||||
|
||||
fn del_item<T: IntoPyObject>(&self, key: T, vm: &VirtualMachine) -> PyResult {
|
||||
fn del_item<T: IntoPyObject + DictKey + Copy>(&self, key: T, vm: &VirtualMachine) -> PyResult {
|
||||
self.as_object().del_item(key, vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ fn inner_mod(int1: &PyInt, int2: &PyInt, vm: &VirtualMachine) -> PyResult {
|
||||
if int2.value.is_zero() {
|
||||
Err(vm.new_zero_division_error("integer modulo by zero".to_string()))
|
||||
} else {
|
||||
Ok(vm.ctx.new_int(&int1.value % &int2.value))
|
||||
Ok(vm.ctx.new_int(int1.value.mod_floor(&int2.value)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__floordiv__")]
|
||||
fn floordiv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_floordiv(self, &other, &vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -309,7 +309,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__rfloordiv__")]
|
||||
fn rfloordiv(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_floordiv(&other, self, &vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -322,7 +322,7 @@ impl PyInt {
|
||||
return Ok(vm.ctx.not_implemented());
|
||||
}
|
||||
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_lshift(self, other, vm)
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ impl PyInt {
|
||||
return Ok(vm.ctx.not_implemented());
|
||||
}
|
||||
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_lshift(other, self, vm)
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ impl PyInt {
|
||||
return Ok(vm.ctx.not_implemented());
|
||||
}
|
||||
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_rshift(self, other, vm)
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ impl PyInt {
|
||||
return Ok(vm.ctx.not_implemented());
|
||||
}
|
||||
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_rshift(other, self, vm)
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__pow__")]
|
||||
fn pow(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_pow(self, &other, vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -412,7 +412,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__rpow__")]
|
||||
fn rpow(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_pow(&other, self, vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -422,7 +422,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__mod__")]
|
||||
fn mod_(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_mod(self, &other, vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -432,7 +432,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__rmod__")]
|
||||
fn rmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_mod(&other, self, vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -442,7 +442,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__divmod__")]
|
||||
fn divmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_divmod(self, &other, vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -452,7 +452,7 @@ impl PyInt {
|
||||
#[pymethod(name = "__rdivmod__")]
|
||||
fn rdivmod(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::isinstance(&other, &vm.ctx.int_type()) {
|
||||
let other = other.payload::<PyInt>().unwrap();
|
||||
let other = get_py_int(&other);
|
||||
inner_divmod(&other, self, vm)
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
@@ -768,11 +768,11 @@ pub fn to_int(vm: &VirtualMachine, obj: &PyObjectRef, mut base: u32) -> PyResult
|
||||
|
||||
// Retrieve inner int value:
|
||||
pub fn get_value(obj: &PyObjectRef) -> &BigInt {
|
||||
&obj.payload::<PyInt>().unwrap().value
|
||||
&get_py_int(obj).value
|
||||
}
|
||||
|
||||
pub fn get_float_value(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
obj.payload::<PyInt>().unwrap().float(vm)
|
||||
get_py_int(obj).float(vm)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -821,6 +821,10 @@ fn get_shift_amount(amount: &PyInt, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_py_int(obj: &PyObjectRef) -> &PyInt {
|
||||
&obj.payload::<PyInt>().unwrap()
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
PyInt::extend_class(context, &context.types.int_type);
|
||||
extend_class!(context, &context.types.int_type, {
|
||||
|
||||
@@ -78,7 +78,7 @@ fn object_setattr(
|
||||
}
|
||||
|
||||
if let Some(ref dict) = obj.clone().dict {
|
||||
dict.set_item(attr_name, value, vm)?;
|
||||
dict.set_item(&attr_name.value, value, vm)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
@@ -99,7 +99,7 @@ fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine)
|
||||
}
|
||||
|
||||
if let Some(ref dict) = obj.dict {
|
||||
dict.del_item(attr_name, vm)?;
|
||||
dict.del_item(&attr_name.value, vm)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
|
||||
@@ -17,11 +17,14 @@ use super::objslice::{PySlice, PySliceRef};
|
||||
use super::objtuple::PyTuple;
|
||||
|
||||
pub trait PySliceableSequence {
|
||||
fn do_slice(&self, range: Range<usize>) -> Self;
|
||||
fn do_slice_reverse(&self, range: Range<usize>) -> Self;
|
||||
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self;
|
||||
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self;
|
||||
fn empty() -> Self;
|
||||
type Sliced;
|
||||
|
||||
fn do_slice(&self, range: Range<usize>) -> Self::Sliced;
|
||||
fn do_slice_reverse(&self, range: Range<usize>) -> Self::Sliced;
|
||||
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self::Sliced;
|
||||
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self::Sliced;
|
||||
fn empty() -> Self::Sliced;
|
||||
|
||||
fn len(&self) -> usize;
|
||||
fn is_empty(&self) -> bool;
|
||||
fn get_pos(&self, p: i32) -> Option<usize> {
|
||||
@@ -63,7 +66,11 @@ pub trait PySliceableSequence {
|
||||
start..stop
|
||||
}
|
||||
|
||||
fn get_slice_items(&self, vm: &VirtualMachine, slice: &PyObjectRef) -> Result<Self, PyObjectRef>
|
||||
fn get_slice_items(
|
||||
&self,
|
||||
vm: &VirtualMachine,
|
||||
slice: &PyObjectRef,
|
||||
) -> Result<Self::Sliced, PyObjectRef>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -121,25 +128,27 @@ pub trait PySliceableSequence {
|
||||
}
|
||||
|
||||
impl<T: Clone> PySliceableSequence for Vec<T> {
|
||||
fn do_slice(&self, range: Range<usize>) -> Self {
|
||||
type Sliced = Vec<T>;
|
||||
|
||||
fn do_slice(&self, range: Range<usize>) -> Self::Sliced {
|
||||
self[range].to_vec()
|
||||
}
|
||||
|
||||
fn do_slice_reverse(&self, range: Range<usize>) -> Self {
|
||||
fn do_slice_reverse(&self, range: Range<usize>) -> Self::Sliced {
|
||||
let mut slice = self[range].to_vec();
|
||||
slice.reverse();
|
||||
slice
|
||||
}
|
||||
|
||||
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self {
|
||||
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self::Sliced {
|
||||
self[range].iter().step_by(step).cloned().collect()
|
||||
}
|
||||
|
||||
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self {
|
||||
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self::Sliced {
|
||||
self[range].iter().rev().step_by(step).cloned().collect()
|
||||
}
|
||||
|
||||
fn empty() -> Self {
|
||||
fn empty() -> Self::Sliced {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
@@ -235,7 +244,7 @@ pub fn get_item(
|
||||
}
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"TypeError: indexing type {:?} with index {:?} is not supported (yet?)",
|
||||
"indexing type {:?} with index {:?} is not supported (yet?)",
|
||||
sequence, subscript
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -996,7 +996,7 @@ impl PyString {
|
||||
|
||||
let mut translated = String::new();
|
||||
for c in self.value.chars() {
|
||||
match table.get_item(c as u32, vm) {
|
||||
match table.get_item(&(c as u32).into_pyobject(vm)?, vm) {
|
||||
Ok(value) => {
|
||||
if let Some(text) = value.payload::<PyString>() {
|
||||
translated.push_str(&text.value);
|
||||
@@ -1036,11 +1036,11 @@ impl PyString {
|
||||
Ok(from_str) => {
|
||||
if to_str.len(vm) == from_str.len(vm) {
|
||||
for (c1, c2) in from_str.value.chars().zip(to_str.value.chars()) {
|
||||
new_dict.set_item(c1 as u32, vm.new_int(c2 as u32), vm)?;
|
||||
new_dict.set_item(&vm.new_int(c1 as u32), vm.new_int(c2 as u32), vm)?;
|
||||
}
|
||||
if let OptionalArg::Present(none_str) = none_str {
|
||||
for c in none_str.value.chars() {
|
||||
new_dict.set_item(c as u32, vm.get_none(), vm)?;
|
||||
new_dict.set_item(&vm.new_int(c as u32), vm.get_none(), vm)?;
|
||||
}
|
||||
}
|
||||
new_dict.into_pyobject(vm)
|
||||
@@ -1061,11 +1061,15 @@ impl PyString {
|
||||
Ok(dict) => {
|
||||
for (key, val) in dict {
|
||||
if let Some(num) = key.payload::<PyInt>() {
|
||||
new_dict.set_item(num.as_bigint().to_i32(), val, vm)?;
|
||||
new_dict.set_item(
|
||||
&num.as_bigint().to_i32().into_pyobject(vm)?,
|
||||
val,
|
||||
vm,
|
||||
)?;
|
||||
} else if let Some(string) = key.payload::<PyString>() {
|
||||
if string.len(vm) == 1 {
|
||||
let num_value = string.value.chars().next().unwrap() as u32;
|
||||
new_dict.set_item(num_value, val, vm)?;
|
||||
new_dict.set_item(&num_value.into_pyobject(vm)?, val, vm)?;
|
||||
} else {
|
||||
return Err(vm.new_value_error(
|
||||
"string keys in translate table must be of length 1".to_owned(),
|
||||
@@ -1459,13 +1463,15 @@ fn perform_format(
|
||||
}
|
||||
|
||||
impl PySliceableSequence for String {
|
||||
fn do_slice(&self, range: Range<usize>) -> Self {
|
||||
type Sliced = String;
|
||||
|
||||
fn do_slice(&self, range: Range<usize>) -> Self::Sliced {
|
||||
to_graphemes(self)
|
||||
.get(range)
|
||||
.map_or(String::default(), |c| c.join(""))
|
||||
}
|
||||
|
||||
fn do_slice_reverse(&self, range: Range<usize>) -> Self {
|
||||
fn do_slice_reverse(&self, range: Range<usize>) -> Self::Sliced {
|
||||
to_graphemes(self)
|
||||
.get_mut(range)
|
||||
.map_or(String::default(), |slice| {
|
||||
@@ -1474,7 +1480,7 @@ impl PySliceableSequence for String {
|
||||
})
|
||||
}
|
||||
|
||||
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self {
|
||||
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self::Sliced {
|
||||
if let Some(s) = to_graphemes(self).get(range) {
|
||||
return s
|
||||
.iter()
|
||||
@@ -1486,7 +1492,7 @@ impl PySliceableSequence for String {
|
||||
String::default()
|
||||
}
|
||||
|
||||
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self {
|
||||
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self::Sliced {
|
||||
if let Some(s) = to_graphemes(self).get(range) {
|
||||
return s
|
||||
.iter()
|
||||
@@ -1499,7 +1505,7 @@ impl PySliceableSequence for String {
|
||||
String::default()
|
||||
}
|
||||
|
||||
fn empty() -> Self {
|
||||
fn empty() -> Self::Sliced {
|
||||
String::default()
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ pub type PySuperRef = PyRef<PySuper>;
|
||||
pub struct PySuper {
|
||||
obj: PyObjectRef,
|
||||
typ: PyObjectRef,
|
||||
obj_type: PyObjectRef,
|
||||
}
|
||||
|
||||
impl PyValue for PySuper {
|
||||
@@ -53,9 +54,31 @@ pub fn init(context: &PyContext) {
|
||||
"__new__" => context.new_rustfunc(super_new),
|
||||
"__getattribute__" => context.new_rustfunc(super_getattribute),
|
||||
"__doc__" => context.new_str(super_doc.to_string()),
|
||||
"__str__" => context.new_rustfunc(super_str),
|
||||
"__repr__" => context.new_rustfunc(super_repr),
|
||||
});
|
||||
}
|
||||
|
||||
fn super_str(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_method(&zelf, "__repr__", vec![])
|
||||
}
|
||||
|
||||
fn super_repr(zelf: PyObjectRef, _vm: &VirtualMachine) -> String {
|
||||
let super_obj = zelf.downcast::<PySuper>().unwrap();
|
||||
let class_type_str = if let Ok(type_class) = super_obj.typ.clone().downcast::<PyClass>() {
|
||||
type_class.name.clone()
|
||||
} else {
|
||||
"NONE".to_string()
|
||||
};
|
||||
match super_obj.obj_type.clone().downcast::<PyClass>() {
|
||||
Ok(obj_class_typ) => format!(
|
||||
"<super: <class '{}'>, <{} object>>",
|
||||
class_type_str, obj_class_typ.name
|
||||
),
|
||||
_ => format!("<super: <class '{}'> NULL>", class_type_str),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_getattribute(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
@@ -141,7 +164,7 @@ fn super_new(
|
||||
};
|
||||
|
||||
// Check obj type:
|
||||
if !objtype::isinstance(&py_obj, &py_type) {
|
||||
let obj_type = if !objtype::isinstance(&py_obj, &py_type) {
|
||||
let is_subclass = if let Ok(py_obj) = PyClassRef::try_from_object(vm, py_obj.clone()) {
|
||||
objtype::issubclass(&py_obj, &py_type)
|
||||
} else {
|
||||
@@ -152,11 +175,15 @@ fn super_new(
|
||||
"super(type, obj): obj must be an instance or subtype of type".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
PyClassRef::try_from_object(vm, py_obj.clone())?
|
||||
} else {
|
||||
py_obj.class()
|
||||
};
|
||||
|
||||
PySuper {
|
||||
obj: py_obj,
|
||||
typ: py_type.into_object(),
|
||||
obj_type: obj_type.into_object(),
|
||||
}
|
||||
.into_ref_with_type(vm, cls)
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ impl<'de> Visitor<'de> for PyObjectDeserializer<'de> {
|
||||
// Although JSON keys must be strings, implementation accepts any keys
|
||||
// and can be reused by other deserializers without such limit
|
||||
while let Some((key_obj, value)) = access.next_entry_seed(self.clone(), self.clone())? {
|
||||
dict.set_item(key_obj, value, self.vm).unwrap();
|
||||
dict.set_item(&key_obj, value, self.vm).unwrap();
|
||||
}
|
||||
Ok(dict.into_object())
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ use num_complex::Complex64;
|
||||
use num_traits::{One, Zero};
|
||||
|
||||
use crate::bytecode;
|
||||
use crate::dictdatatype::DictKey;
|
||||
use crate::exceptions;
|
||||
use crate::function::{IntoPyNativeFunc, PyFuncArgs};
|
||||
use crate::obj::objbuiltinfunc::PyBuiltinFunction;
|
||||
@@ -764,15 +765,17 @@ impl<T> TypeProtocol for PyRef<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The python item protocol. Mostly applies to dictionaries.
|
||||
/// Allows getting, setting and deletion of keys-value pairs.
|
||||
pub trait ItemProtocol {
|
||||
fn get_item<T: IntoPyObject>(&self, key: T, vm: &VirtualMachine) -> PyResult;
|
||||
fn set_item<T: IntoPyObject>(
|
||||
fn get_item<T: IntoPyObject + DictKey + Copy>(&self, key: T, vm: &VirtualMachine) -> PyResult;
|
||||
fn set_item<T: IntoPyObject + DictKey + Copy>(
|
||||
&self,
|
||||
key: T,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult;
|
||||
fn del_item<T: IntoPyObject>(&self, key: T, vm: &VirtualMachine) -> PyResult;
|
||||
fn del_item<T: IntoPyObject + DictKey + Copy>(&self, key: T, vm: &VirtualMachine) -> PyResult;
|
||||
}
|
||||
|
||||
impl ItemProtocol for PyObjectRef {
|
||||
@@ -965,6 +968,12 @@ impl IntoPyObject for PyObjectRef {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPyObject for &PyObjectRef {
|
||||
fn into_pyobject(self, _vm: &VirtualMachine) -> PyResult {
|
||||
Ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoPyObject for PyResult<T>
|
||||
where
|
||||
T: IntoPyObject,
|
||||
|
||||
@@ -138,11 +138,8 @@ impl NameProtocol for Scope {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value) = self.globals.get_item_option(name, vm).unwrap() {
|
||||
return Some(value);
|
||||
}
|
||||
|
||||
vm.get_attribute(vm.builtins.clone(), name).ok()
|
||||
// Fall back to loading a global after all scopes have been searched!
|
||||
self.load_global(vm, name)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Scope"))]
|
||||
@@ -174,7 +171,11 @@ impl NameProtocol for Scope {
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Scope"))]
|
||||
fn load_global(&self, vm: &VirtualMachine, name: &str) -> Option<PyObjectRef> {
|
||||
self.globals.get_item_option(name, vm).unwrap()
|
||||
if let Some(value) = self.globals.get_item_option(name, vm).unwrap() {
|
||||
Some(value)
|
||||
} else {
|
||||
vm.get_attribute(vm.builtins.clone(), name).ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn store_global(&self, vm: &VirtualMachine, name: &str, value: PyObjectRef) {
|
||||
|
||||
@@ -252,7 +252,7 @@ fn optional_statements_to_ast(
|
||||
let statements = if let Some(statements) = statements {
|
||||
statements_to_ast(vm, statements)?.into_object()
|
||||
} else {
|
||||
vm.ctx.none()
|
||||
vm.ctx.new_list(vec![])
|
||||
};
|
||||
Ok(statements)
|
||||
}
|
||||
@@ -283,6 +283,17 @@ fn make_string_list(vm: &VirtualMachine, names: &[String]) -> PyObjectRef {
|
||||
)
|
||||
}
|
||||
|
||||
fn optional_expressions_to_ast(
|
||||
vm: &VirtualMachine,
|
||||
expressions: &[Option<ast::Expression>],
|
||||
) -> PyResult<PyListRef> {
|
||||
let py_expression_nodes: PyResult<_> = expressions
|
||||
.iter()
|
||||
.map(|expression| Ok(optional_expression_to_ast(vm, expression)?))
|
||||
.collect();
|
||||
Ok(vm.ctx.new_list(py_expression_nodes?).downcast().unwrap())
|
||||
}
|
||||
|
||||
fn optional_expression_to_ast(vm: &VirtualMachine, value: &Option<ast::Expression>) -> PyResult {
|
||||
let value = if let Some(value) = value {
|
||||
expression_to_ast(vm, value)?.into_object()
|
||||
@@ -526,8 +537,23 @@ fn operator_string(op: &ast::Operator) -> String {
|
||||
}
|
||||
|
||||
fn parameters_to_ast(vm: &VirtualMachine, args: &ast::Parameters) -> PyResult<AstNodeRef> {
|
||||
let args = map_ast(parameter_to_ast, vm, &args.args)?;
|
||||
Ok(node!(vm, arguments, { args => args }))
|
||||
Ok(node!(vm, arguments, {
|
||||
args => map_ast(parameter_to_ast, vm, &args.args)?,
|
||||
vararg => vararg_to_ast(vm, &args.vararg)?,
|
||||
kwonlyargs => map_ast(parameter_to_ast, vm, &args.kwonlyargs)?,
|
||||
kw_defaults => optional_expressions_to_ast(vm, &args.kw_defaults)?,
|
||||
kwarg => vararg_to_ast(vm, &args.kwarg)?,
|
||||
defaults => expressions_to_ast(vm, &args.defaults)?
|
||||
}))
|
||||
}
|
||||
|
||||
fn vararg_to_ast(vm: &VirtualMachine, vararg: &ast::Varargs) -> PyResult {
|
||||
let py_node = match vararg {
|
||||
ast::Varargs::None => vm.get_none(),
|
||||
ast::Varargs::Unnamed => vm.get_none(),
|
||||
ast::Varargs::Named(parameter) => parameter_to_ast(vm, parameter)?.into_object(),
|
||||
};
|
||||
Ok(py_node)
|
||||
}
|
||||
|
||||
fn parameter_to_ast(vm: &VirtualMachine, parameter: &ast::Parameter) -> PyResult<AstNodeRef> {
|
||||
@@ -537,10 +563,15 @@ fn parameter_to_ast(vm: &VirtualMachine, parameter: &ast::Parameter) -> PyResult
|
||||
vm.ctx.none()
|
||||
};
|
||||
|
||||
Ok(node!(vm, arg, {
|
||||
let py_node = node!(vm, arg, {
|
||||
arg => vm.ctx.new_str(parameter.arg.to_string()),
|
||||
annotation => py_annotation
|
||||
}))
|
||||
});
|
||||
|
||||
let lineno = vm.ctx.new_int(parameter.location.row());
|
||||
vm.set_attr(py_node.as_object(), "lineno", lineno)?;
|
||||
|
||||
Ok(py_node)
|
||||
}
|
||||
|
||||
fn optional_string_to_py_obj(vm: &VirtualMachine, name: &Option<String>) -> PyObjectRef {
|
||||
|
||||
@@ -9,7 +9,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
for (name, code) in ERROR_CODES {
|
||||
let name = vm.new_str((*name).to_owned());
|
||||
let code = vm.ctx.new_int(*code);
|
||||
errorcode.set_item(code.clone(), name.clone(), vm).unwrap();
|
||||
errorcode.set_item(&code, name.clone(), vm).unwrap();
|
||||
vm.set_attr(&module, name, code).unwrap();
|
||||
}
|
||||
module
|
||||
|
||||
@@ -346,18 +346,36 @@ fn file_io_init(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
}
|
||||
|
||||
fn file_io_read(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(file_io, None)]);
|
||||
arg_check!(
|
||||
vm,
|
||||
args,
|
||||
required = [(file_io, None)],
|
||||
optional = [(read_byte, Some(vm.ctx.int_type()))]
|
||||
);
|
||||
|
||||
let file_no = vm.get_attribute(file_io.clone(), "fileno")?;
|
||||
let raw_fd = objint::get_value(&file_no).to_i64().unwrap();
|
||||
|
||||
let mut handle = os::rust_file(raw_fd);
|
||||
|
||||
let mut bytes = vec![];
|
||||
match handle.read_to_end(&mut bytes) {
|
||||
Ok(_) => {}
|
||||
Err(_) => return Err(vm.new_value_error("Error reading from Buffer".to_string())),
|
||||
}
|
||||
let bytes = match read_byte {
|
||||
None => {
|
||||
let mut bytes = vec![];
|
||||
handle
|
||||
.read_to_end(&mut bytes)
|
||||
.map_err(|_| vm.new_value_error("Error reading from Buffer".to_string()))?;
|
||||
bytes
|
||||
}
|
||||
Some(read_byte) => {
|
||||
let mut bytes = vec![0; objint::get_value(&read_byte).to_usize().unwrap()];
|
||||
handle
|
||||
.read_exact(&mut bytes)
|
||||
.map_err(|_| vm.new_value_error("Error reading from Buffer".to_string()))?;
|
||||
let updated = os::raw_file_number(handle);
|
||||
vm.set_attr(file_io, "fileno", vm.ctx.new_int(updated))?;
|
||||
bytes
|
||||
}
|
||||
};
|
||||
|
||||
Ok(vm.ctx.new_bytes(bytes))
|
||||
}
|
||||
|
||||
@@ -418,6 +418,64 @@ impl PyItertoolsIslice {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
struct PyItertoolsFilterFalse {
|
||||
predicate: PyObjectRef,
|
||||
iterable: PyObjectRef,
|
||||
}
|
||||
|
||||
impl PyValue for PyItertoolsFilterFalse {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.class("itertools", "filterfalse")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyItertoolsFilterFalse {
|
||||
#[pymethod(name = "__new__")]
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
fn new(
|
||||
_cls: PyClassRef,
|
||||
predicate: PyObjectRef,
|
||||
iterable: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let iter = get_iter(vm, &iterable)?;
|
||||
|
||||
Ok(PyItertoolsFilterFalse {
|
||||
predicate,
|
||||
iterable: iter,
|
||||
}
|
||||
.into_ref(vm)
|
||||
.into_object())
|
||||
}
|
||||
|
||||
#[pymethod(name = "__next__")]
|
||||
fn next(&self, vm: &VirtualMachine) -> PyResult {
|
||||
let predicate = &self.predicate;
|
||||
let iterable = &self.iterable;
|
||||
|
||||
loop {
|
||||
let obj = call_next(vm, iterable)?;
|
||||
let pred_value = if predicate.is(&vm.get_none()) {
|
||||
obj.clone()
|
||||
} else {
|
||||
vm.invoke(predicate, vec![obj.clone()])?
|
||||
};
|
||||
|
||||
if !objbool::boolval(vm, pred_value)? {
|
||||
return Ok(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__iter__")]
|
||||
fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
@@ -436,6 +494,9 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
|
||||
let islice = PyItertoolsIslice::make_class(ctx);
|
||||
|
||||
let filterfalse = ctx.new_class("filterfalse", ctx.object());
|
||||
PyItertoolsFilterFalse::extend_class(ctx, &filterfalse);
|
||||
|
||||
py_module!(vm, "itertools", {
|
||||
"chain" => chain,
|
||||
"count" => count,
|
||||
@@ -443,5 +504,6 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"starmap" => starmap,
|
||||
"takewhile" => takewhile,
|
||||
"islice" => islice,
|
||||
"filterfalse" => filterfalse,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,9 +6,14 @@
|
||||
use statrs::function::erf::{erf, erfc};
|
||||
use statrs::function::gamma::{gamma, ln_gamma};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::cast::ToPrimitive;
|
||||
use num_traits::{One, Zero};
|
||||
|
||||
use crate::function::PyFuncArgs;
|
||||
use crate::obj::objfloat::PyFloatRef;
|
||||
use crate::obj::objint::PyIntRef;
|
||||
use crate::obj::{objfloat, objtype};
|
||||
use crate::obj::{objfloat, objint, objtype};
|
||||
use crate::pyobject::{PyObjectRef, PyResult, TypeProtocol};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
@@ -226,11 +231,41 @@ fn math_frexp(value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
)
|
||||
}
|
||||
|
||||
fn math_ldexp(value: PyFloatRef, i: PyIntRef, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(vm
|
||||
.ctx
|
||||
.new_float(value.to_f64() * (2_f64).powf(i.as_bigint().to_f64().unwrap())))
|
||||
}
|
||||
|
||||
fn math_gcd(a: PyIntRef, b: PyIntRef, vm: &VirtualMachine) -> PyResult {
|
||||
use num_integer::Integer;
|
||||
Ok(vm.new_int(a.as_bigint().gcd(b.as_bigint())))
|
||||
}
|
||||
|
||||
fn math_factorial(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(value, None)]);
|
||||
let value = objint::get_value(value);
|
||||
if *value < BigInt::zero() {
|
||||
return Err(vm.new_value_error("factorial() not defined for negative values".to_string()));
|
||||
} else if *value <= BigInt::one() {
|
||||
return Ok(vm.ctx.new_int(BigInt::from(1u64)));
|
||||
}
|
||||
let ret: BigInt = num_iter::range_inclusive(BigInt::from(1u64), value.clone()).product();
|
||||
Ok(vm.ctx.new_int(ret))
|
||||
}
|
||||
|
||||
fn math_modf(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(value, None)]);
|
||||
let x = objfloat::make_float(vm, value)?;
|
||||
|
||||
let fract = x.fract();
|
||||
let int = x.trunc();
|
||||
|
||||
Ok(vm
|
||||
.ctx
|
||||
.new_tuple(vec![vm.ctx.new_float(fract), vm.ctx.new_float(int)]))
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
@@ -279,6 +314,8 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"lgamma" => ctx.new_rustfunc(math_lgamma),
|
||||
|
||||
"frexp" => ctx.new_rustfunc(math_frexp),
|
||||
"ldexp" => ctx.new_rustfunc(math_ldexp),
|
||||
"modf" => ctx.new_rustfunc(math_modf),
|
||||
|
||||
// Rounding functions:
|
||||
"trunc" => ctx.new_rustfunc(math_trunc),
|
||||
@@ -288,6 +325,9 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
// Gcd function
|
||||
"gcd" => ctx.new_rustfunc(math_gcd),
|
||||
|
||||
// Factorial function
|
||||
"factorial" => ctx.new_rustfunc(math_factorial),
|
||||
|
||||
// Constants:
|
||||
"pi" => ctx.new_float(std::f64::consts::PI), // 3.14159...
|
||||
"e" => ctx.new_float(std::f64::consts::E), // 2.71..
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use num_cpus;
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
@@ -6,8 +7,6 @@ use std::io::{self, Error, ErrorKind, Read, Write};
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{env, fs};
|
||||
|
||||
use num_cpus;
|
||||
|
||||
#[cfg(unix)]
|
||||
use nix::errno::Errno;
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
@@ -221,6 +220,121 @@ fn convert_nix_errno(vm: &VirtualMachine, errno: Errno) -> PyClassRef {
|
||||
}
|
||||
}
|
||||
|
||||
// Flags for os_access
|
||||
bitflags! {
|
||||
pub struct AccessFlags: u8{
|
||||
const F_OK = 0;
|
||||
const R_OK = 4;
|
||||
const W_OK = 2;
|
||||
const X_OK = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
struct Permissions {
|
||||
is_readable: bool,
|
||||
is_writable: bool,
|
||||
is_executable: bool,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_permissions(mode: u32) -> Permissions {
|
||||
Permissions {
|
||||
is_readable: mode & 4 != 0,
|
||||
is_writable: mode & 2 != 0,
|
||||
is_executable: mode & 1 != 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_right_permission(
|
||||
mode: u32,
|
||||
file_owner: Uid,
|
||||
file_group: Gid,
|
||||
) -> Result<Permissions, nix::Error> {
|
||||
let owner_mode = (mode & 0o700) >> 6;
|
||||
let owner_permissions = get_permissions(owner_mode);
|
||||
|
||||
let group_mode = (mode & 0o070) >> 3;
|
||||
let group_permissions = get_permissions(group_mode);
|
||||
|
||||
let others_mode = mode & 0o007;
|
||||
let others_permissions = get_permissions(others_mode);
|
||||
|
||||
let user_id = nix::unistd::getuid();
|
||||
let groups_ids = getgroups()?;
|
||||
|
||||
if file_owner == user_id {
|
||||
Ok(owner_permissions)
|
||||
} else if groups_ids.contains(&file_group) {
|
||||
Ok(group_permissions)
|
||||
} else {
|
||||
Ok(others_permissions)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn getgroups() -> nix::Result<Vec<Gid>> {
|
||||
use libc::{c_int, gid_t};
|
||||
use std::ptr;
|
||||
let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
|
||||
let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize);
|
||||
loop {
|
||||
let ret = unsafe {
|
||||
libc::getgroups(
|
||||
groups.capacity() as c_int,
|
||||
groups.as_mut_ptr() as *mut gid_t,
|
||||
)
|
||||
};
|
||||
|
||||
return Errno::result(ret).map(|s| {
|
||||
unsafe { groups.set_len(s as usize) };
|
||||
groups
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn getgroups() -> nix::Result<Vec<Gid>> {
|
||||
nix::unistd::getgroups()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn os_access(path: PyStringRef, mode: u8, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
let path = path.as_str();
|
||||
|
||||
let flags = AccessFlags::from_bits(mode).ok_or_else(|| {
|
||||
vm.new_value_error(
|
||||
"One of the flags is wrong, there are only 4 possibilities F_OK, R_OK, W_OK and X_OK"
|
||||
.to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let metadata = fs::metadata(path);
|
||||
|
||||
// if it's only checking for F_OK
|
||||
if flags == AccessFlags::F_OK {
|
||||
return Ok(metadata.is_ok());
|
||||
}
|
||||
|
||||
let metadata = metadata.map_err(|err| convert_io_error(vm, err))?;
|
||||
|
||||
let user_id = metadata.uid();
|
||||
let group_id = metadata.gid();
|
||||
let mode = metadata.mode();
|
||||
|
||||
let perm = get_right_permission(mode, Uid::from_raw(user_id), Gid::from_raw(group_id))
|
||||
.map_err(|err| convert_nix_error(vm, err))?;
|
||||
|
||||
let r_ok = !flags.contains(AccessFlags::R_OK) || perm.is_readable;
|
||||
let w_ok = !flags.contains(AccessFlags::W_OK) || perm.is_writable;
|
||||
let x_ok = !flags.contains(AccessFlags::X_OK) || perm.is_executable;
|
||||
|
||||
Ok(r_ok && w_ok && x_ok)
|
||||
}
|
||||
|
||||
fn os_error(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(
|
||||
vm,
|
||||
@@ -748,6 +862,28 @@ fn os_chdir(path: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
env::set_current_dir(&path.value).map_err(|err| convert_io_error(vm, err))
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn os_chmod(
|
||||
path: PyStringRef,
|
||||
dir_fd: DirFd,
|
||||
mode: u32,
|
||||
follow_symlinks: FollowSymlinks,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let path = make_path(vm, path, &dir_fd);
|
||||
let metadata = if follow_symlinks.follow_symlinks {
|
||||
fs::metadata(&path.value)
|
||||
} else {
|
||||
fs::symlink_metadata(&path.value)
|
||||
};
|
||||
let meta = metadata.map_err(|err| convert_io_error(vm, err))?;
|
||||
let mut permissions = meta.permissions();
|
||||
permissions.set_mode(mode);
|
||||
fs::set_permissions(&path.value, permissions).map_err(|err| convert_io_error(vm, err))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn os_fspath(path: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if objtype::issubclass(&path.class(), &vm.ctx.str_type())
|
||||
|| objtype::issubclass(&path.class(), &vm.ctx.bytes_type())
|
||||
@@ -960,12 +1096,11 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
}
|
||||
}
|
||||
}
|
||||
let support_funcs = vec![
|
||||
let mut support_funcs = vec![
|
||||
SupportFunc::new(vm, "open", os_open, None, Some(false), None),
|
||||
// access Some Some None
|
||||
SupportFunc::new(vm, "chdir", os_chdir, Some(false), None, None),
|
||||
// chflags Some, None Some
|
||||
// chmod Some Some Some
|
||||
// chown Some Some Some
|
||||
// chroot Some None None
|
||||
SupportFunc::new(vm, "listdir", os_listdir, Some(false), None, None),
|
||||
@@ -985,6 +1120,15 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
SupportFunc::new(vm, "unlink", os_remove, Some(false), Some(false), None),
|
||||
// utime Some Some Some
|
||||
];
|
||||
#[cfg(unix)]
|
||||
support_funcs.extend(vec![SupportFunc::new(
|
||||
vm,
|
||||
"chmod",
|
||||
os_chmod,
|
||||
Some(false),
|
||||
Some(false),
|
||||
Some(false),
|
||||
)]);
|
||||
let supports_fd = PySet::default().into_ref(vm);
|
||||
let supports_dir_fd = PySet::default().into_ref(vm);
|
||||
let supports_follow_symlinks = PySet::default().into_ref(vm);
|
||||
@@ -1014,10 +1158,10 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"O_APPEND" => ctx.new_int(FileCreationFlags::O_APPEND.bits()),
|
||||
"O_EXCL" => ctx.new_int(FileCreationFlags::O_EXCL.bits()),
|
||||
"O_CREAT" => ctx.new_int(FileCreationFlags::O_CREAT.bits()),
|
||||
"F_OK" => ctx.new_int(0),
|
||||
"R_OK" => ctx.new_int(4),
|
||||
"W_OK" => ctx.new_int(2),
|
||||
"X_OK" => ctx.new_int(1),
|
||||
"F_OK" => ctx.new_int(AccessFlags::F_OK.bits()),
|
||||
"R_OK" => ctx.new_int(AccessFlags::R_OK.bits()),
|
||||
"W_OK" => ctx.new_int(AccessFlags::W_OK.bits()),
|
||||
"X_OK" => ctx.new_int(AccessFlags::X_OK.bits()),
|
||||
"getpid" => ctx.new_rustfunc(os_getpid),
|
||||
"cpu_count" => ctx.new_rustfunc(os_cpu_count)
|
||||
});
|
||||
@@ -1068,6 +1212,8 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) ->
|
||||
"setgid" => ctx.new_rustfunc(os_setgid),
|
||||
"setpgid" => ctx.new_rustfunc(os_setpgid),
|
||||
"setuid" => ctx.new_rustfunc(os_setuid),
|
||||
"access" => ctx.new_rustfunc(os_access),
|
||||
"chmod" => ctx.new_rustfunc(os_chmod)
|
||||
});
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
/// See also:
|
||||
/// https://docs.python.org/3/library/time.html
|
||||
use std::fmt;
|
||||
use std::ops::Range;
|
||||
use std::thread;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::obj::objint::PyIntRef;
|
||||
use crate::obj::objint::PyInt;
|
||||
use crate::obj::objsequence::get_sequence_index;
|
||||
use crate::obj::objsequence::PySliceableSequence;
|
||||
use crate::obj::objslice::PySlice;
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::obj::{objfloat, objint, objtype};
|
||||
use crate::pyobject::{PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::pyobject::{PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
use num_traits::cast::ToPrimitive;
|
||||
@@ -85,13 +88,15 @@ fn time_gmtime(secs: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult<
|
||||
OptionalArg::Present(secs) => pyobj_to_naive_date_time(&secs, vm)?.unwrap_or(default),
|
||||
OptionalArg::Missing => default,
|
||||
};
|
||||
let value = PyStructTime::new(instant);
|
||||
let value = PyStructTime::new(instant, 0);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn time_localtime(secs: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult<PyStructTime> {
|
||||
let instant = optional_or_localtime(secs, vm)?;
|
||||
let value = PyStructTime::new(instant);
|
||||
// TODO: isdst flag must be valid value here
|
||||
// https://docs.python.org/3/library/time.html#time.localtime
|
||||
let value = PyStructTime::new(instant, -1);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
@@ -157,13 +162,14 @@ fn time_strptime(
|
||||
};
|
||||
let instant = NaiveDateTime::parse_from_str(&string.value, &format)
|
||||
.map_err(|e| vm.new_value_error(format!("Parse error: {:?}", e)))?;
|
||||
let struct_time = PyStructTime::new(instant);
|
||||
let struct_time = PyStructTime::new(instant, -1);
|
||||
Ok(struct_time)
|
||||
}
|
||||
|
||||
#[pyclass(name = "struct_time")]
|
||||
struct PyStructTime {
|
||||
tm: NaiveDateTime,
|
||||
isdst: i32,
|
||||
}
|
||||
|
||||
type PyStructTimeRef = PyRef<PyStructTime>;
|
||||
@@ -182,20 +188,19 @@ impl PyValue for PyStructTime {
|
||||
|
||||
#[pyimpl]
|
||||
impl PyStructTime {
|
||||
fn new(tm: NaiveDateTime) -> Self {
|
||||
PyStructTime { tm }
|
||||
fn new(tm: NaiveDateTime, isdst: i32) -> Self {
|
||||
PyStructTime { tm, isdst }
|
||||
}
|
||||
|
||||
#[pymethod(name = "__repr__")]
|
||||
fn repr(&self, _vm: &VirtualMachine) -> String {
|
||||
// TODO: extract year day and isdst somehow..
|
||||
format!(
|
||||
"time.struct_time(tm_year={}, tm_mon={}, tm_mday={}, tm_hour={}, tm_min={}, tm_sec={}, tm_wday={}, tm_yday={})",
|
||||
self.tm.date().year(), self.tm.date().month(), self.tm.date().day(),
|
||||
self.tm.time().hour(), self.tm.time().minute(), self.tm.time().second(),
|
||||
self.tm.date().weekday().num_days_from_monday(),
|
||||
self.tm.date().ordinal()
|
||||
)
|
||||
"time.struct_time(tm_year={}, tm_mon={}, tm_mday={}, tm_hour={}, tm_min={}, tm_sec={}, tm_wday={}, tm_yday={}, tm_isdst={})",
|
||||
self._year(), self._mon(), self._mday(),
|
||||
self._hour(), self._min(), self._sec(),
|
||||
self._wday(), self._yday(), self._isdst(),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_date_time(&self) -> NaiveDateTime {
|
||||
@@ -204,65 +209,182 @@ impl PyStructTime {
|
||||
|
||||
#[pymethod(name = "__len__")]
|
||||
fn len(&self, _vm: &VirtualMachine) -> usize {
|
||||
8
|
||||
9
|
||||
}
|
||||
|
||||
#[pymethod(name = "__getitem__")]
|
||||
fn getitem(&self, needle: PyIntRef, vm: &VirtualMachine) -> PyResult {
|
||||
let index = get_sequence_index(vm, &needle, 8)?;
|
||||
match index {
|
||||
0 => Ok(vm.ctx.new_int(self.tm.date().year())),
|
||||
1 => Ok(vm.ctx.new_int(self.tm.date().month())),
|
||||
2 => Ok(vm.ctx.new_int(self.tm.date().day())),
|
||||
3 => Ok(vm.ctx.new_int(self.tm.time().hour())),
|
||||
4 => Ok(vm.ctx.new_int(self.tm.time().minute())),
|
||||
5 => Ok(vm.ctx.new_int(self.tm.time().second())),
|
||||
6 => Ok(vm
|
||||
.ctx
|
||||
.new_int(self.tm.date().weekday().num_days_from_monday())),
|
||||
7 => Ok(vm.ctx.new_int(self.tm.date().ordinal())),
|
||||
_ => unreachable!(),
|
||||
fn getitem(&self, subscript: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if subscript.payload::<PyInt>().is_some() {
|
||||
let needle = subscript.downcast().unwrap();
|
||||
let index = get_sequence_index(vm, &needle, 9)?;
|
||||
let tm_fn = TM_FUNCTIONS[index];
|
||||
Ok(vm.new_int(tm_fn(self)))
|
||||
} else if subscript.payload::<PySlice>().is_some() {
|
||||
let values = self.get_slice_items(vm, &subscript)?;
|
||||
let objs = values.iter().map(|v| vm.new_int(*v));
|
||||
Ok(vm.ctx.new_tuple(objs.collect()))
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"TypeError: tuple indices must be integers or slices, {}",
|
||||
subscript.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _year(&self) -> i32 {
|
||||
self.tm.date().year()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _mon(&self) -> i32 {
|
||||
self.tm.date().month() as i32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _mday(&self) -> i32 {
|
||||
self.tm.date().day() as i32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _hour(&self) -> i32 {
|
||||
self.tm.time().hour() as i32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _min(&self) -> i32 {
|
||||
self.tm.time().minute() as i32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _sec(&self) -> i32 {
|
||||
self.tm.time().second() as i32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _wday(&self) -> i32 {
|
||||
self.tm.date().weekday().num_days_from_monday() as i32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _yday(&self) -> i32 {
|
||||
self.tm.date().ordinal() as i32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _isdst(&self) -> i32 {
|
||||
self.isdst
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_year")]
|
||||
fn tm_year(&self, _vm: &VirtualMachine) -> i32 {
|
||||
self.tm.date().year()
|
||||
self._year()
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_mon")]
|
||||
fn tm_mon(&self, _vm: &VirtualMachine) -> u32 {
|
||||
self.tm.date().month()
|
||||
self._mon() as u32
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_mday")]
|
||||
fn tm_mday(&self, _vm: &VirtualMachine) -> u32 {
|
||||
self.tm.date().day()
|
||||
self._mday() as u32
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_hour")]
|
||||
fn tm_hour(&self, _vm: &VirtualMachine) -> u32 {
|
||||
self.tm.time().hour()
|
||||
self._hour() as u32
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_min")]
|
||||
fn tm_min(&self, _vm: &VirtualMachine) -> u32 {
|
||||
self.tm.time().minute()
|
||||
self._min() as u32
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_sec")]
|
||||
fn tm_sec(&self, _vm: &VirtualMachine) -> u32 {
|
||||
self.tm.time().second()
|
||||
self._sec() as u32
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_wday")]
|
||||
fn tm_wday(&self, _vm: &VirtualMachine) -> u32 {
|
||||
self.tm.date().weekday().num_days_from_monday()
|
||||
self._wday() as u32
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_yday")]
|
||||
fn tm_yday(&self, _vm: &VirtualMachine) -> u32 {
|
||||
self.tm.date().ordinal()
|
||||
self._yday() as u32
|
||||
}
|
||||
|
||||
#[pyproperty(name = "tm_isdst")]
|
||||
fn tm_isdst(&self, _vm: &VirtualMachine) -> i32 {
|
||||
self._isdst()
|
||||
}
|
||||
}
|
||||
|
||||
type TmFunction = fn(&PyStructTime) -> i32;
|
||||
const TM_FUNCTIONS: [TmFunction; 9] = [
|
||||
PyStructTime::_year,
|
||||
PyStructTime::_mon,
|
||||
PyStructTime::_mday,
|
||||
PyStructTime::_hour,
|
||||
PyStructTime::_min,
|
||||
PyStructTime::_sec,
|
||||
PyStructTime::_wday,
|
||||
PyStructTime::_yday,
|
||||
PyStructTime::_isdst,
|
||||
];
|
||||
|
||||
impl PySliceableSequence for PyStructTime {
|
||||
type Sliced = Vec<i32>;
|
||||
|
||||
fn do_slice(&self, range: Range<usize>) -> Self::Sliced {
|
||||
if let Some(fs) = TM_FUNCTIONS.get(range) {
|
||||
fs.iter().map(|f| f(self)).collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn do_slice_reverse(&self, range: Range<usize>) -> Self::Sliced {
|
||||
if let Some(fs) = TM_FUNCTIONS.get(range) {
|
||||
fs.iter().rev().map(|f| f(self)).collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn do_stepped_slice(&self, range: Range<usize>, step: usize) -> Self::Sliced {
|
||||
if let Some(fs) = TM_FUNCTIONS.get(range) {
|
||||
fs.iter().cloned().step_by(step).map(|f| f(self)).collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn do_stepped_slice_reverse(&self, range: Range<usize>, step: usize) -> Self::Sliced {
|
||||
if let Some(fs) = TM_FUNCTIONS.get(range) {
|
||||
fs.iter()
|
||||
.rev()
|
||||
.cloned()
|
||||
.step_by(step)
|
||||
.map(|f| f(self))
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn empty() -> Self::Sliced {
|
||||
panic!("struct_time is not empty");
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
TM_FUNCTIONS.len()
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ fn zlib_compress(
|
||||
.unwrap_or(libz::Z_DEFAULT_COMPRESSION);
|
||||
|
||||
let compression = match level {
|
||||
valid_level @ libz::Z_NO_COMPRESSION...libz::Z_BEST_COMPRESSION => {
|
||||
valid_level @ libz::Z_NO_COMPRESSION..=libz::Z_BEST_COMPRESSION => {
|
||||
Compression::new(valid_level as u32)
|
||||
}
|
||||
libz::Z_DEFAULT_COMPRESSION => Compression::default(),
|
||||
|
||||
18
vm/src/vm.rs
18
vm/src/vm.rs
@@ -11,7 +11,7 @@ use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
use crate::builtins;
|
||||
use crate::builtins::{self, to_ascii};
|
||||
use crate::bytecode;
|
||||
use crate::frame::{ExecutionResult, Frame, FrameRef};
|
||||
use crate::frozen;
|
||||
@@ -445,6 +445,13 @@ impl VirtualMachine {
|
||||
TryFromObject::try_from_object(self, repr)
|
||||
}
|
||||
|
||||
pub fn to_ascii(&self, obj: &PyObjectRef) -> PyResult {
|
||||
let repr = self.call_method(obj, "__repr__", vec![])?;
|
||||
let repr: PyStringRef = TryFromObject::try_from_object(self, repr)?;
|
||||
let ascii = to_ascii(&repr.value);
|
||||
Ok(self.new_str(ascii))
|
||||
}
|
||||
|
||||
pub fn import(&self, module: &str, from_list: &PyObjectRef, level: usize) -> PyResult {
|
||||
// if the import inputs seem weird, e.g a package import or something, rather than just
|
||||
// a straight `import ident`
|
||||
@@ -452,14 +459,13 @@ impl VirtualMachine {
|
||||
|| level != 0
|
||||
|| objbool::boolval(self, from_list.clone()).unwrap_or(true);
|
||||
|
||||
let module = self.new_str(module.to_owned());
|
||||
|
||||
let cached_module = if weird {
|
||||
None
|
||||
} else {
|
||||
let sys_modules = self.get_attribute(self.sys_module.clone(), "modules")?;
|
||||
sys_modules.get_item(module.clone(), self).ok()
|
||||
sys_modules.get_item(module, self).ok()
|
||||
};
|
||||
|
||||
match cached_module {
|
||||
Some(module) => Ok(module),
|
||||
None => {
|
||||
@@ -478,7 +484,7 @@ impl VirtualMachine {
|
||||
self.invoke(
|
||||
&import_func,
|
||||
vec![
|
||||
module,
|
||||
self.new_str(module.to_owned()),
|
||||
globals,
|
||||
locals,
|
||||
from_list.clone(),
|
||||
@@ -936,7 +942,7 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
let attr = if let Some(ref dict) = obj.dict {
|
||||
dict.get_item_option(name_str.clone(), self)?
|
||||
dict.get_item_option(&name_str.value, self)?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user