Merge branch 'master' into wasm-fetch-builtin

This commit is contained in:
coolreader18 committed 2019-02-23 12:28:17 -06:00
commit 5a472e46aa
110 files changed
+1970 -1078

No files matched your search

+18
View File
@@ -32,6 +32,7 @@ matrix:
env:
- TRAVIS_RUST_VERSION=stable
- REGULAR_TEST=false
- CODE_COVERAGE=false
script: tests/.travis-runner.sh
- language: python
python: 3.6
@@ -45,6 +46,7 @@ matrix:
env:
- TRAVIS_RUST_VERSION=beta
- REGULAR_TEST=false
- CODE_COVERAGE=false
script: tests/.travis-runner.sh
- name: rustfmt
language: rust
@@ -97,6 +99,22 @@ matrix:
- cargo clippy
env:
- REGULAR_TEST=true
- name: Code Coverage
language: python
python: 3.6
cache:
pip: true
# Because we're using the Python Travis environment, we can't use
# the built-in cargo cacher
directories:
- /home/travis/.cargo
- target
script:
- tests/.travis-runner.sh
env:
- TRAVIS_RUST_VERSION=nightly
- REGULAR_TEST=false
- CODE_COVERAGE=true
allow_failures:
- rust: nightly
env: REGULAR_TEST=true
+1
View File
@@ -2,6 +2,7 @@
name = "rustpython"
version = "0.0.1"
authors = ["Windel Bouwman", "Shing Lyu <shing.lyu@gmail.com>"]
edition = "2018"
[workspace]
members = [".", "vm", "wasm/lib", "parser"]
+17 -5
View File
@@ -3,6 +3,8 @@
A Python-3 (CPython >= 3.5.0) Interpreter written in Rust :snake: :scream: :metal:.
[![Build Status](https://travis-ci.org/RustPython/RustPython.svg?branch=master)](https://travis-ci.org/RustPython/RustPython)
[![Build Status](https://dev.azure.com/ryan0463/ryan/_apis/build/status/RustPython.RustPython?branchName=master)](https://dev.azure.com/ryan0463/ryan/_build/latest?definitionId=1&branchName=master)
[![codecov](https://codecov.io/gh/RustPython/RustPython/branch/master/graph/badge.svg)](https://codecov.io/gh/RustPython/RustPython)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
[![Contributors](https://img.shields.io/github/contributors/RustPython/RustPython.svg)](https://github.com/RustPython/RustPython/graphs/contributors)
[![Gitter](https://badges.gitter.im/RustPython/Lobby.svg)](https://gitter.im/rustpython/Lobby)
@@ -25,6 +27,14 @@ Or use the interactive shell:
>>>>> 2+2
4
# Disclaimer
RustPython is in a development phase and should not be used in production or a fault intolerant setting.
Our current build supports only a subset of Python syntax.
Contribution is also more than welcome! See our contribution section for more information on this.
# Goals
- Full Python-3 environment entirely in Rust (not CPython bindings)
@@ -32,7 +42,7 @@ Or use the interactive shell:
# Documentation
Currently the project is in an early phase, and so is the documentation.
Currently along with other areas of the project, documentation is still in an early phase.
You can read the [online documentation](https://rustpython.github.io/website/rustpython/index.html) for the latest code on master.
@@ -45,7 +55,7 @@ $ cargo doc --no-deps --all # Excluding all dependencies
Documentation HTML files can then be found in the `target/doc` directory.
If you wish to update the online documentation. Push directly to the `release` branch (or ask a maintainer to do so), this will trigger a Travis build that updates the documentation and WebAssembly demo page.
If you wish to update the online documentation, push directly to the `release` branch (or ask a maintainer to do so). This will trigger a Travis build that updates the documentation and WebAssembly demo page.
# Code organization
@@ -62,12 +72,14 @@ If you wish to update the online documentation. Push directly to the `release` b
# Contributing
To start contributing, there are a lot of things that need to be done.
Contributions are more than welcome, and in many cases we are happy to guide contributors through PRs or on gitter.
With that in mind, please note this project is maintained by volunteers, some of the best ways to get started are below:
Most tasks are listed in the [issue tracker](https://github.com/RustPython/RustPython/issues).
Check issues labeled with `good first issue` if you wish to start coding.
Another approach is to checkout the sourcecode: builtin functions and object methods are often the simplest
Another approach is to checkout the source code: builtin functions and object methods are often the simplest
and easiest way to contribute.
You can also simply run
@@ -85,7 +97,7 @@ $ pipenv install
$ pipenv run pytest -v
```
There also are some unittests, you can run those will cargo:
There also are some unit tests, you can run those will cargo:
```shell
$ cargo test --all
+56
View File
@@ -0,0 +1,56 @@
trigger:
- master
jobs:
- job: 'Test'
pool:
vmImage: 'vs2017-win2016'
strategy:
matrix:
Python37:
python.version: '3.7'
maxParallel: 10
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
architecture: 'x64'
- script: |
"C:\Program Files\Git\mingw64\bin\curl.exe" -sSf -o rustup-init.exe https://win.rustup.rs/
.\rustup-init.exe -y
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
rustc -V
cargo -V
displayName: 'Installing Rust'
- script: |
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
cargo build --verbose --all
displayName: 'Build'
- script: |
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
cargo test --verbose --all
displayName: 'Run tests'
- script: |
pip install pipenv
pushd tests
pipenv install
popd
displayName: 'Install pipenv and python packages'
- script: |
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
cargo build --verbose --release
displayName: 'Build release'
- script: |
set PATH=%PATH%;%USERPROFILE%\.cargo\bin
pushd tests
pipenv run pytest
popd
displayName: 'Run snippet tests'
+1
View File
@@ -3,6 +3,7 @@ name = "rustpython_parser"
version = "0.0.1"
authors = [ "Shing Lyu", "Windel Bouwman" ]
build = "build.rs"
edition = "2018"
[build-dependencies]
lalrpop="0.15.1"
+1 -1
View File
@@ -1,4 +1,4 @@
extern crate lalrpop;
use lalrpop;
fn main() {
lalrpop::process_root().unwrap();
+44
View File
@@ -219,6 +219,50 @@ pub enum Expression {
None,
}
impl Expression {
/// Returns a short name for the node suitable for use in error messages.
pub fn name(&self) -> &'static str {
use self::Expression::*;
use self::StringGroup::*;
match self {
BoolOp { .. } | Binop { .. } | Unop { .. } => "operator",
Subscript { .. } => "subscript",
Yield { .. } | YieldFrom { .. } => "yield expression",
Compare { .. } => "comparison",
Attribute { .. } => "attribute",
Call { .. } => "function call",
Number { .. }
| String {
value: Constant { .. },
}
| Bytes { .. } => "literal",
List { .. } => "list",
Tuple { .. } => "tuple",
Dict { .. } => "dict display",
Set { .. } => "set display",
Comprehension { kind, .. } => match **kind {
ComprehensionKind::List { .. } => "list comprehension",
ComprehensionKind::Dict { .. } => "dict comprehension",
ComprehensionKind::Set { .. } => "set comprehension",
ComprehensionKind::GeneratorExpression { .. } => "generator expression",
},
Starred { .. } => "starred",
Slice { .. } => "slice",
String {
value: Joined { .. },
}
| String {
value: FormattedValue { .. },
} => "f-string expression",
Identifier { .. } => "named expression",
Lambda { .. } => "lambda",
IfExpression { .. } => "conditional expression",
True | False | None => "keyword",
}
}
}
/*
* In cpython this is called arguments, but we choose parameters to
* distinguish between function parameters and actual call arguments.
+2 -2
View File
@@ -3,8 +3,8 @@
extern crate lalrpop_util;
use self::lalrpop_util::ParseError as InnerError;
use lexer::{LexicalError, Location};
use token::Tok;
use crate::lexer::{LexicalError, Location};
use crate::token::Tok;
use std::error::Error;
use std::fmt;
+7 -7
View File
@@ -541,7 +541,7 @@ where
fn is_char(&self) -> bool {
match self.chr0 {
Some('a'...'z') | Some('A'...'Z') | Some('_') | Some('0'...'9') => true,
Some('a'..='z') | Some('A'..='Z') | Some('_') | Some('0'..='9') => true,
_ => false,
}
}
@@ -549,19 +549,19 @@ where
fn is_number(&self, radix: u32) -> bool {
match radix {
2 => match self.chr0 {
Some('0'...'1') => true,
Some('0'..='1') => true,
_ => false,
},
8 => match self.chr0 {
Some('0'...'7') => true,
Some('0'..='7') => true,
_ => false,
},
10 => match self.chr0 {
Some('0'...'9') => true,
Some('0'..='9') => true,
_ => false,
},
16 => match self.chr0 {
Some('0'...'9') | Some('a'...'f') | Some('A'...'F') => true,
Some('0'..='9') | Some('a'..='f') | Some('A'..='F') => true,
_ => false,
},
x => unimplemented!("Radix not implemented: {}", x),
@@ -686,8 +686,8 @@ where
}
match self.chr0 {
Some('0'...'9') => return Some(self.lex_number()),
Some('_') | Some('a'...'z') | Some('A'...'Z') => return Some(self.lex_identifier()),
Some('0'..='9') => return Some(self.lex_number()),
Some('_') | Some('a'..='z') | Some('A'..='Z') => return Some(self.lex_identifier()),
Some('#') => {
self.lex_comment();
continue;
-3
View File
@@ -1,9 +1,6 @@
#[macro_use]
extern crate log;
extern crate num_bigint;
extern crate num_traits;
pub mod ast;
pub mod error;
pub mod lexer;
+5 -7
View File
@@ -1,12 +1,10 @@
extern crate lalrpop_util;
use std::iter;
use super::ast;
use super::error::ParseError;
use super::lexer;
use super::python;
use super::token;
use crate::ast;
use crate::error::ParseError;
use crate::lexer;
use crate::python;
use crate::token;
/*
* Parse python code.
+13 -4
View File
@@ -613,17 +613,26 @@ ClassDef: ast::LocatedStatement = {
},
};
Path: ast::Expression = {
<n:Identifier> => ast::Expression::Identifier { name: n },
<p:Path> "." <n:name> => {
ast::Expression::Attribute {
value: Box::new(p),
name: n,
}
},
};
// Decorators:
Decorator: ast::Expression = {
"@" <n:DottedName> <a: ("(" ArgumentList ")")?> "\n" => {
let name = ast::Expression::Identifier { name: n };
"@" <p:Path> <a: ("(" ArgumentList ")")?> "\n" => {
match a {
Some((_, args, _)) => ast::Expression::Call {
function: Box::new(name),
function: Box::new(p),
args: args.0,
keywords: args.1,
},
None => name,
None => p,
}
},
};
+1
View File
@@ -2,6 +2,7 @@
name = "py_code_object"
version = "0.1.0"
authors = ["Shing Lyu <shing.lyu@gmail.com>"]
edition = "2018"
[dependencies]
log = "0.3"
@@ -2,6 +2,7 @@
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" }
+4 -7
View File
@@ -19,10 +19,7 @@ use rustpython_vm::{
util, VirtualMachine,
};
use rustyline::{error::ReadlineError, Editor};
use std::{
error::Error,
path::{Path, PathBuf},
};
use std::path::{Path, PathBuf};
fn main() {
env_logger::init();
@@ -81,7 +78,7 @@ fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: String) -> Py
)
.map_err(|err| {
let syntax_error = vm.context().exceptions.syntax_error.clone();
vm.new_exception(syntax_error, err.description().to_string())
vm.new_exception(syntax_error, err.to_string())
})?;
// trace!("Code object: {:?}", code_obj.borrow());
let builtins = vm.get_builtin_scope();
@@ -151,12 +148,12 @@ fn shell_exec(
}
}
#[cfg(not(target_family = "unix"))]
#[cfg(not(unix))]
fn get_history_path() -> PathBuf {
PathBuf::from(".repl_history.txt")
}
#[cfg(target_family = "unix")]
#[cfg(unix)]
fn get_history_path() -> PathBuf {
//work around for windows dependent builds. The xdg crate is unix specific
//so access to the BaseDirectories struct breaks builds on python.
+26 -1
View File
@@ -10,7 +10,32 @@ pip install pipenv
(cd tests; pipenv install)
# Build outside of the test runner
cargo build --verbose --release
if [ $CODE_COVERAGE = "true" ]
then
find . -name '*.gcda' -delete
export CARGO_INCREMENTAL=0
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads"
cargo build --verbose
else
cargo build --verbose --release
fi
# Run the tests
(cd tests; pipenv run pytest)
if [ $CODE_COVERAGE = "true" ]
then
cargo test --verbose --all
zip -0 ccov.zip `find . \( -name "rustpython*.gc*" \) -print`
# Install grcov
curl -L https://github.com/mozilla/grcov/releases/download/v0.4.1/grcov-linux-x86_64.tar.bz2 | tar jxf -
./grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore-dir "/*" -p "x" > lcov.info
# Install codecov.io reporter
curl -s https://codecov.io/bash -o codecov.sh
bash codecov.sh -f lcov.info
fi
+6
View File
@@ -38,3 +38,9 @@ assert b.real == 0
assert a.imag == 4
assert b.imag == 4
# int and complex addition
assert 1 + 1j == complex(1, 1)
assert 1j + 1 == complex(1, 1)
assert (1j + 1) + 3 == complex(4, 1)
assert 3 + (1j + 1) == complex(4, 1)
+4 -13
View File
@@ -1,17 +1,8 @@
from testutils import assert_raises
assert divmod(11, 3) == (3, 2)
assert divmod(8,11) == (0, 8)
assert divmod(0.873, 0.252) == (3.0, 0.11699999999999999)
try:
divmod(5, 0)
except ZeroDivisionError:
pass
else:
assert False, "Expected divmod by zero to throw ZeroDivisionError"
try:
divmod(5.0, 0.0)
except ZeroDivisionError:
pass
else:
assert False, "Expected divmod by zero to throw ZeroDivisionError"
assert_raises(ZeroDivisionError, lambda: divmod(5, 0), 'divmod by zero')
assert_raises(ZeroDivisionError, lambda: divmod(5.0, 0.0), 'divmod by zero')
+4 -12
View File
@@ -1,17 +1,9 @@
from testutils import assert_raises
assert format(5, "b") == "101"
try:
format(2, 3)
except TypeError:
pass
else:
assert False, "TypeError not raised when format is called with a number"
assert_raises(TypeError, lambda: format(2, 3), 'format called with number')
assert format({}) == "{}"
try:
format({}, 'b')
except TypeError:
pass
else:
assert False, "TypeError not raised when format_spec not empty for dict"
assert_raises(TypeError, lambda: format({}, 'b'), 'format_spec not empty for dict')
+3 -6
View File
@@ -1,9 +1,6 @@
from testutils import assert_raises
assert hex(16) == '0x10'
assert hex(-16) == '-0x10'
try:
hex({})
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with a dict"
assert_raises(TypeError, lambda: hex({}), 'ord() called with dict')
+6 -24
View File
@@ -1,3 +1,5 @@
from testutils import assert_raises
# simple values
assert max(0, 0) == 0
assert max(1, 0) == 1
@@ -14,32 +16,17 @@ assert max({
}) == "b"
assert max([1, 2], default=0) == 2
assert max([], default=0) == 0
try:
max([])
except ValueError:
pass
else:
assert False, "ValueError was not raised"
assert_raises(ValueError, lambda: max([]))
# key parameter
assert max(1, 2, -3, key=abs) == -3
assert max([1, 2, -3], key=abs) == -3
# no argument
try:
max()
except TypeError:
pass
else:
assert False, "TypeError was not raised"
assert_raises(TypeError, lambda: max())
# one non-iterable argument
try:
max(1)
except TypeError:
pass
else:
assert False, "TypeError was not raised"
assert_raises(TypeError, lambda: max(1))
# custom class
@@ -64,9 +51,4 @@ class MyNotComparable():
pass
try:
max(MyNotComparable(), MyNotComparable())
except TypeError:
pass
else:
assert False, "TypeError was not raised"
assert_raises(TypeError, lambda: max(MyNotComparable(), MyNotComparable()))
+7 -24
View File
@@ -1,3 +1,5 @@
from testutils import assert_raises
# simple values
assert min(0, 0) == 0
assert min(1, 0) == 0
@@ -14,32 +16,18 @@ assert min({
}) == "a"
assert min([1, 2], default=0) == 1
assert min([], default=0) == 0
try:
min([])
except ValueError:
pass
else:
assert False, "ValueError was not raised"
assert_raises(ValueError, lambda: min([]))
# key parameter
assert min(1, 2, -3, key=abs) == 1
assert min([1, 2, -3], key=abs) == 1
# no argument
try:
min()
except TypeError:
pass
else:
assert False, "TypeError was not raised"
assert_raises(TypeError, lambda: min())
# one non-iterable argument
try:
min(1)
except TypeError:
pass
else:
assert False, "TypeError was not raised"
assert_raises(TypeError, lambda: min(1))
# custom class
@@ -64,9 +52,4 @@ class MyNotComparable():
pass
try:
min(MyNotComparable(), MyNotComparable())
except TypeError:
pass
else:
assert False, "TypeError was not raised"
assert_raises(TypeError, lambda: min(MyNotComparable(), MyNotComparable()))
+3 -5
View File
@@ -1,8 +1,6 @@
from testutils import assert_raises
fd = open('README.md')
assert 'RustPython' in fd.read()
try:
open('DoesNotExist')
assert False
except FileNotFoundError:
pass
assert_raises(FileNotFoundError, lambda: open('DoesNotExist'))
+5 -19
View File
@@ -1,23 +1,9 @@
from testutils import assert_raises
assert ord("a") == 97
assert ord("é") == 233
assert ord("🤡") == 129313
try:
ord()
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with no argument"
try:
ord("")
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with an empty string"
try:
ord("ab")
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with more than one character"
assert_raises(TypeError, lambda: ord(), "ord() is called with no argument")
assert_raises(TypeError, lambda: ord(""), "ord() is called with an empty string")
assert_raises(TypeError, lambda: ord("ab"), "ord() is called with more than one character")
+5 -26
View File
@@ -1,20 +1,4 @@
def assert_raises(expr, exc_type):
"""
Helper function to assert `expr` raises an exception of type `exc_type`
Args:
expr: Callable
exec_type: Exception
Returns:
None
Raises:
Assertion error on failure
"""
try:
expr(None)
except exc_type:
assert True
else:
assert False
from testutils import assert_raises
assert range(2**63+1)[2**63] == 9223372036854775808
@@ -29,15 +13,10 @@ assert range(4, 10).index(6) == 2
assert range(4, 10, 2).index(6) == 1
assert range(10, 4, -2).index(8) == 1
# index raises value error on out of bounds
assert_raises(lambda _: range(10).index(-1), ValueError)
assert_raises(lambda _: range(10).index(10), ValueError)
# index raises value error if out of step
assert_raises(lambda _: range(4, 10, 2).index(5), ValueError)
# index raises value error if needle is not an int
assert_raises(lambda _: range(10).index('foo'), ValueError)
assert_raises(ValueError, lambda: range(10).index(-1), 'out of bounds')
assert_raises(ValueError, lambda: range(10).index(10), 'out of bounds')
assert_raises(ValueError, lambda: range(4, 10, 2).index(5), 'out of step')
assert_raises(ValueError, lambda: range(10).index('foo'), 'not an int')
# count tests
assert range(10).count(2) == 1
+2 -6
View File
@@ -1,3 +1,4 @@
from testutils import assert_raises
a = []
assert a[:] == []
@@ -18,12 +19,7 @@ assert b[-10:1] == [1]
assert b[0:0] == []
assert b[1:0] == []
try:
_ = b[::0]
except ValueError:
pass
else:
assert False, "Zero step slice should raise ValueError"
assert_raises(ValueError, lambda: b[::0], 'zero step slice')
assert b[::-1] == [2, 1]
assert b[1::-1] == [2, 1]
+38 -2
View File
@@ -18,14 +18,50 @@ assert not bytearray(b'abc1').isalpha()
assert bytearray(b'1234567890').isdigit()
assert not bytearray(b'12ab').isdigit()
assert bytearray(b'lower').islower()
l = bytearray(b'lower')
assert l.islower()
assert not l.isupper()
assert l.upper().isupper()
assert not bytearray(b'Super Friends').islower()
assert bytearray(b' \n\t').isspace()
assert not bytearray(b'\td\n').isspace()
assert bytearray(b'UPPER').isupper()
b = bytearray(b'UPPER')
assert b.isupper()
assert not b.islower()
assert b.lower().islower()
assert not bytearray(b'tuPpEr').isupper()
assert bytearray(b'Is Title Case').istitle()
assert not bytearray(b'is Not title casE').istitle()
a = bytearray(b'abcd')
a.clear()
assert len(a) == 0
try:
bytearray([400])
except ValueError:
pass
else:
assert False
b = bytearray(b'test')
assert len(b) == 4
b.pop()
assert len(b) == 3
c = bytearray([123, 255, 111])
assert len(c) == 3
c.pop()
assert len(c) == 2
c.pop()
c.pop()
try:
c.pop()
except IndexError:
pass
else:
assert False
+33
View File
@@ -0,0 +1,33 @@
# break from a nested for loop
def foo():
sum = 0
for i in range(10):
sum += i
for j in range(10):
sum += j
break
return sum
assert foo() == 45
# continue statement
def primes(limit):
"""Finds all the primes from 2 up to a given number using the Sieve of Eratosthenes."""
sieve = [False] * (limit + 1)
for i in range(2, limit + 1):
if sieve[i]:
continue
yield i
for j in range(2 * i, limit + 1, i):
sieve[j] = True
assert list(primes(1)) == []
assert list(primes(2)) == [2]
assert list(primes(10)) == [2, 3, 5, 7]
assert list(primes(13)) == [2, 3, 5, 7, 11, 13]
+12
View File
@@ -14,3 +14,15 @@ c = add(10, 3)
assert c == 14
def f(func): return lambda: 42
class A: pass
a = A()
a.a = A()
a.a.x = f
@a.a.x
def func():
pass
assert func() == 42
+3
View File
@@ -14,3 +14,6 @@ c['d'] = 3
c['a']['g'] = 2
assert dict_eq(a, {'g': 2})
assert dict_eq(b, {'a': a, 'd': 9})
a.clear()
assert len(a) == 0
+10
View File
@@ -0,0 +1,10 @@
import dis
dis.disassemble(compile("5 + x + 5 or 2", "", "eval"))
print("\n")
dis.disassemble(compile("def f(x):\n return 1", "", "exec"))
print("\n")
dis.disassemble(compile("if a:\n 1 or 2\nelif x == 'hello':\n 3\nelse:\n 4", "", "exec"))
print("\n")
dis.disassemble(compile("f(x=1, y=2)", "", "eval"))
print("\n")
+9 -53
View File
@@ -1,55 +1,11 @@
try:
5 / 0
except ZeroDivisionError:
pass
else:
assert False, 'Expected ZeroDivisionError'
from testutils import assert_raises
try:
5 / -0.0
except ZeroDivisionError:
pass
else:
assert False, 'Expected ZeroDivisionError'
assert_raises(ZeroDivisionError, lambda: 5 / 0)
assert_raises(ZeroDivisionError, lambda: 5 / -0.0)
assert_raises(ZeroDivisionError, lambda: 5 / (2-2))
assert_raises(ZeroDivisionError, lambda: 5 % 0)
assert_raises(ZeroDivisionError, lambda: 5 // 0)
assert_raises(ZeroDivisionError, lambda: 5.3 // (-0.0))
assert_raises(ZeroDivisionError, lambda: divmod(5, 0))
try:
5 / (2-2)
except ZeroDivisionError:
pass
else:
assert False, 'Expected ZeroDivisionError'
try:
5 % 0
except ZeroDivisionError:
pass
else:
assert False, 'Expected ZeroDivisionError'
try:
5 // 0
except ZeroDivisionError:
pass
else:
assert False, 'Expected ZeroDivisionError'
try:
5.3 // (-0.0)
except ZeroDivisionError:
pass
else:
assert False, 'Expected ZeroDivisionError'
try:
divmod(5, 0)
except ZeroDivisionError:
pass
else:
assert False, 'Expected ZeroDivisionError'
try:
raise ZeroDivisionError('Is an ArithmeticError subclass?')
except ArithmeticError:
pass
else:
assert False, 'Expected ZeroDivisionError'
assert issubclass(ZeroDivisionError, ArithmeticError)
+4 -12
View File
@@ -1,3 +1,5 @@
from testutils import assert_raises
# 2.456984346552728
res = 10**500 / (4 * 10**499 + 7 * 10**497 + 3 * 10**494)
assert 2.456984 <= res <= 2.456985
@@ -8,20 +10,10 @@ assert 95.238095 <= res <= 95.238096
assert 10**500 / (2*10**(500-308)) == 5e307
assert 10**500 / (10**(500-308)) == 1e308
try:
10**500 / (10**(500-309))
except OverflowError:
pass
else:
assert False, 'Expected overflow on too big result'
assert_raises(OverflowError, lambda: 10**500 / (10**(500-309)), 'too big result')
# a bit more than f64::MAX = 1.7976931348623157e+308_f64
assert (2 * 10**308) / 2 == 1e308
# when dividing too big int by a float, the operation should fail
try:
(2 * 10**308) / 2.0
except OverflowError:
pass
else:
assert False, 'Expected overflow on division of a big int by a float'
assert_raises(OverflowError, lambda: (2 * 10**308) / 2.0, 'division of big int by float')
+3 -19
View File
@@ -1,22 +1,6 @@
import math
def assert_raises(expr, exc_type):
"""
Helper function to assert `expr` raises an exception of type `exc_type`
Args:
expr: Callable
exec_type: Exception
Returns:
None
Raises:
Assertion error on failure
"""
try:
expr(None)
except exc_type:
assert True
else:
assert False
from testutils import assert_raises
1 + 1.1
@@ -79,8 +63,8 @@ assert float('2.99e-23') == 2.99e-23
assert float(b'3.14') == 3.14
assert float(b'2.99e-23') == 2.99e-23
assert_raises(lambda _: float('foo'), ValueError)
assert_raises(lambda _: float(2**10000), OverflowError)
assert_raises(ValueError, lambda: float('foo'))
assert_raises(OverflowError, lambda: float(2**10000))
# check that magic methods are implemented for ints and floats
+26 -64
View File
@@ -1,21 +1,12 @@
from testutils import assert_raises
def no_args():
pass
no_args()
try:
no_args('one_arg')
except TypeError:
pass
else:
assert False, 'no TypeError raised: 1 arg to no_args'
try:
no_args(kw='should fail')
except TypeError:
pass
else:
assert False, 'no TypeError raised: kwarg to no_args'
assert_raises(TypeError, lambda: no_args('one_arg'), '1 arg to no_args')
assert_raises(TypeError, lambda: no_args(kw='should fail'), 'kwarg to no_args')
def one_arg(arg):
@@ -24,40 +15,20 @@ def one_arg(arg):
one_arg('one_arg')
assert "arg" == one_arg(arg="arg")
try:
one_arg()
except TypeError:
pass
else:
assert False, 'no TypeError raised: no args to one_arg'
assert_raises(TypeError, lambda: one_arg(), 'no args to one_arg')
assert_raises(TypeError,
lambda: one_arg(wrong_arg='wont work'),
'incorrect kwarg to one_arg')
assert_raises(TypeError,
lambda: one_arg('one_arg', 'two_arg'),
'two args to one_arg')
assert_raises(TypeError,
lambda: one_arg('one_arg', extra_arg='wont work'),
'no TypeError raised: extra kwarg to one_arg')
try:
one_arg(wrong_arg='wont work')
except TypeError:
pass
else:
assert False, 'no TypeError raised: incorrect kwarg to one_arg'
try:
one_arg('one_arg', 'two_arg')
except TypeError:
pass
else:
assert False, 'no TypeError raised: two args to one_arg'
try:
one_arg('one_arg', extra_arg='wont work')
except TypeError:
pass
else:
assert False, 'no TypeError raised: extra kwarg to one_arg'
try:
one_arg('one_arg', arg='duplicate')
except TypeError:
pass
else:
assert False, 'no TypeError raised: same pos and kwarg to one_arg'
assert_raises(TypeError,
lambda: one_arg('one_arg', arg='duplicate'),
'same pos and kwarg to one_arg')
def one_default_arg(arg="default"):
@@ -67,12 +38,9 @@ assert 'default' == one_default_arg()
assert 'arg' == one_default_arg('arg')
assert 'kwarg' == one_default_arg(arg='kwarg')
try:
one_default_arg('one_arg', 'two_arg')
except TypeError:
pass
else:
assert False, 'no TypeError raised: two args to one_default_arg'
assert_raises(TypeError,
lambda: one_default_arg('one_arg', 'two_arg'),
'two args to one_default_arg')
def one_normal_one_default_arg(pos, arg="default"):
@@ -81,19 +49,13 @@ def one_normal_one_default_arg(pos, arg="default"):
assert ('arg', 'default') == one_normal_one_default_arg('arg')
assert ('arg', 'arg2') == one_normal_one_default_arg('arg', 'arg2')
try:
one_normal_one_default_arg()
except TypeError:
pass
else:
assert False, 'no TypeError raised: no args to one_normal_one_default_arg'
assert_raises(TypeError,
lambda: one_normal_one_default_arg(),
'no args to one_normal_one_default_arg')
try:
one_normal_one_default_arg('one', 'two', 'three')
except TypeError:
pass
else:
assert False, 'no TypeError raised: three args to one_normal_one_default_arg'
assert_raises(TypeError,
lambda: one_normal_one_default_arg('one', 'two', 'three'),
'three args to one_normal_one_default_arg')
def two_pos(a, b):
+109
View File
@@ -0,0 +1,109 @@
class InPlace:
def __init__(self, val):
self.val = val
def __ipow__(self, other):
self.val **= other
return self
def __imul__(self, other):
self.val *= other
return self
def __imatmul__(self, other):
# I guess you could think of an int as a 1x1 matrix
self.val *= other
return self
def __itruediv__(self, other):
self.val /= other
return self
def __ifloordiv__(self, other):
self.val //= other
return self
def __imod__(self, other):
self.val %= other
return self
def __iadd__(self, other):
self.val += other
return self
def __isub__(self, other):
self.val -= other
return self
def __ilshift__(self, other):
self.val <<= other
return self
def __irshift__(self, other):
self.val >>= other
return self
def __iand__(self, other):
self.val &= other
return self
def __ixor__(self, other):
self.val ^= other
return self
def __ior__(self, other):
self.val |= other
return self
i = InPlace(2)
i **= 3
assert i.val == 8
i = InPlace(2)
i *= 2
assert i.val == 4
i = InPlace(2)
i @= 2
assert i.val == 4
i = InPlace(1)
i /= 2
assert i.val == 0.5
i = InPlace(1)
i //= 2
assert i.val == 0
i = InPlace(10)
i %= 3
assert i.val == 1
i = InPlace(1)
i += 1
assert i.val == 2
i = InPlace(2)
i -= 1
assert i.val == 1
i = InPlace(2)
i <<= 3
assert i.val == 16
i = InPlace(16)
i >>= 3
assert i.val == 2
i = InPlace(0b010101)
i &= 0b111000
assert i.val == 0b010000
i = InPlace(0b010101)
i ^= 0b111000
assert i.val == 0b101101
i = InPlace(0b010101)
i |= 0b111000
assert i.val == 0b111101
+5
View File
@@ -32,6 +32,11 @@ assert (2).__rmul__(1) == 2
assert (2).__truediv__(1) == 2.0
assert (2).__rtruediv__(1) == 0.5
# real/imag attributes
assert (1).real == 1
assert (1).imag == 0
assert (1).__eq__(1.0) == NotImplemented
assert (1).__ne__(1.0) == NotImplemented
assert (1).__gt__(1.0) == NotImplemented
+53 -24
View File
@@ -1,3 +1,5 @@
from testutils import assert_raises
x = [1, 2, 3]
assert x[0] == 1
assert x[1] == 2
@@ -16,12 +18,7 @@ assert x * 2 == [1, 2, 3, 1, 2, 3], "list __mul__ by 2 failed"
# index()
assert ['a', 'b', 'c'].index('b') == 1
assert [5, 6, 7].index(7) == 2
try:
['a', 'b', 'c'].index('z')
except ValueError:
pass
else:
assert False, "ValueError was not raised"
assert_raises(ValueError, lambda: ['a', 'b', 'c'].index('z'))
x = [[1,0,-3], 'a', 1]
y = [[3,2,1], 'z', 2]
@@ -33,12 +30,7 @@ assert x > y, "list __gt__ failed"
assert [1,2,'a'].pop() == 'a', "list pop failed"
try:
[].pop()
except IndexError:
pass
else:
assert False, "IndexError was not raised"
assert_raises(IndexError, lambda: [].pop())
recursive = []
recursive.append(recursive)
@@ -61,12 +53,7 @@ x = ['a', 'b', 'c']
x.insert(-100, 'z')
assert x == ['z', 'a', 'b', 'c']
try:
x.insert(100000000000000000000, 'z')
except OverflowError:
pass
else:
assert False, "OverflowError was not raised"
assert_raises(OverflowError, lambda: x.insert(100000000000000000000, 'z'))
x = [[], 2, {}]
y = x.copy()
@@ -82,9 +69,51 @@ a.remove(1)
assert len(a) == 2
assert not 1 in a
try:
a.remove(10)
except ValueError:
pass
else:
assert False, "Remove not exist element should raise ValueError"
assert_raises(ValueError, lambda: a.remove(10), 'Remove not exist element')
foo = bar = [1]
foo += [2]
assert (foo, bar) == ([1, 2], [1, 2])
x = [1]
x.append(x)
assert x in x
assert x.index(x) == 1
assert x.count(x) == 1
x.remove(x)
assert x not in x
class Foo(object):
def __eq__(self, x):
return False
foo = Foo()
foo1 = Foo()
x = [1, foo, 2, foo, []]
assert x == x
assert foo in x
assert 2 in x
assert x.index(foo) == 1
assert x.count(foo) == 2
assert x.index(2) == 2
assert [] in x
assert x.index([]) == 4
assert foo1 not in x
x.remove(foo)
assert x.index(foo) == 2
assert x.count(foo) == 1
x = []
x.append(x)
assert x == x
a = [1, 2, 3]
b = [1, 2, 3]
c = [a, b]
a.append(c)
b.append(c)
assert a == b
assert [foo] == [foo]
+4 -12
View File
@@ -1,3 +1,5 @@
from testutils import assert_raises
# test lists
assert 3 in [1, 2, 3]
assert 3 not in [1, 2]
@@ -19,12 +21,7 @@ assert b"5" <= b"5"
assert b"4" > b"2"
assert not b"1" >= b"2"
assert b"10" >= b"10"
try:
bytes() > 2
except TypeError:
pass
else:
assert False, "TypeError not raised"
assert_raises(TypeError, lambda: bytes() > 2)
# test tuple
assert 1 in (1, 2)
@@ -53,12 +50,7 @@ class MyNotContainingClass():
pass
try:
1 in MyNotContainingClass()
except TypeError:
pass
else:
assert False, "TypeError not raised"
assert_raises(TypeError, lambda: 1 in MyNotContainingClass())
class MyContainingClass():
+1 -1
View File
@@ -1,3 +1,3 @@
import os
assert os.name == 'posix'
assert os.name == 'posix' or os.name == 'nt'
+4 -13
View File
@@ -1,18 +1,9 @@
from testutils import assert_raises
print(2 + 3)
try:
print('test', end=4)
except TypeError:
pass
else:
assert False, 'Expected TypeError on wrong type passed to end'
try:
print('test', sep=['a'])
except TypeError:
pass
else:
assert False, 'Expected TypeError on wrong type passed to sep'
assert_raises(TypeError, lambda: print('test', end=4), 'wrong type passed to end')
assert_raises(TypeError, lambda: print('test', sep=['a']), 'wrong type passed to sep')
try:
print('test', end=None, sep=None, flush=None)
+70 -14
View File
@@ -1,3 +1,5 @@
from testutils import assert_raises, assertRaises
assert set([1,2]) == set([1,2])
assert not set([1,2,3]) == set([1,2])
@@ -69,22 +71,76 @@ assert set([1,2,3]).symmetric_difference(set([5,6])) == set([1,2,3,5,6])
assert set([1,2,3]) ^ set([4,5]) == set([1,2,3,4,5])
assert set([1,2,3]) ^ set([1,2,3,4,5]) == set([4,5])
try:
set([[]])
except TypeError:
pass
else:
assert False, "TypeError was not raised"
try:
set().add([])
except TypeError:
pass
else:
assert False, "TypeError was not raised"
assert_raises(TypeError, lambda: set([[]]))
assert_raises(TypeError, lambda: set().add([]))
a = set([1, 2, 3])
assert a.discard(1) is None
assert not 1 in a
assert a.discard(42) is None
a = set([1,2,3])
b = a.copy()
assert len(a) == 3
assert len(b) == 3
b.clear()
assert len(a) == 3
assert len(b) == 0
a = set([1,2])
b = a.pop()
assert b in [1,2]
c = a.pop()
assert (c in [1,2] and c != b)
assert_raises(KeyError, lambda: a.pop())
a = set([1,2,3])
a.update([3,4,5])
assert a == set([1,2,3,4,5])
assert_raises(TypeError, lambda: a.update(1))
a = set([1,2,3])
b = set()
for e in a:
assert e == 1 or e == 2 or e == 3
b.add(e)
assert a == b
a = set([1,2,3])
a |= set([3,4,5])
assert a == set([1,2,3,4,5])
with assertRaises(TypeError):
a |= 1
a = set([1,2,3])
a.intersection_update([2,3,4,5])
assert a == set([2,3])
assert_raises(TypeError, lambda: a.intersection_update(1))
a = set([1,2,3])
a &= set([2,3,4,5])
assert a == set([2,3])
with assertRaises(TypeError):
a &= 1
a = set([1,2,3])
a.difference_update([3,4,5])
assert a == set([1,2])
assert_raises(TypeError, lambda: a.difference_update(1))
a = set([1,2,3])
a -= set([3,4,5])
assert a == set([1,2])
with assertRaises(TypeError):
a -= 1
a = set([1,2,3])
a.symmetric_difference_update([3,4,5])
assert a == set([1,2,4,5])
assert_raises(TypeError, lambda: a.difference_update(1))
a = set([1,2,3])
a ^= set([3,4,5])
assert a == set([1,2,4,5])
with assertRaises(TypeError):
a ^= 1
+3 -5
View File
@@ -1,13 +1,11 @@
import os
from testutils import assert_raises
assert os.open('README.md', 0) > 0
try:
os.open('DOES_NOT_EXIST', 0)
assert False
except FileNotFoundError:
pass
assert_raises(FileNotFoundError, lambda: os.open('DOES_NOT_EXIST', 0))
assert os.O_RDONLY == 0
+7 -23
View File
@@ -1,20 +1,4 @@
def assert_raises(expr, exc_type):
"""
Helper function to assert `expr` raises an exception of type `exc_type`
Args:
expr: Callable
exec_type: Exception
Returns:
None
Raises:
Assertion error on failure
"""
try:
expr(None)
except exc_type:
assert True
else:
assert False
from testutils import assert_raises
#
# Tests
@@ -23,15 +7,15 @@ assert 8 >> 3 == 1
assert 8 << 3 == 64
# Left shift raises type error
assert_raises(lambda _: 1 << 0.1, TypeError)
assert_raises(lambda _: 1 << "abc", TypeError)
assert_raises(TypeError, lambda: 1 << 0.1)
assert_raises(TypeError, lambda: 1 << "abc")
# Right shift raises type error
assert_raises(lambda _: 1 >> 0.1, TypeError)
assert_raises(lambda _: 1 >> "abc", TypeError)
assert_raises(TypeError, lambda: 1 >> 0.1)
assert_raises(TypeError, lambda: 1 >> "abc")
# Left shift raises value error on negative
assert_raises(lambda _: 1 << -1, ValueError)
assert_raises(ValueError, lambda: 1 << -1)
# Right shift raises value error on negative
assert_raises(lambda _: 1 >> -1, ValueError)
assert_raises(ValueError, lambda: 1 >> -1)
+36
View File
@@ -0,0 +1,36 @@
def assert_raises(exc_type, expr, msg=None):
"""
Helper function to assert `expr` raises an exception of type `exc_type`.
Args:
expr: Callable
exec_type: Exception
Returns:
None
Raises:
Assertion error on failure
"""
try:
expr()
except exc_type:
pass
else:
failmsg = '{!s} was not raised'.format(exc_type.__name__)
if msg is not None:
failmsg += ': {!s}'.format(msg)
assert False, failmsg
class assertRaises:
def __init__(self, expected):
self.expected = expected
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
failmsg = '{!s} was not raised'.format(self.expected.__name_)
assert False, failmsg
if not issubclass(exc_type, self.expected):
return False
return True
+7
View File
@@ -27,3 +27,10 @@ assert repr(recursive) == "([(...)],)"
assert (None, "", 1).index(1) == 2
assert 1 in (None, "", 1)
class Foo(object):
def __eq__(self, x):
return False
foo = Foo()
assert (foo,) == (foo,)
+6 -2
View File
@@ -77,8 +77,12 @@ def run_via_rustpython(filename, test_type):
log_level = 'info' if test_type == _TestType.benchmark else 'trace'
env['RUST_LOG'] = '{},cargo=error,jobserver=error'.format(log_level)
env['RUST_BACKTRACE'] = '1'
subprocess.check_call(
['cargo', 'run', '--release', filename], env=env)
if env.get('CODE_COVERAGE', 'false') == 'true':
subprocess.check_call(
['cargo', 'run', filename], env=env)
else:
subprocess.check_call(
['cargo', 'run', '--release', filename], env=env)
def create_test_function(cls, filename, method, test_type):
+1
View File
@@ -2,6 +2,7 @@
name = "rustpython_vm"
version = "0.1.0"
authors = ["Shing Lyu <shing.lyu@gmail.com>"]
edition = "2018"
[dependencies]
bitflags = "1.0.4"
+99 -139
View File
@@ -4,26 +4,25 @@
// use std::ops::Deref;
use std::char;
use std::error::Error;
use std::io::{self, Write};
use super::compile;
use super::obj::objbool;
use super::obj::objdict;
use super::obj::objint;
use super::obj::objiter;
use super::obj::objstr;
use super::obj::objtype;
use crate::compile;
use crate::obj::objbool;
use crate::obj::objdict;
use crate::obj::objint;
use crate::obj::objiter;
use crate::obj::objstr;
use crate::obj::objtype;
use super::pyobject::{
use crate::pyobject::{
AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef,
PyResult, Scope, TypeProtocol,
};
#[cfg(not(target_arch = "wasm32"))]
use super::stdlib::io::io_open;
use crate::stdlib::io::io_open;
use super::vm::VirtualMachine;
use crate::vm::VirtualMachine;
use num_traits::{Signed, ToPrimitive};
fn get_locals(vm: &mut VirtualMachine) -> PyObjectRef {
@@ -154,7 +153,7 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
compile::compile(&source, &mode, filename, vm.ctx.code_type()).map_err(|err| {
let syntax_error = vm.context().exceptions.syntax_error.clone();
vm.new_exception(syntax_error, err.description().to_string())
vm.new_exception(syntax_error, err.to_string())
})
}
@@ -208,7 +207,7 @@ fn builtin_eval(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
compile::compile(&source, &mode, "<string>".to_string(), vm.ctx.code_type()).map_err(
|err| {
let syntax_error = vm.context().exceptions.syntax_error.clone();
vm.new_exception(syntax_error, err.description().to_string())
vm.new_exception(syntax_error, err.to_string())
},
)?
} else {
@@ -243,7 +242,7 @@ fn builtin_exec(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
compile::compile(&source, &mode, "<string>".to_string(), vm.ctx.code_type()).map_err(
|err| {
let syntax_error = vm.context().exceptions.syntax_error.clone();
vm.new_exception(syntax_error, err.description().to_string())
vm.new_exception(syntax_error, err.to_string())
},
)?
} else if objtype::isinstance(source, &vm.ctx.code_type()) {
@@ -705,135 +704,96 @@ fn builtin_sum(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
// builtin___import__
pub fn make_module(ctx: &PyContext) -> PyObjectRef {
let mod_name = "__builtins__";
let py_mod = ctx.new_module(mod_name, ctx.new_scope(None));
let py_mod = py_module!(ctx, "__builtins__", {
//set __name__ fixes: https://github.com/RustPython/RustPython/issues/146
"__name__" => ctx.new_str(String::from("__main__")),
//set __name__ fixes: https://github.com/RustPython/RustPython/issues/146
ctx.set_attr(&py_mod, "__name__", ctx.new_str(String::from("__main__")));
"abs" => ctx.new_rustfunc(builtin_abs),
"all" => ctx.new_rustfunc(builtin_all),
"any" => ctx.new_rustfunc(builtin_any),
"bin" => ctx.new_rustfunc(builtin_bin),
"bool" => ctx.bool_type(),
"bytearray" => ctx.bytearray_type(),
"bytes" => ctx.bytes_type(),
"callable" => ctx.new_rustfunc(builtin_callable),
"chr" => ctx.new_rustfunc(builtin_chr),
"classmethod" => ctx.classmethod_type(),
"compile" => ctx.new_rustfunc(builtin_compile),
"complex" => ctx.complex_type(),
"delattr" => ctx.new_rustfunc(builtin_delattr),
"dict" => ctx.dict_type(),
"divmod" => ctx.new_rustfunc(builtin_divmod),
"dir" => ctx.new_rustfunc(builtin_dir),
"enumerate" => ctx.enumerate_type(),
"eval" => ctx.new_rustfunc(builtin_eval),
"exec" => ctx.new_rustfunc(builtin_exec),
"float" => ctx.float_type(),
"frozenset" => ctx.frozenset_type(),
"filter" => ctx.filter_type(),
"format" => ctx.new_rustfunc(builtin_format),
"getattr" => ctx.new_rustfunc(builtin_getattr),
"hasattr" => ctx.new_rustfunc(builtin_hasattr),
"hash" => ctx.new_rustfunc(builtin_hash),
"hex" => ctx.new_rustfunc(builtin_hex),
"id" => ctx.new_rustfunc(builtin_id),
"int" => ctx.int_type(),
"isinstance" => ctx.new_rustfunc(builtin_isinstance),
"issubclass" => ctx.new_rustfunc(builtin_issubclass),
"iter" => ctx.new_rustfunc(builtin_iter),
"len" => ctx.new_rustfunc(builtin_len),
"list" => ctx.list_type(),
"locals" => ctx.new_rustfunc(builtin_locals),
"map" => ctx.map_type(),
"max" => ctx.new_rustfunc(builtin_max),
"memoryview" => ctx.memoryview_type(),
"min" => ctx.new_rustfunc(builtin_min),
"object" => ctx.object(),
"oct" => ctx.new_rustfunc(builtin_oct),
"ord" => ctx.new_rustfunc(builtin_ord),
"next" => ctx.new_rustfunc(builtin_next),
"pow" => ctx.new_rustfunc(builtin_pow),
"print" => ctx.new_rustfunc(builtin_print),
"property" => ctx.property_type(),
"range" => ctx.range_type(),
"repr" => ctx.new_rustfunc(builtin_repr),
"reversed" => ctx.new_rustfunc(builtin_reversed),
"round" => ctx.new_rustfunc(builtin_round),
"set" => ctx.set_type(),
"setattr" => ctx.new_rustfunc(builtin_setattr),
"slice" => ctx.slice_type(),
"staticmethod" => ctx.staticmethod_type(),
"str" => ctx.str_type(),
"sum" => ctx.new_rustfunc(builtin_sum),
"super" => ctx.super_type(),
"tuple" => ctx.tuple_type(),
"type" => ctx.type_type(),
"zip" => ctx.zip_type(),
// Constants
"NotImplemented" => ctx.not_implemented.clone(),
// Exceptions:
"BaseException" => ctx.exceptions.base_exception_type.clone(),
"Exception" => ctx.exceptions.exception_type.clone(),
"ArithmeticError" => ctx.exceptions.arithmetic_error.clone(),
"AssertionError" => ctx.exceptions.assertion_error.clone(),
"AttributeError" => ctx.exceptions.attribute_error.clone(),
"NameError" => ctx.exceptions.name_error.clone(),
"OverflowError" => ctx.exceptions.overflow_error.clone(),
"RuntimeError" => ctx.exceptions.runtime_error.clone(),
"NotImplementedError" => ctx.exceptions.not_implemented_error.clone(),
"TypeError" => ctx.exceptions.type_error.clone(),
"ValueError" => ctx.exceptions.value_error.clone(),
"IndexError" => ctx.exceptions.index_error.clone(),
"ImportError" => ctx.exceptions.import_error.clone(),
"FileNotFoundError" => ctx.exceptions.file_not_found_error.clone(),
"StopIteration" => ctx.exceptions.stop_iteration.clone(),
"ZeroDivisionError" => ctx.exceptions.zero_division_error.clone(),
"KeyError" => ctx.exceptions.key_error.clone(),
});
ctx.set_attr(&py_mod, "abs", ctx.new_rustfunc(builtin_abs));
ctx.set_attr(&py_mod, "all", ctx.new_rustfunc(builtin_all));
ctx.set_attr(&py_mod, "any", ctx.new_rustfunc(builtin_any));
ctx.set_attr(&py_mod, "bin", ctx.new_rustfunc(builtin_bin));
ctx.set_attr(&py_mod, "bool", ctx.bool_type());
ctx.set_attr(&py_mod, "bytearray", ctx.bytearray_type());
ctx.set_attr(&py_mod, "bytes", ctx.bytes_type());
ctx.set_attr(&py_mod, "callable", ctx.new_rustfunc(builtin_callable));
ctx.set_attr(&py_mod, "chr", ctx.new_rustfunc(builtin_chr));
ctx.set_attr(&py_mod, "classmethod", ctx.classmethod_type());
ctx.set_attr(&py_mod, "compile", ctx.new_rustfunc(builtin_compile));
ctx.set_attr(&py_mod, "complex", ctx.complex_type());
ctx.set_attr(&py_mod, "delattr", ctx.new_rustfunc(builtin_delattr));
ctx.set_attr(&py_mod, "dict", ctx.dict_type());
ctx.set_attr(&py_mod, "divmod", ctx.new_rustfunc(builtin_divmod));
ctx.set_attr(&py_mod, "dir", ctx.new_rustfunc(builtin_dir));
ctx.set_attr(&py_mod, "enumerate", ctx.enumerate_type());
ctx.set_attr(&py_mod, "eval", ctx.new_rustfunc(builtin_eval));
ctx.set_attr(&py_mod, "exec", ctx.new_rustfunc(builtin_exec));
ctx.set_attr(&py_mod, "float", ctx.float_type());
ctx.set_attr(&py_mod, "frozenset", ctx.frozenset_type());
ctx.set_attr(&py_mod, "filter", ctx.filter_type());
ctx.set_attr(&py_mod, "format", ctx.new_rustfunc(builtin_format));
ctx.set_attr(&py_mod, "getattr", ctx.new_rustfunc(builtin_getattr));
ctx.set_attr(&py_mod, "hasattr", ctx.new_rustfunc(builtin_hasattr));
ctx.set_attr(&py_mod, "hash", ctx.new_rustfunc(builtin_hash));
ctx.set_attr(&py_mod, "hex", ctx.new_rustfunc(builtin_hex));
ctx.set_attr(&py_mod, "id", ctx.new_rustfunc(builtin_id));
ctx.set_attr(&py_mod, "int", ctx.int_type());
ctx.set_attr(&py_mod, "isinstance", ctx.new_rustfunc(builtin_isinstance));
ctx.set_attr(&py_mod, "issubclass", ctx.new_rustfunc(builtin_issubclass));
ctx.set_attr(&py_mod, "iter", ctx.new_rustfunc(builtin_iter));
ctx.set_attr(&py_mod, "len", ctx.new_rustfunc(builtin_len));
ctx.set_attr(&py_mod, "list", ctx.list_type());
ctx.set_attr(&py_mod, "locals", ctx.new_rustfunc(builtin_locals));
ctx.set_attr(&py_mod, "map", ctx.map_type());
ctx.set_attr(&py_mod, "max", ctx.new_rustfunc(builtin_max));
ctx.set_attr(&py_mod, "memoryview", ctx.memoryview_type());
ctx.set_attr(&py_mod, "min", ctx.new_rustfunc(builtin_min));
ctx.set_attr(&py_mod, "object", ctx.object());
ctx.set_attr(&py_mod, "oct", ctx.new_rustfunc(builtin_oct));
#[cfg(not(target_arch = "wasm32"))]
ctx.set_attr(&py_mod, "open", ctx.new_rustfunc(io_open));
ctx.set_attr(&py_mod, "ord", ctx.new_rustfunc(builtin_ord));
ctx.set_attr(&py_mod, "next", ctx.new_rustfunc(builtin_next));
ctx.set_attr(&py_mod, "pow", ctx.new_rustfunc(builtin_pow));
ctx.set_attr(&py_mod, "print", ctx.new_rustfunc(builtin_print));
ctx.set_attr(&py_mod, "property", ctx.property_type());
ctx.set_attr(&py_mod, "range", ctx.range_type());
ctx.set_attr(&py_mod, "repr", ctx.new_rustfunc(builtin_repr));
ctx.set_attr(&py_mod, "reversed", ctx.new_rustfunc(builtin_reversed));
ctx.set_attr(&py_mod, "round", ctx.new_rustfunc(builtin_round));
ctx.set_attr(&py_mod, "set", ctx.set_type());
ctx.set_attr(&py_mod, "setattr", ctx.new_rustfunc(builtin_setattr));
ctx.set_attr(&py_mod, "slice", ctx.slice_type());
ctx.set_attr(&py_mod, "staticmethod", ctx.staticmethod_type());
ctx.set_attr(&py_mod, "str", ctx.str_type());
ctx.set_attr(&py_mod, "sum", ctx.new_rustfunc(builtin_sum));
ctx.set_attr(&py_mod, "super", ctx.super_type());
ctx.set_attr(&py_mod, "tuple", ctx.tuple_type());
ctx.set_attr(&py_mod, "type", ctx.type_type());
ctx.set_attr(&py_mod, "zip", ctx.zip_type());
// Constants
ctx.set_attr(&py_mod, "NotImplemented", ctx.not_implemented.clone());
// Exceptions:
ctx.set_attr(
&py_mod,
"BaseException",
ctx.exceptions.base_exception_type.clone(),
);
ctx.set_attr(&py_mod, "Exception", ctx.exceptions.exception_type.clone());
ctx.set_attr(
&py_mod,
"ArithmeticError",
ctx.exceptions.arithmetic_error.clone(),
);
ctx.set_attr(
&py_mod,
"AssertionError",
ctx.exceptions.assertion_error.clone(),
);
ctx.set_attr(
&py_mod,
"AttributeError",
ctx.exceptions.attribute_error.clone(),
);
ctx.set_attr(&py_mod, "NameError", ctx.exceptions.name_error.clone());
ctx.set_attr(
&py_mod,
"OverflowError",
ctx.exceptions.overflow_error.clone(),
);
ctx.set_attr(
&py_mod,
"RuntimeError",
ctx.exceptions.runtime_error.clone(),
);
ctx.set_attr(
&py_mod,
"NotImplementedError",
ctx.exceptions.not_implemented_error.clone(),
);
ctx.set_attr(&py_mod, "TypeError", ctx.exceptions.type_error.clone());
ctx.set_attr(&py_mod, "ValueError", ctx.exceptions.value_error.clone());
ctx.set_attr(&py_mod, "IndexError", ctx.exceptions.index_error.clone());
ctx.set_attr(&py_mod, "ImportError", ctx.exceptions.import_error.clone());
ctx.set_attr(
&py_mod,
"FileNotFoundError",
ctx.exceptions.file_not_found_error.clone(),
);
ctx.set_attr(
&py_mod,
"StopIteration",
ctx.exceptions.stop_iteration.clone(),
);
ctx.set_attr(
&py_mod,
"ZeroDivisionError",
ctx.exceptions.zero_division_error.clone(),
);
py_mod
}
+121 -12
View File
@@ -8,7 +8,7 @@
use num_bigint::BigInt;
use num_complex::Complex64;
use rustpython_parser::ast;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fmt;
/// Primary container of a single code object. Each python function has
@@ -71,6 +71,7 @@ pub enum Instruction {
},
BinaryOperation {
op: BinaryOperator,
inplace: bool,
},
LoadAttr {
name: String,
@@ -172,6 +173,8 @@ pub enum Instruction {
},
}
use self::Instruction::*;
#[derive(Debug, Clone, PartialEq)]
pub enum CallType {
Positional(usize),
@@ -276,17 +279,123 @@ impl CodeObject {
}
}
impl fmt::Debug for CodeObject {
impl fmt::Display for CodeObject {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let inst_str = self
.instructions
.iter()
.zip(self.locations.iter())
.enumerate()
.map(|(i, inst)| format!("Inst {}: {:?}", i, inst))
.collect::<Vec<_>>()
.join("\n");
let labelmap_str = format!("label_map: {:?}", self.label_map);
write!(f, "Code Object {{ \n{}\n{} }}", inst_str, labelmap_str)
let label_targets: HashSet<&usize> = self.label_map.values().collect();
for (offset, instruction) in self.instructions.iter().enumerate() {
let arrow = if label_targets.contains(&offset) {
">>"
} else {
" "
};
write!(f, " {} {:5} ", arrow, offset)?;
instruction.fmt_dis(f, &self.label_map)?;
}
Ok(())
}
}
impl Instruction {
fn fmt_dis(&self, f: &mut fmt::Formatter, label_map: &HashMap<Label, usize>) -> fmt::Result {
macro_rules! w {
($variant:ident) => {
write!(f, "{:20}\n", stringify!($variant))
};
($variant:ident, $var:expr) => {
write!(f, "{:20} ({})\n", stringify!($variant), $var)
};
($variant:ident, $var1:expr, $var2:expr) => {
write!(f, "{:20} ({}, {})\n", stringify!($variant), $var1, $var2)
};
}
match self {
Import { name, symbol } => w!(Import, name, format!("{:?}", symbol)),
ImportStar { name } => w!(ImportStar, name),
LoadName { name } => w!(LoadName, name),
StoreName { name } => w!(StoreName, name),
DeleteName { name } => w!(DeleteName, name),
StoreSubscript => w!(StoreSubscript),
DeleteSubscript => w!(DeleteSubscript),
StoreAttr { name } => w!(StoreAttr, name),
DeleteAttr { name } => w!(DeleteAttr, name),
LoadConst { value } => w!(LoadConst, value),
UnaryOperation { op } => w!(UnaryOperation, format!("{:?}", op)),
BinaryOperation { op, inplace } => w!(BinaryOperation, format!("{:?}", op), inplace),
LoadAttr { name } => w!(LoadAttr, name),
CompareOperation { op } => w!(CompareOperation, format!("{:?}", op)),
Pop => w!(Pop),
Rotate { amount } => w!(Rotate, amount),
Duplicate => w!(Duplicate),
GetIter => w!(GetIter),
Pass => w!(Pass),
Continue => w!(Continue),
Break => w!(Break),
Jump { target } => w!(Jump, label_map[target]),
JumpIf { target } => w!(JumpIf, label_map[target]),
JumpIfFalse { target } => w!(JumpIfFalse, label_map[target]),
MakeFunction { flags } => w!(MakeFunction, format!("{:?}", flags)),
CallFunction { typ } => w!(CallFunction, format!("{:?}", typ)),
ForIter { target } => w!(ForIter, label_map[target]),
ReturnValue => w!(ReturnValue),
YieldValue => w!(YieldValue),
YieldFrom => w!(YieldFrom),
SetupLoop { start, end } => w!(SetupLoop, label_map[start], label_map[end]),
SetupExcept { handler } => w!(SetupExcept, handler),
SetupWith { end } => w!(SetupWith, end),
CleanupWith { end } => w!(CleanupWith, end),
PopBlock => w!(PopBlock),
Raise { argc } => w!(Raise, argc),
BuildString { size } => w!(BuildString, size),
BuildTuple { size, unpack } => w!(BuildTuple, size, unpack),
BuildList { size, unpack } => w!(BuildList, size, unpack),
BuildSet { size, unpack } => w!(BuildSet, size, unpack),
BuildMap { size, unpack } => w!(BuildMap, size, unpack),
BuildSlice { size } => w!(BuildSlice, size),
ListAppend { i } => w!(ListAppend, i),
SetAdd { i } => w!(SetAdd, i),
MapAdd { i } => w!(MapAdd, i),
PrintExpr => w!(PrintExpr),
LoadBuildClass => w!(LoadBuildClass),
StoreLocals => w!(StoreLocals),
UnpackSequence { size } => w!(UnpackSequence, size),
UnpackEx { before, after } => w!(UnpackEx, before, after),
Unpack => w!(Unpack),
FormatValue { spec } => w!(FormatValue, spec),
}
}
}
impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Constant::Integer { value } => write!(f, "{}", value),
Constant::Float { value } => write!(f, "{}", value),
Constant::Complex { value } => write!(f, "{}", value),
Constant::Boolean { value } => write!(f, "{}", value),
Constant::String { value } => write!(f, "{:?}", value),
Constant::Bytes { value } => write!(f, "{:?}", value),
Constant::Code { code } => write!(f, "{:?}", code),
Constant::Tuple { elements } => write!(
f,
"({})",
elements
.iter()
.map(|e| format!("{}", e))
.collect::<Vec<_>>()
.join(", ")
),
Constant::None => write!(f, "None"),
}
}
}
impl fmt::Debug for CodeObject {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"<code object {} at ??? file {:?}, line {}>",
self.obj_name, self.source_path, self.first_line_number
)
}
}
+39 -22
View File
@@ -5,9 +5,9 @@
//! https://github.com/python/cpython/blob/master/Python/compile.c
//! https://github.com/micropython/micropython/blob/master/py/compile.c
use super::bytecode::{self, CallType, CodeObject, Instruction};
use super::error::CompileError;
use super::pyobject::{PyObject, PyObjectPayload, PyObjectRef};
use crate::bytecode::{self, CallType, CodeObject, Instruction};
use crate::error::CompileError;
use crate::pyobject::{PyObject, PyObjectPayload, PyObjectRef};
use num_complex::Complex64;
use rustpython_parser::{ast, parser};
@@ -16,6 +16,7 @@ struct Compiler {
nxt_label: usize,
source_path: Option<String>,
current_source_location: ast::Location,
in_loop: bool,
}
/// Compile a given sourcecode into a bytecode object.
@@ -73,6 +74,7 @@ impl Compiler {
nxt_label: 0,
source_path: None,
current_source_location: ast::Location::default(),
in_loop: false,
}
}
@@ -229,16 +231,19 @@ impl Compiler {
self.set_label(start_label);
self.compile_test(test, None, Some(else_label), EvalContext::Statement)?;
self.in_loop = true;
self.compile_statements(body)?;
self.in_loop = false;
self.emit(Instruction::Jump {
target: start_label,
});
self.set_label(else_label);
self.emit(Instruction::PopBlock);
if let Some(orelse) = orelse {
self.compile_statements(orelse)?;
}
self.set_label(end_label);
self.emit(Instruction::PopBlock);
}
ast::Statement::With { items, body } => {
let end_label = self.new_label();
@@ -267,14 +272,6 @@ impl Compiler {
body,
orelse,
} => {
// The thing iterated:
for i in iter {
self.compile_expression(i)?;
}
// Retrieve iterator
self.emit(Instruction::GetIter);
// Start loop
let start_label = self.new_label();
let else_label = self.new_label();
@@ -283,6 +280,15 @@ impl Compiler {
start: start_label,
end: end_label,
});
// The thing iterated:
for i in iter {
self.compile_expression(i)?;
}
// Retrieve Iterator
self.emit(Instruction::GetIter);
self.set_label(start_label);
self.emit(Instruction::ForIter { target: else_label });
@@ -290,16 +296,19 @@ impl Compiler {
self.compile_store(target)?;
// Body of loop:
self.in_loop = true;
self.compile_statements(body)?;
self.in_loop = false;
self.emit(Instruction::Jump {
target: start_label,
});
self.set_label(else_label);
self.emit(Instruction::PopBlock);
if let Some(orelse) = orelse {
self.compile_statements(orelse)?;
}
self.set_label(end_label);
self.emit(Instruction::PopBlock);
}
ast::Statement::Raise { exception, cause } => match exception {
Some(value) => {
@@ -563,9 +572,15 @@ impl Compiler {
self.set_label(end_label);
}
ast::Statement::Break => {
if !self.in_loop {
return Err(CompileError::InvalidBreak);
}
self.emit(Instruction::Break);
}
ast::Statement::Continue => {
if !self.in_loop {
return Err(CompileError::InvalidContinue);
}
self.emit(Instruction::Continue);
}
ast::Statement::Return { value } => {
@@ -608,7 +623,7 @@ impl Compiler {
self.compile_expression(value)?;
// Perform operation:
self.compile_op(op);
self.compile_op(op, true);
self.compile_store(target)?;
}
ast::Statement::Delete { targets } => {
@@ -631,7 +646,7 @@ impl Compiler {
self.emit(Instruction::DeleteSubscript);
}
_ => {
return Err(CompileError::Delete);
return Err(CompileError::Delete(target.name()));
}
}
}
@@ -648,6 +663,7 @@ impl Compiler {
name: &str,
args: &ast::Parameters,
) -> Result<bytecode::FunctionOpArg, CompileError> {
self.in_loop = false;
let have_kwargs = !args.defaults.is_empty();
if have_kwargs {
// Construct a tuple:
@@ -750,14 +766,14 @@ impl Compiler {
}
}
_ => {
return Err(CompileError::Assign(format!("{:?}", target)));
return Err(CompileError::Assign(target.name()));
}
}
Ok(())
}
fn compile_op(&mut self, op: &ast::Operator) {
fn compile_op(&mut self, op: &ast::Operator, inplace: bool) {
let i = match op {
ast::Operator::Add => bytecode::BinaryOperator::Add,
ast::Operator::Sub => bytecode::BinaryOperator::Subtract,
@@ -773,7 +789,7 @@ impl Compiler {
ast::Operator::BitXor => bytecode::BinaryOperator::Xor,
ast::Operator::BitAnd => bytecode::BinaryOperator::And,
};
self.emit(Instruction::BinaryOperation { op: i });
self.emit(Instruction::BinaryOperation { op: i, inplace });
}
fn compile_test(
@@ -852,13 +868,14 @@ impl Compiler {
self.compile_expression(b)?;
// Perform operation:
self.compile_op(op);
self.compile_op(op, false);
}
ast::Expression::Subscript { a, b } => {
self.compile_expression(a)?;
self.compile_expression(b)?;
self.emit(Instruction::BinaryOperation {
op: bytecode::BinaryOperator::Subscript,
inplace: false,
});
}
ast::Expression::Unop { op, a } => {
@@ -1384,10 +1401,10 @@ impl Compiler {
#[cfg(test)]
mod tests {
use super::bytecode::CodeObject;
use super::bytecode::Constant::*;
use super::bytecode::Instruction::*;
use super::Compiler;
use crate::bytecode::CodeObject;
use crate::bytecode::Constant::*;
use crate::bytecode::Instruction::*;
use rustpython_parser::parser;
fn compile_exec(source: &str) -> CodeObject {
let mut compiler = Compiler::new();
+4 -4
View File
@@ -1,7 +1,7 @@
use super::obj::objbool;
use super::obj::objint;
use super::pyobject::{IdProtocol, PyObjectRef, PyResult};
use super::vm::VirtualMachine;
use crate::obj::objbool;
use crate::obj::objint;
use crate::pyobject::{IdProtocol, PyObjectRef, PyResult};
use crate::vm::VirtualMachine;
use num_traits::ToPrimitive;
/// Ordered dictionary implementation.
/// Inspired by: https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html
+16 -10
View File
@@ -5,26 +5,32 @@ use std::fmt;
#[derive(Debug)]
pub enum CompileError {
// Invalid assignment, cannot store value in target.
Assign(String),
// Invalid delete
Delete,
// Expected an expression got a statement
/// Invalid assignment, cannot store value in target.
Assign(&'static str),
/// Invalid delete
Delete(&'static str),
/// Expected an expression got a statement
ExpectExpr,
// Parser error
/// Parser error
Parse(ParseError),
// Multiple `*` detected
/// Multiple `*` detected
StarArgs,
/// Break statement outside of loop.
InvalidBreak,
/// Continue statement outside of loop.
InvalidContinue,
}
impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CompileError::Assign(expr) => write!(f, "Invalid assignment: {}", expr),
CompileError::Delete => write!(f, "Invalid delete statement"),
CompileError::Assign(target) => write!(f, "can't assign to {}", target),
CompileError::Delete(target) => write!(f, "can't delete {}", target),
CompileError::ExpectExpr => write!(f, "Expecting expression, got statement"),
CompileError::Parse(err) => err.fmt(f),
CompileError::Parse(err) => write!(f, "{}", err),
CompileError::StarArgs => write!(f, "Two starred expressions in assignment"),
CompileError::InvalidBreak => write!(f, "break outside loop"),
CompileError::InvalidContinue => write!(f, "continue outside loop"),
}
}
}
+3 -3
View File
@@ -2,9 +2,9 @@ extern crate rustpython_parser;
use std::error::Error;
use super::compile;
use super::pyobject::{PyObjectRef, PyResult};
use super::vm::VirtualMachine;
use crate::compile;
use crate::pyobject::{PyObjectRef, PyResult};
use crate::vm::VirtualMachine;
pub fn eval(
vm: &mut VirtualMachine,
+5 -5
View File
@@ -1,10 +1,10 @@
use super::obj::objsequence;
use super::obj::objstr;
use super::obj::objtype;
use super::pyobject::{
use crate::obj::objsequence;
use crate::obj::objstr;
use crate::obj::objtype;
use crate::pyobject::{
create_type, AttributeProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol,
};
use super::vm::VirtualMachine;
use crate::vm::VirtualMachine;
fn exception_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let zelf = args.args[0].clone();
+98 -64
View File
@@ -5,25 +5,33 @@ use std::fmt;
use std::mem;
use std::path::PathBuf;
use super::builtins;
use super::bytecode;
use super::import::{import, import_module};
use super::obj::objbool;
use super::obj::objcode;
use super::obj::objdict;
use super::obj::objiter;
use super::obj::objlist;
use super::obj::objstr;
use super::obj::objtype;
use super::pyobject::{
use crate::builtins;
use crate::bytecode;
use crate::import::{import, import_module};
use crate::obj::objbool;
use crate::obj::objcode;
use crate::obj::objdict;
use crate::obj::objiter;
use crate::obj::objlist;
use crate::obj::objstr;
use crate::obj::objtype;
use crate::pyobject::{
DictProtocol, IdProtocol, ParentProtocol, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef,
PyResult, TypeProtocol,
};
use super::vm::VirtualMachine;
use crate::vm::VirtualMachine;
use num_bigint::BigInt;
#[derive(Clone, Debug)]
enum Block {
struct Block {
/// The type of block.
typ: BlockType,
/// The level of the value stack when the block was entered.
level: usize,
}
#[derive(Clone, Debug)]
enum BlockType {
Loop {
start: bytecode::Label,
end: bytecode::Label,
@@ -316,7 +324,9 @@ impl Frame {
vm.call_method(&dict_obj, "__setitem__", vec![key, value])?;
Ok(None)
}
bytecode::Instruction::BinaryOperation { ref op } => self.execute_binop(vm, op),
bytecode::Instruction::BinaryOperation { ref op, inplace } => {
self.execute_binop(vm, op, *inplace)
}
bytecode::Instruction::LoadAttr { ref name } => self.load_attr(vm, name),
bytecode::Instruction::StoreAttr { ref name } => self.store_attr(vm, name),
bytecode::Instruction::DeleteAttr { ref name } => self.delete_attr(vm, name),
@@ -355,21 +365,21 @@ impl Frame {
}
}
bytecode::Instruction::SetupLoop { start, end } => {
self.push_block(Block::Loop {
self.push_block(BlockType::Loop {
start: *start,
end: *end,
});
Ok(None)
}
bytecode::Instruction::SetupExcept { handler } => {
self.push_block(Block::TryExcept { handler: *handler });
self.push_block(BlockType::TryExcept { handler: *handler });
Ok(None)
}
bytecode::Instruction::SetupWith { end } => {
let context_manager = self.pop_value();
// Call enter:
let obj = vm.call_method(&context_manager, "__enter__", vec![])?;
self.push_block(Block::With {
self.push_block(BlockType::With {
end: *end,
context_manager: context_manager.clone(),
});
@@ -378,22 +388,23 @@ impl Frame {
}
bytecode::Instruction::CleanupWith { end: end1 } => {
let block = self.pop_block().unwrap();
if let Block::With {
if let BlockType::With {
end: end2,
context_manager,
} = &block
} = &block.typ
{
assert!(end1 == end2);
debug_assert!(end1 == end2);
// call exit now with no exception:
self.with_exit(vm, context_manager, None)?;
Ok(None)
self.with_exit(vm, &context_manager, None)?;
} else {
panic!("Block stack is incorrect, expected a with block");
unreachable!("Block stack is incorrect, expected a with block");
}
Ok(None)
}
bytecode::Instruction::PopBlock => {
self.pop_block();
self.pop_block().expect("no pop to block");
Ok(None)
}
bytecode::Instruction::GetIter => {
@@ -530,8 +541,11 @@ impl Frame {
bytecode::Instruction::Break => {
let block = self.unwind_loop(vm);
if let Block::Loop { end, .. } = block {
if let BlockType::Loop { end, .. } = block.typ {
self.pop_block();
self.jump(end);
} else {
unreachable!()
}
Ok(None)
}
@@ -541,10 +555,10 @@ impl Frame {
}
bytecode::Instruction::Continue => {
let block = self.unwind_loop(vm);
if let Block::Loop { start, .. } = block {
if let BlockType::Loop { start, .. } = block.typ {
self.jump(start);
} else {
assert!(false);
unreachable!();
}
Ok(None)
}
@@ -709,16 +723,15 @@ impl Frame {
// Unwind all blocks:
fn unwind_blocks(&mut self, vm: &mut VirtualMachine) -> Option<PyObjectRef> {
loop {
let block = self.pop_block();
match block {
Some(Block::Loop { .. }) => {}
Some(Block::TryExcept { .. }) => {
while let Some(block) = self.pop_block() {
match block.typ {
BlockType::Loop { .. } => {}
BlockType::TryExcept { .. } => {
// TODO: execute finally handler
}
Some(Block::With {
BlockType::With {
context_manager, ..
}) => {
} => {
match self.with_exit(vm, &context_manager, None) {
Ok(..) => {}
Err(exc) => {
@@ -727,29 +740,31 @@ impl Frame {
}
}
}
None => break None,
}
}
None
}
fn unwind_loop(&mut self, vm: &mut VirtualMachine) -> Block {
loop {
let block = self.pop_block();
match block {
Some(Block::Loop { .. }) => break block.unwrap(),
Some(Block::TryExcept { .. }) => {
let block = self.current_block().cloned().expect("not in a loop");
match block.typ {
BlockType::Loop { .. } => break block,
BlockType::TryExcept { .. } => {
// TODO: execute finally handler
}
Some(Block::With {
BlockType::With {
context_manager, ..
}) => match self.with_exit(vm, &context_manager, None) {
} => match self.with_exit(vm, &context_manager, None) {
Ok(..) => {}
Err(exc) => {
panic!("Exception in with __exit__ {:?}", exc);
}
},
None => panic!("No block to break / continue"),
}
self.pop_block();
}
}
@@ -759,18 +774,17 @@ impl Frame {
exc: PyObjectRef,
) -> Option<PyObjectRef> {
// unwind block stack on exception and find any handlers:
loop {
let block = self.pop_block();
match block {
Some(Block::TryExcept { handler }) => {
while let Some(block) = self.pop_block() {
match block.typ {
BlockType::TryExcept { handler } => {
self.push_value(exc);
self.jump(handler);
return None;
}
Some(Block::With {
BlockType::With {
end,
context_manager,
}) => {
} => {
match self.with_exit(vm, &context_manager, Some(exc.clone())) {
Ok(exit_action) => {
match objbool::boolval(vm, exit_action) {
@@ -795,15 +809,14 @@ impl Frame {
}
}
}
Some(Block::Loop { .. }) => {}
None => break,
BlockType::Loop { .. } => {}
}
}
Some(exc)
}
fn with_exit(
&mut self,
&self,
vm: &mut VirtualMachine,
context_manager: &PyObjectRef,
exc: Option<PyObjectRef>,
@@ -893,27 +906,39 @@ impl Frame {
&mut self,
vm: &mut VirtualMachine,
op: &bytecode::BinaryOperator,
inplace: bool,
) -> FrameResult {
let b_ref = self.pop_value();
let a_ref = self.pop_value();
let value = match *op {
bytecode::BinaryOperator::Subtract if inplace => vm._isub(a_ref, b_ref),
bytecode::BinaryOperator::Subtract => vm._sub(a_ref, b_ref),
bytecode::BinaryOperator::Add if inplace => vm._iadd(a_ref, b_ref),
bytecode::BinaryOperator::Add => vm._add(a_ref, b_ref),
bytecode::BinaryOperator::Multiply if inplace => vm._imul(a_ref, b_ref),
bytecode::BinaryOperator::Multiply => vm._mul(a_ref, b_ref),
bytecode::BinaryOperator::MatrixMultiply => {
vm.call_method(&a_ref, "__matmul__", vec![b_ref])
}
bytecode::BinaryOperator::MatrixMultiply if inplace => vm._imatmul(a_ref, b_ref),
bytecode::BinaryOperator::MatrixMultiply => vm._matmul(a_ref, b_ref),
bytecode::BinaryOperator::Power if inplace => vm._ipow(a_ref, b_ref),
bytecode::BinaryOperator::Power => vm._pow(a_ref, b_ref),
bytecode::BinaryOperator::Divide => vm._div(a_ref, b_ref),
bytecode::BinaryOperator::FloorDivide => {
vm.call_method(&a_ref, "__floordiv__", vec![b_ref])
}
bytecode::BinaryOperator::Divide if inplace => vm._itruediv(a_ref, b_ref),
bytecode::BinaryOperator::Divide => vm._truediv(a_ref, b_ref),
bytecode::BinaryOperator::FloorDivide if inplace => vm._ifloordiv(a_ref, b_ref),
bytecode::BinaryOperator::FloorDivide => vm._floordiv(a_ref, b_ref),
// TODO: Subscript should probably have its own op
bytecode::BinaryOperator::Subscript if inplace => unreachable!(),
bytecode::BinaryOperator::Subscript => self.subscript(vm, a_ref, b_ref),
bytecode::BinaryOperator::Modulo => vm._modulo(a_ref, b_ref),
bytecode::BinaryOperator::Lshift => vm.call_method(&a_ref, "__lshift__", vec![b_ref]),
bytecode::BinaryOperator::Rshift => vm.call_method(&a_ref, "__rshift__", vec![b_ref]),
bytecode::BinaryOperator::Modulo if inplace => vm._imod(a_ref, b_ref),
bytecode::BinaryOperator::Modulo => vm._mod(a_ref, b_ref),
bytecode::BinaryOperator::Lshift if inplace => vm._ilshift(a_ref, b_ref),
bytecode::BinaryOperator::Lshift => vm._lshift(a_ref, b_ref),
bytecode::BinaryOperator::Rshift if inplace => vm._irshift(a_ref, b_ref),
bytecode::BinaryOperator::Rshift => vm._rshift(a_ref, b_ref),
bytecode::BinaryOperator::Xor if inplace => vm._ixor(a_ref, b_ref),
bytecode::BinaryOperator::Xor => vm._xor(a_ref, b_ref),
bytecode::BinaryOperator::Or if inplace => vm._ior(a_ref, b_ref),
bytecode::BinaryOperator::Or => vm._or(a_ref, b_ref),
bytecode::BinaryOperator::And if inplace => vm._iand(a_ref, b_ref),
bytecode::BinaryOperator::And => vm._and(a_ref, b_ref),
}?;
@@ -1047,12 +1072,21 @@ impl Frame {
self.code.locations[self.lasti].clone()
}
fn push_block(&mut self, block: Block) {
self.blocks.push(block);
fn push_block(&mut self, typ: BlockType) {
self.blocks.push(Block {
typ,
level: self.stack.len(),
});
}
fn pop_block(&mut self) -> Option<Block> {
self.blocks.pop()
let block = self.blocks.pop()?;
self.stack.truncate(block.level);
Some(block)
}
fn current_block(&self) -> Option<&Block> {
self.blocks.last()
}
pub fn push_value(&mut self, obj: PyObjectRef) {
+5 -5
View File
@@ -5,11 +5,11 @@
use std::error::Error;
use std::path::PathBuf;
use super::compile;
use super::pyobject::{AttributeProtocol, DictProtocol, PyResult};
use super::util;
use super::vm::VirtualMachine;
use obj::{objsequence, objstr};
use crate::compile;
use crate::obj::{objsequence, objstr};
use crate::pyobject::{AttributeProtocol, DictProtocol, PyResult};
use crate::util;
use crate::vm::VirtualMachine;
fn import_uncached_module(
vm: &mut VirtualMachine,
+22 -1
View File
@@ -1,3 +1,4 @@
// count number of tokens given as arguments.
// see: https://danielkeep.github.io/tlborm/book/blk-counting.html
#[macro_export]
macro_rules! replace_expr {
@@ -17,7 +18,7 @@ macro_rules! type_check {
// None indicates that we have no type requirement (i.e. we accept any type)
if let Some(expected_type) = $arg_type {
let arg = &$args.args[$arg_count];
if !objtype::isinstance(arg, &expected_type) {
if !$crate::obj::objtype::isinstance(arg, &expected_type) {
let arg_typ = arg.typ();
let expected_type_name = $vm.to_pystr(&expected_type)?;
let actual_type = $vm.to_pystr(&arg_typ)?;
@@ -48,9 +49,11 @@ macro_rules! arg_check {
( $vm: ident, $args:ident, required=[$( ($arg_name:ident, $arg_type:expr) ),*], optional=[$( ($optional_arg_name:ident, $optional_arg_type:expr) ),*] ) => {
let mut arg_count = 0;
// use macro magic to compile-time count number of required and optional arguments
let minimum_arg_count = count_tts!($($arg_name)*);
let maximum_arg_count = minimum_arg_count + count_tts!($($optional_arg_name)*);
// verify that the number of given arguments is right
if $args.args.len() < minimum_arg_count || $args.args.len() > maximum_arg_count {
let expected_str = if minimum_arg_count == maximum_arg_count {
format!("{}", minimum_arg_count)
@@ -64,6 +67,9 @@ macro_rules! arg_check {
)));
};
// for each required parameter:
// check if the type matches. If not, return with error
// assign the arg to a variable
$(
type_check!($vm, $args, arg_count, $arg_name, $arg_type);
let $arg_name = &$args.args[arg_count];
@@ -73,6 +79,9 @@ macro_rules! arg_check {
}
)*
// for each optional parameter, if there are enough positional arguments:
// check if the type matches. If not, return with error
// assign the arg to a variable
$(
let $optional_arg_name = if arg_count < $args.args.len() {
type_check!($vm, $args, arg_count, $optional_arg_name, $optional_arg_type);
@@ -101,3 +110,15 @@ macro_rules! no_kwargs {
}
};
}
macro_rules! py_module {
( $ctx:expr, $module_name:expr, { $($name:expr => $value:expr),* $(,)* }) => {
{
let py_mod = $ctx.new_module($module_name, $ctx.new_scope(None));
$(
$ctx.set_attr(&py_mod, $name, $value);
)*
py_mod
}
}
}
+3 -3
View File
@@ -1,8 +1,8 @@
use super::super::pyobject::{
use super::objtype;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::vm::VirtualMachine;
use num_traits::Zero;
pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObjectRef> {
+66 -6
View File
@@ -1,14 +1,13 @@
//! Implementation of the python bytearray object.
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol};
use super::objint;
use super::super::vm::VirtualMachine;
use super::objbytes::get_mut_value;
use super::objbytes::get_value;
use super::objtype;
use crate::vm::VirtualMachine;
use num_traits::ToPrimitive;
// Binary data support
@@ -95,6 +94,22 @@ pub fn init(context: &PyContext) {
"istitle",
context.new_rustfunc(bytearray_istitle),
);
context.set_attr(
&bytearray_type,
"clear",
context.new_rustfunc(bytearray_clear),
);
context.set_attr(&bytearray_type, "pop", context.new_rustfunc(bytearray_pop));
context.set_attr(
&bytearray_type,
"lower",
context.new_rustfunc(bytearray_lower),
);
context.set_attr(
&bytearray_type,
"upper",
context.new_rustfunc(bytearray_upper),
);
}
fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -114,7 +129,11 @@ fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let mut data_bytes = vec![];
for elem in elements.iter() {
let v = objint::to_int(vm, elem, 10)?;
data_bytes.push(v.to_u8().unwrap());
if let Some(i) = v.to_u8() {
data_bytes.push(i);
} else {
return Err(vm.new_value_error("byte must be in range(0, 256)".to_string()));
}
}
data_bytes
// return Err(vm.new_type_error("Cannot construct bytes".to_string()));
@@ -177,7 +196,7 @@ fn bytearray_islower(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
!bytes.is_empty()
&& bytes
.iter()
.filter(|x| char::from(**x).is_whitespace())
.filter(|x| !char::from(**x).is_whitespace())
.all(|x| char::from(*x).is_lowercase()),
))
}
@@ -261,3 +280,44 @@ fn bytearray_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let data = String::from_utf8(value.to_vec()).unwrap();
Ok(vm.new_str(format!("bytearray(b'{}')", data)))
}
fn bytearray_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.bytearray_type()))]);
let mut mut_obj = zelf.borrow_mut();
match mut_obj.payload {
PyObjectPayload::Bytes { ref mut value } => {
value.clear();
Ok(vm.get_none())
}
_ => panic!("Bytearray has incorrect payload."),
}
}
fn bytearray_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]);
let mut value = get_mut_value(obj);
if let Some(i) = value.pop() {
Ok(vm.ctx.new_int(i))
} else {
Err(vm.new_index_error("pop from empty bytearray".to_string()))
}
}
fn bytearray_lower(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]);
let value = get_value(obj).to_vec().to_ascii_lowercase();
Ok(PyObject::new(
PyObjectPayload::Bytes { value },
vm.ctx.bytearray_type(),
))
}
fn bytearray_upper(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(obj, Some(vm.ctx.bytearray_type()))]);
let value = get_value(obj).to_vec().to_ascii_uppercase();
Ok(PyObject::new(
PyObjectPayload::Bytes { value },
vm.ctx.bytearray_type(),
))
}
+17 -5
View File
@@ -1,13 +1,15 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objint;
use super::objtype;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use crate::vm::VirtualMachine;
use num_traits::ToPrimitive;
use std::cell::Ref;
use std::cell::RefMut;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::ops::DerefMut;
// Binary data support
@@ -183,7 +185,17 @@ pub fn get_value<'a>(obj: &'a PyObjectRef) -> impl Deref<Target = Vec<u8>> + 'a
if let PyObjectPayload::Bytes { ref value } = py_obj.payload {
value
} else {
panic!("Inner error getting int {:?}", obj);
panic!("Inner error getting bytearray {:?}", obj);
}
})
}
pub fn get_mut_value<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Vec<u8>> + 'a {
RefMut::map(obj.borrow_mut(), |py_obj| {
if let PyObjectPayload::Bytes { ref mut value } = py_obj.payload {
value
} else {
panic!("Inner error getting bytearray {:?}", obj);
}
})
}
+3 -4
View File
@@ -2,12 +2,11 @@
*/
use super::super::bytecode;
use super::super::pyobject::{
use crate::bytecode;
use crate::pyobject::{
IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::vm::VirtualMachine;
pub fn init(context: &PyContext) {
let code_type = &context.code_type;
+33 -4
View File
@@ -1,10 +1,10 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objfloat;
use super::objint;
use super::objtype;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use crate::vm::VirtualMachine;
use num_complex::Complex64;
use num_traits::ToPrimitive;
@@ -17,6 +17,11 @@ pub fn init(context: &PyContext) {
context.set_attr(&complex_type, "__abs__", context.new_rustfunc(complex_abs));
context.set_attr(&complex_type, "__add__", context.new_rustfunc(complex_add));
context.set_attr(
&complex_type,
"__radd__",
context.new_rustfunc(complex_radd),
);
context.set_attr(&complex_type, "__eq__", context.new_rustfunc(complex_eq));
context.set_attr(&complex_type, "__neg__", context.new_rustfunc(complex_neg));
context.set_attr(&complex_type, "__new__", context.new_rustfunc(complex_new));
@@ -106,6 +111,30 @@ fn complex_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let v1 = get_value(i);
if objtype::isinstance(i2, &vm.ctx.complex_type()) {
Ok(vm.ctx.new_complex(v1 + get_value(i2)))
} else if objtype::isinstance(i2, &vm.ctx.int_type()) {
Ok(vm.ctx.new_complex(Complex64::new(
v1.re + objint::get_value(i2).to_f64().unwrap(),
v1.im,
)))
} else {
Err(vm.new_type_error(format!("Cannot add {} and {}", i.borrow(), i2.borrow())))
}
}
fn complex_radd(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(i, Some(vm.ctx.complex_type())), (i2, None)]
);
let v1 = get_value(i);
if objtype::isinstance(i2, &vm.ctx.int_type()) {
Ok(vm.ctx.new_complex(Complex64::new(
v1.re + objint::get_value(i2).to_f64().unwrap(),
v1.im,
)))
} else {
Err(vm.new_type_error(format!("Cannot add {} and {}", i.borrow(), i2.borrow())))
}
+12 -5
View File
@@ -1,11 +1,11 @@
use super::super::pyobject::{
PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult,
TypeProtocol,
};
use super::super::vm::{ReprGuard, VirtualMachine};
use super::objiter;
use super::objstr;
use super::objtype;
use crate::pyobject::{
PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult,
TypeProtocol,
};
use crate::vm::{ReprGuard, VirtualMachine};
use std::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
@@ -244,6 +244,12 @@ fn dict_delitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
}
}
fn dict_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(dict, Some(vm.ctx.dict_type()))]);
get_mut_elements(dict).clear();
Ok(vm.get_none())
}
/// When iterating over a dictionary, we iterate over the keys of it.
fn dict_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(dict, Some(vm.ctx.dict_type()))]);
@@ -337,4 +343,5 @@ pub fn init(context: &PyContext) {
"__setitem__",
context.new_rustfunc(dict_setitem),
);
context.set_attr(&dict_type, "clear", context.new_rustfunc(dict_clear));
}
+2 -5
View File
@@ -1,10 +1,7 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objint;
use super::objiter;
use super::objtype; // Required for arg_check! to use isinstance
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
use num_bigint::BigInt;
use num_traits::Zero;
use std::ops::AddAssign;
+4 -5
View File
@@ -1,10 +1,9 @@
use super::super::pyobject::{
IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objbool;
use super::objiter;
use super::objtype; // Required for arg_check! to use isinstance
use crate::pyobject::{
IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance
fn filter_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
+4 -4
View File
@@ -1,11 +1,11 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objbytes;
use super::objint;
use super::objstr;
use super::objtype;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use crate::vm::VirtualMachine;
use num_bigint::ToBigInt;
use num_traits::ToPrimitive;
+3 -4
View File
@@ -2,12 +2,11 @@
*/
use super::super::frame::Frame;
use super::super::pyobject::{
use crate::frame::Frame;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::vm::VirtualMachine;
pub fn init(context: &PyContext) {
let frame_type = &context.frame_type;
+2 -3
View File
@@ -1,8 +1,7 @@
use super::super::pyobject::{
use crate::pyobject::{
AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::vm::VirtualMachine;
pub fn init(context: &PyContext) {
let function_type = &context.function_type;
+3 -4
View File
@@ -2,12 +2,11 @@
* The mythical generator.
*/
use super::super::frame::{ExecutionResult, Frame};
use super::super::pyobject::{
use crate::frame::{ExecutionResult, Frame};
use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::vm::VirtualMachine;
pub fn init(context: &PyContext) {
let generator_type = &context.generator_type;
+20 -6
View File
@@ -1,12 +1,12 @@
use super::super::format::FormatSpec;
use super::super::pyobject::{
FromPyObjectRef, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult,
TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objfloat;
use super::objstr;
use super::objtype;
use crate::format::FormatSpec;
use crate::pyobject::{
FromPyObjectRef, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult,
TypeProtocol,
};
use crate::vm::VirtualMachine;
use num_bigint::{BigInt, ToBigInt};
use num_integer::Integer;
use num_traits::{Pow, Signed, ToPrimitive, Zero};
@@ -608,6 +608,18 @@ fn int_conjugate(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(vm.ctx.new_int(v))
}
fn int_real(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.int_type()))]);
let value = BigInt::from_pyobj(zelf);
Ok(vm.ctx.new_int(value))
}
fn int_imag(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.int_type()))]);
let value = BigInt::from(0);
Ok(vm.ctx.new_int(value))
}
pub fn init(context: &PyContext) {
let int_doc = "int(x=0) -> integer
int(x, base=10) -> integer
@@ -680,4 +692,6 @@ Base 0 means to interpret the base from the string as an integer literal.
);
context.set_attr(&int_type, "__doc__", context.new_str(int_doc.to_string()));
context.set_attr(&int_type, "conjugate", context.new_rustfunc(int_conjugate));
context.set_attr(&int_type, "real", context.new_property(int_real));
context.set_attr(&int_type, "imag", context.new_property(int_imag));
}
+3 -3
View File
@@ -2,11 +2,11 @@
* Various types to support iteration.
*/
use super::super::pyobject::{
use super::objbool;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objbool;
use crate::vm::VirtualMachine;
// use super::objstr;
use super::objtype; // Required for arg_check! to use isinstance
+43 -8
View File
@@ -1,7 +1,3 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::{ReprGuard, VirtualMachine};
use super::objbool;
use super::objint;
use super::objsequence::{
@@ -10,6 +6,11 @@ use super::objsequence::{
};
use super::objstr;
use super::objtype;
use crate::pyobject::{
IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult,
TypeProtocol,
};
use crate::vm::{ReprGuard, VirtualMachine};
use num_traits::ToPrimitive;
// set_item:
@@ -66,6 +67,10 @@ fn list_eq(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
required = [(zelf, Some(vm.ctx.list_type())), (other, None)]
);
if zelf.is(&other) {
return Ok(vm.ctx.new_bool(true));
}
let result = if objtype::isinstance(other, &vm.ctx.list_type()) {
let zelf = get_elements(zelf);
let other = get_elements(other);
@@ -181,6 +186,21 @@ fn list_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
}
}
fn list_iadd(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(zelf, Some(vm.ctx.list_type())), (other, None)]
);
if objtype::isinstance(other, &vm.ctx.list_type()) {
get_mut_elements(zelf).extend_from_slice(&get_elements(other));
Ok(zelf.clone())
} else {
Ok(vm.ctx.not_implemented())
}
}
fn list_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(o, Some(vm.ctx.list_type()))]);
@@ -234,9 +254,13 @@ fn list_count(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
let elements = get_elements(zelf);
let mut count: usize = 0;
for element in elements.iter() {
let is_eq = vm._eq(element.clone(), value.clone())?;
if objbool::boolval(vm, is_eq)? {
if value.is(&element) {
count += 1;
} else {
let is_eq = vm._eq(element.clone(), value.clone())?;
if objbool::boolval(vm, is_eq)? {
count += 1;
}
}
}
Ok(vm.context().new_int(count))
@@ -262,6 +286,9 @@ fn list_index(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
required = [(list, Some(vm.ctx.list_type())), (needle, None)]
);
for (index, element) in get_elements(list).iter().enumerate() {
if needle.is(&element) {
return Ok(vm.context().new_int(index));
}
let py_equal = vm._eq(needle.clone(), element.clone())?;
if objbool::get_value(&py_equal) {
return Ok(vm.context().new_int(index));
@@ -335,6 +362,9 @@ fn list_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
required = [(list, Some(vm.ctx.list_type())), (needle, None)]
);
for element in get_elements(list).iter() {
if needle.is(&element) {
return Ok(vm.new_bool(true));
}
match vm._eq(needle.clone(), element.clone()) {
Ok(value) => {
if objbool::get_value(&value) {
@@ -416,9 +446,12 @@ fn list_remove(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
required = [(list, Some(vm.ctx.list_type())), (needle, None)]
);
let mut elements = get_mut_elements(list);
let mut ri: Option<usize> = None;
for (index, element) in elements.iter().enumerate() {
for (index, element) in get_elements(list).iter().enumerate() {
if needle.is(&element) {
ri = Some(index);
break;
}
let py_equal = vm._eq(needle.clone(), element.clone())?;
if objbool::get_value(&py_equal) {
ri = Some(index);
@@ -427,6 +460,7 @@ fn list_remove(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
}
if let Some(index) = ri {
let mut elements = get_mut_elements(list);
elements.remove(index);
Ok(vm.get_none())
} else {
@@ -443,6 +477,7 @@ pub fn init(context: &PyContext) {
The argument must be an iterable if specified.";
context.set_attr(&list_type, "__add__", context.new_rustfunc(list_add));
context.set_attr(&list_type, "__iadd__", context.new_rustfunc(list_iadd));
context.set_attr(
&list_type,
"__contains__",
+2 -5
View File
@@ -1,9 +1,6 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objiter;
use super::objtype; // Required for arg_check! to use isinstance
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol};
use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance
fn map_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
no_kwargs!(vm, args);
+2 -6
View File
@@ -1,9 +1,5 @@
use super::objtype;
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
pub fn new_memory_view(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(cls, None), (bytes_object, None)]);
+2 -3
View File
@@ -1,6 +1,5 @@
use super::super::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
pub fn init(context: &PyContext) {
let none_type = &context.none.typ();
+4 -4
View File
@@ -1,10 +1,10 @@
use super::super::pyobject::{
use super::objstr;
use super::objtype;
use crate::pyobject::{
AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult,
TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objstr;
use super::objtype;
use crate::vm::VirtualMachine;
use std::cell::RefCell;
use std::collections::HashMap;
+2 -3
View File
@@ -2,9 +2,8 @@
*/
use super::super::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
pub fn init(context: &PyContext) {
let property_type = &context.property_type;
+4 -4
View File
@@ -1,9 +1,9 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objint;
use super::objtype;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use crate::vm::VirtualMachine;
use num_bigint::{BigInt, Sign};
use num_integer::Integer;
use num_traits::{One, Signed, ToPrimitive, Zero};
+8 -6
View File
@@ -1,7 +1,7 @@
use super::super::pyobject::{PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol};
use super::super::vm::VirtualMachine;
use super::objbool;
use super::objint;
use crate::pyobject::{IdProtocol, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
use num_bigint::BigInt;
use num_traits::{One, Signed, ToPrimitive, Zero};
use std::cell::{Ref, RefMut};
@@ -178,10 +178,12 @@ pub fn seq_equal(
) -> Result<bool, PyObjectRef> {
if zelf.len() == other.len() {
for (a, b) in Iterator::zip(zelf.iter(), other.iter()) {
let eq = vm._eq(a.clone(), b.clone())?;
let value = objbool::boolval(vm, eq)?;
if !value {
return Ok(false);
if !a.is(&b) {
let eq = vm._eq(a.clone(), b.clone())?;
let value = objbool::boolval(vm, eq)?;
if !value {
return Ok(false);
}
}
}
Ok(true)
+176 -4
View File
@@ -2,15 +2,15 @@
* Builtin set type with a sequence of unique items.
*/
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::{ReprGuard, VirtualMachine};
use super::objbool;
use super::objint;
use super::objiter;
use super::objstr;
use super::objtype;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use crate::vm::{ReprGuard, VirtualMachine};
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
@@ -178,6 +178,16 @@ fn set_len(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(vm.context().new_int(elements.len()))
}
fn set_copy(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
trace!("set.copy called with: {:?}", args);
arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]);
let elements = get_elements(s);
Ok(PyObject::new(
PyObjectPayload::Set { elements },
vm.ctx.set_type(),
))
}
fn set_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(o, Some(vm.ctx.set_type()))]);
@@ -408,6 +418,145 @@ fn set_combine_inner(
))
}
fn set_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(s, Some(vm.ctx.set_type()))]);
let mut mut_obj = s.borrow_mut();
match mut_obj.payload {
PyObjectPayload::Set { ref mut elements } => match elements.clone().keys().next() {
Some(key) => Ok(elements.remove(key).unwrap()),
None => Err(vm.new_key_error("pop from an empty set".to_string())),
},
_ => Err(vm.new_type_error("".to_string())),
}
}
fn set_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
set_ior(vm, args)?;
Ok(vm.get_none())
}
fn set_ior(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(zelf, Some(vm.ctx.set_type())), (iterable, None)]
);
let mut mut_obj = zelf.borrow_mut();
match mut_obj.payload {
PyObjectPayload::Set { ref mut elements } => {
let iterator = objiter::get_iter(vm, iterable)?;
while let Ok(v) = vm.call_method(&iterator, "__next__", vec![]) {
insert_into_set(vm, elements, &v)?;
}
}
_ => return Err(vm.new_type_error("set.update is called with no other".to_string())),
}
Ok(zelf.clone())
}
fn set_intersection_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
set_combine_update_inner(vm, args, SetCombineOperation::Intersection)?;
Ok(vm.get_none())
}
fn set_iand(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
set_combine_update_inner(vm, args, SetCombineOperation::Intersection)
}
fn set_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
set_combine_update_inner(vm, args, SetCombineOperation::Difference)?;
Ok(vm.get_none())
}
fn set_isub(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
set_combine_update_inner(vm, args, SetCombineOperation::Difference)
}
fn set_combine_update_inner(
vm: &mut VirtualMachine,
args: PyFuncArgs,
op: SetCombineOperation,
) -> PyResult {
arg_check!(
vm,
args,
required = [(zelf, Some(vm.ctx.set_type())), (iterable, None)]
);
let mut mut_obj = zelf.borrow_mut();
match mut_obj.payload {
PyObjectPayload::Set { ref mut elements } => {
for element in elements.clone().iter() {
let value = vm.call_method(iterable, "__contains__", vec![element.1.clone()])?;
let should_remove = match op {
SetCombineOperation::Intersection => !objbool::get_value(&value),
SetCombineOperation::Difference => objbool::get_value(&value),
};
if should_remove {
elements.remove(&element.0.clone());
}
}
}
_ => return Err(vm.new_type_error("".to_string())),
}
Ok(zelf.clone())
}
fn set_symmetric_difference_update(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
set_ixor(vm, args)?;
Ok(vm.get_none())
}
fn set_ixor(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(zelf, Some(vm.ctx.set_type())), (iterable, None)]
);
let mut mut_obj = zelf.borrow_mut();
match mut_obj.payload {
PyObjectPayload::Set { ref mut elements } => {
let elements_original = elements.clone();
let iterator = objiter::get_iter(vm, iterable)?;
while let Ok(v) = vm.call_method(&iterator, "__next__", vec![]) {
insert_into_set(vm, elements, &v)?;
}
for element in elements_original.iter() {
let value = vm.call_method(iterable, "__contains__", vec![element.1.clone()])?;
if objbool::get_value(&value) {
elements.remove(&element.0.clone());
}
}
}
_ => return Err(vm.new_type_error("".to_string())),
}
Ok(zelf.clone())
}
fn set_iter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(zelf, Some(vm.ctx.set_type()))]);
let items = get_elements(zelf).values().map(|x| x.clone()).collect();
let set_list = vm.ctx.new_list(items);
let iter_obj = PyObject::new(
PyObjectPayload::Iterator {
position: 0,
iterated_obj: set_list,
},
vm.ctx.iter_type(),
);
Ok(iter_obj)
}
fn frozenset_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(o, Some(vm.ctx.frozenset_type()))]);
@@ -477,6 +626,29 @@ pub fn init(context: &PyContext) {
context.set_attr(&set_type, "remove", context.new_rustfunc(set_remove));
context.set_attr(&set_type, "discard", context.new_rustfunc(set_discard));
context.set_attr(&set_type, "clear", context.new_rustfunc(set_clear));
context.set_attr(&set_type, "copy", context.new_rustfunc(set_copy));
context.set_attr(&set_type, "pop", context.new_rustfunc(set_pop));
context.set_attr(&set_type, "update", context.new_rustfunc(set_update));
context.set_attr(&set_type, "__ior__", context.new_rustfunc(set_ior));
context.set_attr(
&set_type,
"intersection_update",
context.new_rustfunc(set_intersection_update),
);
context.set_attr(&set_type, "__iand__", context.new_rustfunc(set_iand));
context.set_attr(
&set_type,
"difference_update",
context.new_rustfunc(set_difference_update),
);
context.set_attr(&set_type, "__isub__", context.new_rustfunc(set_isub));
context.set_attr(
&set_type,
"symmetric_difference_update",
context.new_rustfunc(set_symmetric_difference_update),
);
context.set_attr(&set_type, "__ixor__", context.new_rustfunc(set_ixor));
context.set_attr(&set_type, "__iter__", context.new_rustfunc(set_iter));
let frozenset_type = &context.frozenset_type;
+3 -4
View File
@@ -1,9 +1,8 @@
use super::super::pyobject::{
use super::objint;
use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objint;
use super::objtype; // Required for arg_check! to use isinstance
use crate::vm::VirtualMachine;
use num_bigint::BigInt;
fn slice_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
+5 -5
View File
@@ -1,11 +1,11 @@
use super::super::format::{FormatParseError, FormatPart, FormatString};
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objint;
use super::objsequence::PySliceableSequence;
use super::objtype;
use crate::format::{FormatParseError, FormatPart, FormatString};
use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
};
use crate::vm::VirtualMachine;
use num_traits::ToPrimitive;
use std::cell::Ref;
use std::hash::{Hash, Hasher};
+2 -2
View File
@@ -6,9 +6,9 @@ https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/
*/
use super::super::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol};
use super::super::vm::VirtualMachine;
use super::objtype;
use crate::pyobject::{PyContext, PyFuncArgs, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
pub fn init(context: &PyContext) {
let super_type = &context.super_type;
+2 -4
View File
@@ -1,7 +1,3 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use super::super::vm::{ReprGuard, VirtualMachine};
use super::objbool;
use super::objint;
use super::objsequence::{
@@ -9,6 +5,8 @@ use super::objsequence::{
};
use super::objstr;
use super::objtype;
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol};
use crate::vm::{ReprGuard, VirtualMachine};
use std::hash::{Hash, Hasher};
fn tuple_lt(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
+5 -5
View File
@@ -1,11 +1,11 @@
use super::super::pyobject::{
AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload,
PyObjectRef, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objdict;
use super::objstr;
use super::objtype; // Required for arg_check! to use isinstance
use crate::pyobject::{
AttributeProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObject, PyObjectPayload,
PyObjectRef, PyResult, TypeProtocol,
};
use crate::vm::VirtualMachine;
use std::cell::RefCell;
use std::collections::HashMap;
+2 -5
View File
@@ -1,9 +1,6 @@
use super::super::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use super::objiter;
use super::objtype; // Required for arg_check! to use isinstance
use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol};
use crate::vm::VirtualMachine; // Required for arg_check! to use isinstance
fn zip_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
no_kwargs!(vm, args);
+32 -32
View File
@@ -1,35 +1,35 @@
use super::bytecode;
use super::exceptions;
use super::frame::Frame;
use super::obj::objbool;
use super::obj::objbytearray;
use super::obj::objbytes;
use super::obj::objcode;
use super::obj::objcomplex;
use super::obj::objdict;
use super::obj::objenumerate;
use super::obj::objfilter;
use super::obj::objfloat;
use super::obj::objframe;
use super::obj::objfunction;
use super::obj::objgenerator;
use super::obj::objint;
use super::obj::objiter;
use super::obj::objlist;
use super::obj::objmap;
use super::obj::objmemory;
use super::obj::objnone;
use super::obj::objobject;
use super::obj::objproperty;
use super::obj::objrange;
use super::obj::objset;
use super::obj::objslice;
use super::obj::objstr;
use super::obj::objsuper;
use super::obj::objtuple;
use super::obj::objtype;
use super::obj::objzip;
use super::vm::VirtualMachine;
use crate::bytecode;
use crate::exceptions;
use crate::frame::Frame;
use crate::obj::objbool;
use crate::obj::objbytearray;
use crate::obj::objbytes;
use crate::obj::objcode;
use crate::obj::objcomplex;
use crate::obj::objdict;
use crate::obj::objenumerate;
use crate::obj::objfilter;
use crate::obj::objfloat;
use crate::obj::objframe;
use crate::obj::objfunction;
use crate::obj::objgenerator;
use crate::obj::objint;
use crate::obj::objiter;
use crate::obj::objlist;
use crate::obj::objmap;
use crate::obj::objmemory;
use crate::obj::objnone;
use crate::obj::objobject;
use crate::obj::objproperty;
use crate::obj::objrange;
use crate::obj::objset;
use crate::obj::objslice;
use crate::obj::objstr;
use crate::obj::objsuper;
use crate::obj::objtuple;
use crate::obj::objtype;
use crate::obj::objzip;
use crate::vm::VirtualMachine;
use num_bigint::BigInt;
use num_bigint::ToBigInt;
use num_complex::Complex64;
+3 -3
View File
@@ -6,9 +6,9 @@
extern crate rustpython_parser;
use self::rustpython_parser::{ast, parser};
use super::super::obj::{objstr, objtype};
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::VirtualMachine;
use crate::obj::objstr;
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::VirtualMachine;
use num_complex::Complex64;
use std::ops::Deref;
+17
View File
@@ -0,0 +1,17 @@
use crate::obj::objcode;
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
fn dis_disassemble(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(co, Some(vm.ctx.code_type()))]);
let code = objcode::get_value(co);
print!("{}", code);
Ok(vm.get_none())
}
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
py_module!(ctx, "dis", {
"disassemble" => ctx.new_rustfunc(dis_disassemble)
})
}
+9 -10
View File
@@ -13,18 +13,17 @@ use num_bigint::ToBigInt;
use num_traits::ToPrimitive;
//custom imports
use super::super::obj::objbytes;
use super::super::obj::objint;
use super::super::obj::objstr;
use super::super::obj::objtype;
use super::os;
use crate::obj::objbytes;
use crate::obj::objint;
use crate::obj::objstr;
use super::super::pyobject::{
use crate::pyobject::{
AttributeProtocol, BufferProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef,
PyResult, TypeProtocol,
};
use super::super::vm::VirtualMachine;
use crate::vm::VirtualMachine;
fn compute_c_flag(mode: &str) -> u16 {
match mode {
@@ -421,18 +420,18 @@ pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
};
ctx.set_attr(&py_mod, "TextIOWrapper", text_io_wrapper.clone());
// BytesIO: in-memory bytes
//StringIO: in-memory text
let string_io = {
let string_io = ctx.new_class("StringIO", io_base.clone());
let string_io = ctx.new_class("StringIO", text_io_base.clone());
ctx.set_attr(&string_io, "__init__", ctx.new_rustfunc(string_io_init));
ctx.set_attr(&string_io, "getvalue", ctx.new_rustfunc(string_io_getvalue));
string_io
};
ctx.set_attr(&py_mod, "StringIO", string_io);
// StringIO: in-memory text
//BytesIO: in-memory bytes
let bytes_io = {
let bytes_io = ctx.new_class("BytesIO", io_base.clone());
let bytes_io = ctx.new_class("BytesIO", buffered_io_base.clone());
ctx.set_attr(&bytes_io, "__init__", ctx.new_rustfunc(bytes_io_init));
ctx.set_attr(&bytes_io, "getvalue", ctx.new_rustfunc(bytes_io_getvalue));
bytes_io
+3 -3
View File
@@ -5,12 +5,12 @@ use serde::de::{DeserializeSeed, Visitor};
use serde::ser::{SerializeMap, SerializeSeq};
use serde_json;
use super::super::obj::{objbool, objdict, objfloat, objint, objsequence, objstr, objtype};
use super::super::pyobject::{
use crate::obj::{objbool, objdict, objfloat, objint, objsequence, objstr, objtype};
use crate::pyobject::{
create_type, DictProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult,
TypeProtocol,
};
use super::super::VirtualMachine;
use crate::VirtualMachine;
use num_traits::cast::ToPrimitive;
// We need to have a VM available to serialise a PyObject based on its subclass, so we implement
+3 -3
View File
@@ -4,9 +4,9 @@
extern crate rustpython_parser;
use self::rustpython_parser::lexer;
use super::super::obj::{objstr, objtype};
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::VirtualMachine;
use crate::obj::objstr;
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::VirtualMachine;
fn keyword_iskeyword(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
+48 -50
View File
@@ -3,9 +3,9 @@
*
*/
use super::super::obj::{objfloat, objtype};
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::VirtualMachine;
use crate::obj::objfloat;
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::VirtualMachine;
use statrs::function::erf::{erf, erfc};
use statrs::function::gamma::{gamma, ln_gamma};
use std;
@@ -172,57 +172,55 @@ fn math_lgamma(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
}
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
let py_mod = ctx.new_module(&"math".to_string(), ctx.new_scope(None));
py_module!(ctx, "math", {
// Number theory functions:
"fabs" => ctx.new_rustfunc(math_fabs),
"isfinite" => ctx.new_rustfunc(math_isfinite),
"isinf" => ctx.new_rustfunc(math_isinf),
"isnan" => ctx.new_rustfunc(math_isnan),
// Number theory functions:
ctx.set_attr(&py_mod, "fabs", ctx.new_rustfunc(math_fabs));
ctx.set_attr(&py_mod, "isfinite", ctx.new_rustfunc(math_isfinite));
ctx.set_attr(&py_mod, "isinf", ctx.new_rustfunc(math_isinf));
ctx.set_attr(&py_mod, "isnan", ctx.new_rustfunc(math_isnan));
// Power and logarithmic functions:
"exp" => ctx.new_rustfunc(math_exp),
"expm1" => ctx.new_rustfunc(math_expm1),
"log" => ctx.new_rustfunc(math_log),
"log1p" => ctx.new_rustfunc(math_log1p),
"log2" => ctx.new_rustfunc(math_log2),
"log10" => ctx.new_rustfunc(math_log10),
"pow" => ctx.new_rustfunc(math_pow),
"sqrt" => ctx.new_rustfunc(math_sqrt),
// Power and logarithmic functions:
ctx.set_attr(&py_mod, "exp", ctx.new_rustfunc(math_exp));
ctx.set_attr(&py_mod, "expm1", ctx.new_rustfunc(math_expm1));
ctx.set_attr(&py_mod, "log", ctx.new_rustfunc(math_log));
ctx.set_attr(&py_mod, "log1p", ctx.new_rustfunc(math_log1p));
ctx.set_attr(&py_mod, "log2", ctx.new_rustfunc(math_log2));
ctx.set_attr(&py_mod, "log10", ctx.new_rustfunc(math_log10));
ctx.set_attr(&py_mod, "pow", ctx.new_rustfunc(math_pow));
ctx.set_attr(&py_mod, "sqrt", ctx.new_rustfunc(math_sqrt));
// Trigonometric functions:
"acos" => ctx.new_rustfunc(math_acos),
"asin" => ctx.new_rustfunc(math_asin),
"atan" => ctx.new_rustfunc(math_atan),
"atan2" => ctx.new_rustfunc(math_atan2),
"cos" => ctx.new_rustfunc(math_cos),
"hypot" => ctx.new_rustfunc(math_hypot),
"sin" => ctx.new_rustfunc(math_sin),
"tan" => ctx.new_rustfunc(math_tan),
// Trigonometric functions:
ctx.set_attr(&py_mod, "acos", ctx.new_rustfunc(math_acos));
ctx.set_attr(&py_mod, "asin", ctx.new_rustfunc(math_asin));
ctx.set_attr(&py_mod, "atan", ctx.new_rustfunc(math_atan));
ctx.set_attr(&py_mod, "atan2", ctx.new_rustfunc(math_atan2));
ctx.set_attr(&py_mod, "cos", ctx.new_rustfunc(math_cos));
ctx.set_attr(&py_mod, "hypot", ctx.new_rustfunc(math_hypot));
ctx.set_attr(&py_mod, "sin", ctx.new_rustfunc(math_sin));
ctx.set_attr(&py_mod, "tan", ctx.new_rustfunc(math_tan));
"degrees" => ctx.new_rustfunc(math_degrees),
"radians" => ctx.new_rustfunc(math_radians),
ctx.set_attr(&py_mod, "degrees", ctx.new_rustfunc(math_degrees));
ctx.set_attr(&py_mod, "radians", ctx.new_rustfunc(math_radians));
// Hyperbolic functions:
"acosh" => ctx.new_rustfunc(math_acosh),
"asinh" => ctx.new_rustfunc(math_asinh),
"atanh" => ctx.new_rustfunc(math_atanh),
"cosh" => ctx.new_rustfunc(math_cosh),
"sinh" => ctx.new_rustfunc(math_sinh),
"tanh" => ctx.new_rustfunc(math_tanh),
// Hyperbolic functions:
ctx.set_attr(&py_mod, "acosh", ctx.new_rustfunc(math_acosh));
ctx.set_attr(&py_mod, "asinh", ctx.new_rustfunc(math_asinh));
ctx.set_attr(&py_mod, "atanh", ctx.new_rustfunc(math_atanh));
ctx.set_attr(&py_mod, "cosh", ctx.new_rustfunc(math_cosh));
ctx.set_attr(&py_mod, "sinh", ctx.new_rustfunc(math_sinh));
ctx.set_attr(&py_mod, "tanh", ctx.new_rustfunc(math_tanh));
// Special functions:
"erf" => ctx.new_rustfunc(math_erf),
"erfc" => ctx.new_rustfunc(math_erfc),
"gamma" => ctx.new_rustfunc(math_gamma),
"lgamma" => ctx.new_rustfunc(math_lgamma),
// Special functions:
ctx.set_attr(&py_mod, "erf", ctx.new_rustfunc(math_erf));
ctx.set_attr(&py_mod, "erfc", ctx.new_rustfunc(math_erfc));
ctx.set_attr(&py_mod, "gamma", ctx.new_rustfunc(math_gamma));
ctx.set_attr(&py_mod, "lgamma", ctx.new_rustfunc(math_lgamma));
// Constants:
ctx.set_attr(&py_mod, "pi", ctx.new_float(std::f64::consts::PI)); // 3.14159...
ctx.set_attr(&py_mod, "e", ctx.new_float(std::f64::consts::E)); // 2.71..
ctx.set_attr(&py_mod, "tau", ctx.new_float(2.0 * std::f64::consts::PI));
ctx.set_attr(&py_mod, "inf", ctx.new_float(std::f64::INFINITY));
ctx.set_attr(&py_mod, "nan", ctx.new_float(std::f64::NAN));
py_mod
// Constants:
"pi" => ctx.new_float(std::f64::consts::PI), // 3.14159...
"e" => ctx.new_float(std::f64::consts::E), // 2.71..
"tau" => ctx.new_float(2.0 * std::f64::consts::PI),
"inf" => ctx.new_float(std::f64::INFINITY),
"nan" => ctx.new_float(std::f64::NAN)
})
}
+3 -1
View File
@@ -1,4 +1,5 @@
mod ast;
mod dis;
mod json;
mod keyword;
mod math;
@@ -17,13 +18,14 @@ pub mod io;
#[cfg(not(target_arch = "wasm32"))]
mod os;
use super::pyobject::{PyContext, PyObjectRef};
use crate::pyobject::{PyContext, PyObjectRef};
pub type StdlibInitFunc = fn(&PyContext) -> PyObjectRef;
pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
let mut modules = HashMap::new();
modules.insert("ast".to_string(), ast::mk_module as StdlibInitFunc);
modules.insert("dis".to_string(), dis::mk_module as StdlibInitFunc);
modules.insert("json".to_string(), json::mk_module as StdlibInitFunc);
modules.insert("keyword".to_string(), keyword::mk_module as StdlibInitFunc);
modules.insert("math".to_string(), math::mk_module as StdlibInitFunc);
+19 -10
View File
@@ -8,36 +8,35 @@ use std::io::ErrorKind;
use num_traits::cast::ToPrimitive;
//custom imports
use super::super::obj::objint;
use super::super::obj::objstr;
use super::super::obj::objtype;
// use super::super::obj::objdict;
use crate::obj::objint;
use crate::obj::objstr;
// use crate::obj::objdict;
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::vm::VirtualMachine;
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
#[cfg(target_family = "unix")]
#[cfg(unix)]
pub fn raw_file_number(handle: File) -> i64 {
use std::os::unix::io::IntoRawFd;
i64::from(handle.into_raw_fd())
}
#[cfg(target_family = "unix")]
#[cfg(unix)]
pub fn rust_file(raw_fileno: i64) -> File {
use std::os::unix::io::FromRawFd;
unsafe { File::from_raw_fd(raw_fileno as i32) }
}
#[cfg(target_family = "windows")]
#[cfg(windows)]
pub fn raw_file_number(handle: File) -> i64 {
use std::os::windows::io::IntoRawHandle;
handle.into_raw_handle() as i64
}
#[cfg(target_family = "windows")]
#[cfg(windows)]
pub fn rust_file(raw_fileno: i64) -> File {
use std::ffi::c_void;
use std::os::windows::io::FromRawHandle;
@@ -46,6 +45,16 @@ pub fn rust_file(raw_fileno: i64) -> File {
unsafe { File::from_raw_handle(raw_fileno as *mut c_void) }
}
#[cfg(all(not(unix), not(windows)))]
pub fn rust_file(raw_fileno: i64) -> File {
unimplemented!();
}
#[cfg(all(not(unix), not(windows)))]
pub fn raw_file_number(handle: File) -> i64 {
unimplemented!();
}
pub fn os_close(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(fileno, Some(vm.ctx.int_type()))]);
+3 -3
View File
@@ -10,9 +10,9 @@
extern crate byteorder;
use self::byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::super::obj::{objbool, objbytes, objfloat, objint, objstr, objtype};
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::VirtualMachine;
use crate::obj::{objbool, objbytes, objfloat, objint, objstr, objtype};
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::VirtualMachine;
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use std::io::{Cursor, Read, Write};
+10 -15
View File
@@ -2,23 +2,18 @@
extern crate rand;
use super::super::obj::{objfloat, objtype};
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::VirtualMachine;
use stdlib::random::rand::distributions::{Distribution, Normal};
use crate::obj::objfloat;
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::stdlib::random::rand::distributions::{Distribution, Normal};
use crate::VirtualMachine;
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
let py_mod = ctx.new_module(&"random".to_string(), ctx.new_scope(None));
ctx.set_attr(&py_mod, "gauss", ctx.new_rustfunc(random_gauss));
ctx.set_attr(
&py_mod,
"normalvariate",
ctx.new_rustfunc(random_normalvariate),
);
ctx.set_attr(&py_mod, "random", ctx.new_rustfunc(random_random));
// py_mod.set_attr("weibull", ctx.new_rustfunc(random_weibullvariate));
// TODO: implement more random functions.
py_mod
py_module!(ctx, "random", {
"guass" => ctx.new_rustfunc(random_gauss),
"normalvariate" => ctx.new_rustfunc(random_normalvariate),
"random" => ctx.new_rustfunc(random_random),
// "weibull", ctx.new_rustfunc(random_weibullvariate),
})
}
fn random_gauss(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
+3 -3
View File
@@ -8,9 +8,9 @@
extern crate regex;
use self::regex::Regex;
use super::super::obj::{objstr, objtype};
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::VirtualMachine;
use crate::obj::objstr;
use crate::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use crate::VirtualMachine;
fn re_match(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
// TODO:
+1 -1
View File
@@ -3,7 +3,7 @@
*
*/
use super::super::pyobject::{PyContext, PyObjectRef};
use crate::pyobject::{PyContext, PyObjectRef};
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
let py_mod = ctx.new_module(&"string".to_string(), ctx.new_scope(None));
Loaded 100 of 110 files, more files were not shown because too many files have changed in this diff. Show more