Compare commits

..

2 Commits

Author SHA1 Message Date
Shing Lyu
6435ab3ad4 Added explanation why we cp file to pkg 2018-12-09 20:12:41 +01:00
Shing Lyu
d2565cd1b0 Print to html with JS-side function 2018-12-09 20:11:27 +01:00
204 changed files with 4447 additions and 16316 deletions

View File

@@ -1,2 +0,0 @@
target
**/node_modules

4
.gitignore vendored
View File

@@ -1,10 +1,8 @@
/target
wasm/target
**/*.rs.bk
**/*.bytecode
__pycache__
**/*.pytest_cache
.*sw*
.repl_history.txt
.vscode
wasm-pack.log
.idea/

View File

@@ -1,3 +1,4 @@
language: rust
rust:
@@ -6,119 +7,84 @@ rust:
- nightly
script:
- cargo build --verbose --all
- cargo test --verbose --all
- cargo build --verbose --all
- cargo test --verbose --all
env:
# This is used to only capture the regular nightly test in allow_failures
- REGULAR_TEST=true
# This is used to only capture the regular nightly test in allow_failures
- REGULAR_TEST=true
cache: cargo
matrix:
fast_finish: true
include:
# To test the snippets, we use Travis' Python environment (because
# installing rust ourselves is a lot easier than installing Python)
- 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
env:
- TRAVIS_RUST_VERSION=stable
- REGULAR_TEST=false
- CODE_COVERAGE=false
script: tests/.travis-runner.sh
- 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
env:
- TRAVIS_RUST_VERSION=beta
- REGULAR_TEST=false
- CODE_COVERAGE=false
script: tests/.travis-runner.sh
- name: rustfmt
language: rust
rust: stable
cache: cargo
before_script:
- rustup component add rustfmt-preview
script:
# Code references the generated python.rs, so put something in
# place to make `cargo fmt` happy. (We use `echo` rather than
# `touch` because rustfmt complains about the empty file touch
# creates.)
- echo > parser/src/python.rs
- cargo fmt --all -- --check
env:
- REGULAR_TEST=false
- name: publish documentation
language: rust
rust: stable
cache: cargo
script:
- cargo doc --no-deps --all
if: branch = release
env:
- REGULAR_TEST=false
- DEPLOY_DOC=true
- name: WASM online demo
language: rust
rust: nightly
cache: cargo
install:
- nvm install node
# install wasm-pack
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
script:
- cd wasm/demo
- npm install
- npm run dist
if: branch = release
env:
- REGULAR_TEST=false
- DEPLOY_DEMO=true
- name: cargo-clippy
language: rust
rust: stable
cache: cargo
before_script:
- rustup component add clippy
script:
- 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
- name: cargo-clippy
include:
# To test the snippets, we use Travis' Python environment (because
# installing rust ourselves is a lot easier than installing Python)
- 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
env:
- TRAVIS_RUST_VERSION=stable
- REGULAR_TEST=false
script: tests/.travis-runner.sh
- 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
env:
- TRAVIS_RUST_VERSION=beta
- REGULAR_TEST=false
script: tests/.travis-runner.sh
- name: rustfmt
language: rust
rust: nightly
cache: cargo
before_script:
- rustup component add rustfmt-preview
script:
# Code references the generated python.rs, so put something in
# place to make `cargo fmt` happy. (We use `echo` rather than
# `touch` because rustfmt complains about the empty file touch
# creates.)
- echo > parser/src/python.rs
- cargo fmt --all -- --check
env:
- REGULAR_TEST=false
- name: publish documentation
language: rust
rust: stable
cache: cargo
script:
- cargo doc --no-deps --all
if: branch = release
env:
- REGULAR_TEST=false
- PUBLISH_DOC=true
- name: WASM online demo
language: rust
rust: nightly
cache: cargo
script:
- cd wasm
- bash release.sh
if: branch = release
env:
- REGULAR_TEST=false
- PUBLISH_DEMO=true
allow_failures:
- rust: nightly
env: REGULAR_TEST=true
deploy:
- provider: pages
@@ -126,20 +92,18 @@ deploy:
target-branch: master
local-dir: target/doc
skip-cleanup: true
# Set in the settings page of your repository, as a secure variable
github-token: $WEBSITE_GITHUB_TOKEN
github-token: $WEBSITE_GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable
keep-history: true
on:
branch: release
condition: $DEPLOY_DOC = true
condition: $PUBLISH_DOC = true
- provider: pages
repo: RustPython/demo
target-branch: master
local-dir: wasm/demo/dist
local-dir: wasm/app/dist
skip-cleanup: true
# Set in the settings page of your repository, as a secure variable
github-token: $WEBSITE_GITHUB_TOKEN
github-token: $WEBSITE_GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable
keep-history: true
on:
branch: release
condition: $DEPLOY_DEMO = true
condition: $PUBLISH_DEMO = true

357
Cargo.lock generated
View File

@@ -1,5 +1,3 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.6.4"
@@ -133,15 +131,6 @@ name = "byteorder"
version = "1.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "caseless"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cc"
version = "1.0.25"
@@ -207,7 +196,7 @@ name = "docopt"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -232,22 +221,10 @@ dependencies = [
"atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.2"
@@ -292,11 +269,6 @@ name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "generic-array"
version = "0.9.0"
@@ -305,14 +277,6 @@ dependencies = [
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heck"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "humantime"
version = "1.1.1"
@@ -334,14 +298,6 @@ name = "itoa"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "js-sys"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wasm-bindgen 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
@@ -404,29 +360,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.2.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lexical"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lexical-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lexical-core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.42"
@@ -481,14 +417,6 @@ name = "nodrop"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nom"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint"
version = "0.2.1"
@@ -514,16 +442,6 @@ dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.6"
@@ -669,19 +587,19 @@ dependencies = [
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.0.3"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -711,26 +629,9 @@ name = "rustc-demangle"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc_version_runtime"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustpython"
version = "0.0.1-pre-alpha.1"
version = "0.0.1"
dependencies = [
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -738,7 +639,6 @@ dependencies = [
"rustpython_parser 0.0.1",
"rustpython_vm 0.1.0",
"rustyline 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -759,39 +659,17 @@ version = "0.1.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"caseless 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lexical 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version_runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustpython_parser 0.0.1",
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"statrs 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustpython_wasm"
version = "0.1.0"
dependencies = [
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"js-sys 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustpython_parser 0.0.1",
"rustpython_vm 0.1.0",
"wasm-bindgen 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-futures 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"web-sys 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -812,7 +690,7 @@ dependencies = [
[[package]]
name = "ryu"
version = "0.2.7"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -820,19 +698,6 @@ name = "scoped_threadpool"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.66"
@@ -854,7 +719,7 @@ version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -874,24 +739,6 @@ name = "siphasher"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "sourcefile"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stackvector"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "static_assertions"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "statrs"
version = "0.10.0"
@@ -905,7 +752,7 @@ name = "string_cache"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -951,16 +798,6 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
version = "0.9.0"
@@ -989,14 +826,6 @@ dependencies = [
"wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termcolor"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
@@ -1017,10 +846,11 @@ dependencies = [
[[package]]
name = "thread_local"
version = "0.3.6"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1033,11 +863,6 @@ name = "ucd-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-normalization"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-segmentation"
version = "1.2.1"
@@ -1081,99 +906,6 @@ name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasm-bindgen"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wasm-bindgen-macro 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"js-sys 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-macro-support 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-backend 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasm-bindgen-webidl"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-backend 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "web-sys"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"js-sys 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-webidl 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "weedle"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.8"
@@ -1198,14 +930,6 @@ name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
@@ -1219,20 +943,6 @@ dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wincolor"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "xdg"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
@@ -1251,7 +961,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
"checksum caseless 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "808dab3318747be122cb31d36de18d4d1c81277a76f8332a02b81a3d73463d7f"
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
@@ -1264,27 +973,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum ena 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe5a5078ac8c506d3e4430763b1ba9b609b1286913e7d08e581d1c2de9b7e5"
"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a"
"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
"checksum js-sys 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58cfec35fd4a94f3cf357d5cb7da71c71cd52720c2f2a7320090a8db5f06f655"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lalrpop 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ba451f7bd819b7afc99d4cf4bdcd5a4861e64955ba9680ac70df3a50625ad6cf"
"checksum lalrpop-snap 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "60013fd6be14317d43f47658b1440956a9ca48a9ed0257e0e0a59aac13e43a1f"
"checksum lalrpop-util 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "60c6c48ba857cd700673ce88907cadcdd7e2cd7783ed02378537c5ffd4f6460c"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum lexical 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4fac65df7e751b57bb3a334c346239cb4ce2601907d698726ceeb82a54ba4ef"
"checksum lexical-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "025babf624c0c2b4bed1373efd684d5d0b2eecd61138d26ec3eec77bf0f2e33d"
"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac"
@@ -1292,11 +995,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
"checksum num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "10b8423ea72ec64751198856a853e07b37087cfc9b53a87ecb19bff67b6d1320"
"checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
@@ -1316,26 +1017,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
"checksum regex 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d8c9f33201f46669484bacc312b00e7541bed6aaf296dffe2bb4e0ac6b8ce2a"
"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rustc_version_runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6de8ecd7fad7731f306f69b6e10ec5a3178c61e464dcc06979427aa4cc891145"
"checksum rustyline 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6010155119d53aac4f5b987cb8f6ea913d0d64d9b237da36f8f96a90cb3f5385"
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
"checksum ryu 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c066b8e2923f05d4718a06d2622f189ff362bc642bfade6c6629f0440f3827"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95"
"checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79"
"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"
"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
"checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6"
"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
"checksum statrs 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "10102ac8d55e35db2b3fafc26f81ba8647da2e15879ab686a67e6d19af2685e8"
"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
"checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191"
@@ -1343,17 +1037,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc"
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83"
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
@@ -1362,21 +1053,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum wasm-bindgen 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "91f95b8f30407b9ca0c2de157281d3828bbed1fc1f55bea6eb54f40c52ec75ec"
"checksum wasm-bindgen-backend 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "ab7c242ebcb45bae45340986c48d1853eb2c1c52ff551f7724951b62a2c51429"
"checksum wasm-bindgen-futures 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d1784e7401a90119b2a4e8ec9c8d37c3594c3e3bb9ba24533ee1969eebaf0485"
"checksum wasm-bindgen-macro 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "6e353f83716dec9a3597b5719ef88cb6c9e461ec16528f38aa023d3224b4e569"
"checksum wasm-bindgen-macro-support 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc90b65fe69c3dd5a09684517dc79f42b847baa2d479c234d125e0a629d9b0a"
"checksum wasm-bindgen-shared 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "a71a37df4f5845025f96f279d20bbe5b19cbcb77f5410a3a90c6c544d889a162"
"checksum wasm-bindgen-webidl 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "b064b8b2336b5a6bf5f31bc95fc1310842395df29877d910cb6f8f791070f319"
"checksum web-sys 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d7c588c2e5a091bc4532c5a87032955f9133b644e868b54d08ead0185dcc5b9"
"checksum weedle 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26a4c67f132386d965390b8a734d5d10adbcd30eb5cc74bd9229af8b83f10044"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"

View File

@@ -1,11 +1,9 @@
[package]
name = "rustpython"
version = "0.0.1-pre-alpha.1"
version = "0.0.1"
authors = ["Windel Bouwman", "Shing Lyu <shing.lyu@gmail.com>"]
edition = "2018"
[workspace]
members = [".", "vm", "wasm/lib", "parser"]
[dependencies]
log="0.4.1"
@@ -14,7 +12,3 @@ clap = "2.31.2"
rustpython_parser = {path = "parser"}
rustpython_vm = {path = "vm"}
rustyline = "2.1.0"
xdg = "2.2.0"
[profile.release]
opt-level = "s"

View File

@@ -1,9 +0,0 @@
FROM rust:1.31-slim
WORKDIR /rustpython
COPY . .
RUN cargo build --release
CMD [ "/rustpython/target/release/rustpython" ]

View File

@@ -1,19 +0,0 @@
FROM rust:1.31-slim
RUN apt-get update && apt-get install curl gnupg -y && \
curl -o- https://deb.nodesource.com/setup_10.x | bash && \
apt-get install nodejs -y && \
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh && \
npm i -g serve
WORKDIR /rustpython
COPY . .
RUN cd ./wasm/lib/ && \
cargo build --release && \
cd ../demo && \
npm install && \
npm run dist
CMD [ "serve", "/rustpython/wasm/demo/dist" ]

111
README.md
View File

@@ -1,18 +1,13 @@
# RustPython
A Python-3 (CPython >= 3.5.0) Interpreter written in Rust :snake: :scream: :metal:.
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)
# Usage
### Check out our [online demo](https://rustpython.github.io/demo/) running on WebAssembly.
To test RustPython, do the following:
$ git clone https://github.com/RustPython/RustPython
@@ -27,13 +22,6 @@ 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
@@ -42,7 +30,7 @@ Or use the interactive shell:
# Documentation
Currently along with other areas of the project, documentation is still in an early phase.
Currently the project is in an early phase, and so is the documentation.
You can read the [online documentation](https://rustpython.github.io/website/rustpython/index.html) for the latest code on master.
@@ -55,32 +43,28 @@ $ 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.
# Code organization
- `parser/src`: python lexing, parsing and ast
- `vm/src`: python virtual machine
- `builtins.rs`: Builtin functions
- `compile.rs`: the python compiler from ast to bytecode
- `obj`: python builtin types
- `builtins.rs`: Builtin functions
- `compile.rs`: the python compiler from ast to bytecode
- `obj`: python builtin types
- `src`: using the other subcrates to bring rustpython to life.
- `docs`: documentation (work in progress)
- `py_code_object`: CPython bytecode to rustpython bytecode converter (work in progress)
- `wasm`: Binary crate and resources for WebAssembly build
- `py_code_object`: CPython bytecode to rustpython bytecode convertor (work in progress)
- `wasm`: Binary crate and resources for WebAssembly build
- `tests`: integration test snippets
# Contributing
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:
To start contributing, there are a lot of things that need to be done.
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 source code: builtin functions and object methods are often the simplest
and easiest way to contribute.
Another approach is to checkout the sourcecode: builtin functions and object methods are often the simplest
and easiest way to contribute.
You can also simply run
`cargo run tests/snippets/whats_left_to_implement.py` to assist in finding any
@@ -93,11 +77,11 @@ To test rustpython, there is a collection of python snippets located in the
```shell
$ cd tests
$ pipenv install
$ pipenv run pytest -v
$ pipenv shell
$ pytest -v
```
There also are some unit tests, you can run those with cargo:
There also are some unittests, you can run those will cargo:
```shell
$ cargo test --all
@@ -127,7 +111,8 @@ At this stage RustPython only has preliminary support for web assembly. The inst
## Setup
To get started, install [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) and `npm`. ([wasm-bindgen](https://rustwasm.github.io/wasm-bindgen/whirlwind-tour/basic-usage.html) should be installed by `wasm-pack`. if not, install it yourself)
To get started, install [wasm-bindgen](https://rustwasm.github.io/wasm-bindgen/whirlwind-tour/basic-usage.html)
and [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/). You will also need to have `npm` installed.
<!-- Using `rustup` add the compile target `wasm32-unknown-emscripten`. To do so you will need to have [rustup](https://rustup.rs/) installed.
@@ -145,53 +130,56 @@ cd emsdk-portable/
./emsdk activate sdk-incoming-64bit
``` -->
## Build
Move into the `wasm` directory. This directory contains a library crate for interop
with python to rust to js and back in `wasm/lib`, the demo website found at
https://rustpython.github.io/demo in `wasm/demo`, and an example of how to use
the crate as a library in one's own JS app in `wasm/example`.
Move into the `wasm` directory. This contains a custom library crate optimized for wasm build of RustPython.
```sh
```bash
cd wasm
```
Go to the demo directory. This is the best way of seeing the changes made to either
the library or the JS demo, as the `rustpython_wasm` module is set to the global
JS variable `rp` on the website.
From here run the build. This can take several minutes depending on the machine.
```sh
cd demo
```
wasm-pack build
```
Now, start the webpack development server. It'll compile the crate and then
the demo app. This will likely take a long time, both the wasm-pack portion and
the webpack portion (from after it says "Your crate has been correctly compiled"),
so be patient.
Upon successful build, cd in the the `/pkg` directory and run:
```sh
npm run dev
```
npm link
```
You can now open the webpage on https://localhost:8080 and Python code in either
the text box or browser devtools with:
Now move back out into the `/app` directory. The files here have been adapted from [wasm-pack-template](https://github.com/rustwasm/wasm-pack-template).
Finally, run:
```
npm install
npm link rustpython_wasm
```
and you will be able to run the files with:
```
node_modules/.bin/webpack-dev-server
```
Open a browser console and see the output of rustpython_wasm. To verify this, modify the line in `app/index.js`
```js
rp.pyEval(
`
print(js_vars['a'] * 9)
`,
{
vars: {
a: 9
}
}
);
rp.run_code("print('Hello Python!')\n");
```
Alternatively, you can run `npm run build` to build the app once, without watching
for changes, or `npm run dist` to build the app in release mode, both for the
crate and webpack.
To the following:
```js
rp.run_code("assert(False)\n");
```
and you should observe: `Execution failed` in your console output, indicating that the execution of RustPython has failed.
# Code style
@@ -214,3 +202,4 @@ These are some useful links to related projects:
- https://github.com/ProgVal/pythonvm-rust
- https://github.com/shinglyu/RustPython
- https://github.com/windelbouwman/rspython

View File

@@ -1,56 +0,0 @@
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'

View File

@@ -1,6 +1,6 @@
Byterun
* Builtins are exposed to frame.f_builtins
* Builtins are exposted to frame.f_builtins
* f_builtins is assigned during frame creation,
self.f_builtins = f_locals['__builtins__']
if hasattr(self.f_builtins, '__dict__'):
@@ -21,10 +21,10 @@ TODO:
* Implement a new type NativeFunction
* Wrap a function pointer in NativeFunction
* Refactor the CALL_FUNCTION case so it can call both python function and native function
* During frame creation, force push a native function `print` into the namespace
* During frame creation, force push a nativefunction `print` into the namespace
* Modify LOAD_* so they can search for names in builtins
* Create a module type
* In VM initialization, load the builtins module into locals
* During frame creation, create a field that contains the builtins dict
* During frame creation, create a field that conatins the builtins dict

View File

@@ -3,7 +3,6 @@ name = "rustpython_parser"
version = "0.0.1"
authors = [ "Shing Lyu", "Windel Bouwman" ]
build = "build.rs"
edition = "2018"
[build-dependencies]
lalrpop="0.15.1"

View File

@@ -1,4 +1,4 @@
use lalrpop;
extern crate lalrpop;
fn main() {
lalrpop::process_root().unwrap();

View File

@@ -65,9 +65,9 @@ pub enum Statement {
value: Expression,
},
AugAssign {
target: Box<Expression>,
target: Expression,
op: Operator,
value: Box<Expression>,
value: Expression,
},
Expression {
expression: Expression,
@@ -122,7 +122,6 @@ pub enum Statement {
// docstring: String,
body: Vec<LocatedStatement>,
decorator_list: Vec<Expression>,
returns: Option<Expression>,
},
}
@@ -198,7 +197,7 @@ pub enum Expression {
elements: Vec<Expression>,
},
String {
value: StringGroup,
value: String,
},
Bytes {
value: Vec<u8>,
@@ -218,74 +217,22 @@ pub enum Expression {
True,
False,
None,
Ellipsis,
}
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",
Ellipsis => "ellipsis",
}
}
}
/*
* In cpython this is called arguments, but we choose parameters to
* distinguish between function parameters and actual call arguments.
* distuingish between function parameters and actual call arguments.
*/
#[derive(Debug, PartialEq, Default)]
pub struct Parameters {
pub args: Vec<Parameter>,
pub kwonlyargs: Vec<Parameter>,
pub vararg: Option<Option<Parameter>>, // Optionally we handle optionally named '*args' or '*'
pub kwarg: Option<Option<Parameter>>,
pub args: Vec<String>,
pub kwonlyargs: Vec<String>,
pub vararg: Option<Option<String>>, // Optionally we handle optionally named '*args' or '*'
pub kwarg: Option<Option<String>>,
pub defaults: Vec<Expression>,
pub kw_defaults: Vec<Option<Expression>>,
}
#[derive(Debug, PartialEq, Default)]
pub struct Parameter {
pub arg: String,
pub annotation: Option<Box<Expression>>,
}
#[derive(Debug, PartialEq)]
pub enum ComprehensionKind {
GeneratorExpression { element: Expression },
@@ -365,29 +312,3 @@ pub enum Number {
Float { value: f64 },
Complex { real: f64, imag: f64 },
}
/// Transforms a value prior to formatting it.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ConversionFlag {
/// Converts by calling `str(<value>)`.
Str,
/// Converts by calling `ascii(<value>)`.
Ascii,
/// Converts by calling `repr(<value>)`.
Repr,
}
#[derive(Debug, PartialEq)]
pub enum StringGroup {
Constant {
value: String,
},
FormattedValue {
value: Box<Expression>,
conversion: Option<ConversionFlag>,
spec: String,
},
Joined {
values: Vec<StringGroup>,
},
}

View File

@@ -1,79 +0,0 @@
//! Define internal parse error types
//! The goal is to provide a matching and a safe error API, maksing errors from LALR
extern crate lalrpop_util;
use self::lalrpop_util::ParseError as InnerError;
use crate::lexer::{LexicalError, Location};
use crate::token::Tok;
use std::error::Error;
use std::fmt;
// A token of type `Tok` was observed, with a span given by the two Location values
type TokSpan = (Location, Tok, Location);
/// Represents an error during parsing
#[derive(Debug, PartialEq)]
pub enum ParseError {
/// Parser encountered an unexpected end of input
EOF(Option<Location>),
/// Parser encountered an extra token
ExtraToken(TokSpan),
/// Parser encountered an invalid token
InvalidToken(Location),
/// Parser encountered an unexpected token
UnrecognizedToken(TokSpan, Vec<String>),
/// Maps to `User` type from `lalrpop-util`
Other,
}
/// Convert `lalrpop_util::ParseError` to our internal type
impl From<InnerError<Location, Tok, LexicalError>> for ParseError {
fn from(err: InnerError<Location, Tok, LexicalError>) -> Self {
match err {
// TODO: Are there cases where this isn't an EOF?
InnerError::InvalidToken { location } => ParseError::EOF(Some(location)),
InnerError::ExtraToken { token } => ParseError::ExtraToken(token),
// Inner field is a unit-like enum `LexicalError::StringError` with no useful info
InnerError::User { .. } => ParseError::Other,
InnerError::UnrecognizedToken { token, expected } => {
match token {
Some(tok) => ParseError::UnrecognizedToken(tok, expected),
// EOF was observed when it was unexpected
None => ParseError::EOF(None),
}
}
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ParseError::EOF(ref location) => {
if let Some(l) = location {
write!(f, "Got unexpected EOF at: {:?}", l)
} else {
write!(f, "Got unexpected EOF")
}
}
ParseError::ExtraToken(ref t_span) => {
write!(f, "Got extraneous token: {:?} at: {:?}", t_span.1, t_span.0)
}
ParseError::InvalidToken(ref location) => {
write!(f, "Got invalid token at: {:?}", location)
}
ParseError::UnrecognizedToken(ref t_span, _) => {
write!(f, "Got unexpected token: {:?} at {:?}", t_span.1, t_span.0)
}
// This is user defined, it probably means a more useful error should have been given upstream.
ParseError::Other => write!(f, "Got unsupported token(s)"),
}
}
}
impl Error for ParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}

View File

@@ -1,234 +0,0 @@
use std::iter;
use std::mem;
use std::str;
use lalrpop_util::ParseError as LalrpopError;
use crate::ast::{ConversionFlag, StringGroup};
use crate::lexer::{LexicalError, Location, Tok};
use crate::parser::parse_expression;
use self::FStringError::*;
use self::StringGroup::*;
// TODO: consolidate these with ParseError
#[derive(Debug, PartialEq)]
pub enum FStringError {
UnclosedLbrace,
UnopenedRbrace,
InvalidExpression,
InvalidConversionFlag,
EmptyExpression,
MismatchedDelimiter,
}
impl From<FStringError> for LalrpopError<Location, Tok, LexicalError> {
fn from(_err: FStringError) -> Self {
lalrpop_util::ParseError::User {
error: LexicalError::StringError,
}
}
}
struct FStringParser<'a> {
chars: iter::Peekable<str::Chars<'a>>,
}
impl<'a> FStringParser<'a> {
fn new(source: &'a str) -> Self {
Self {
chars: source.chars().peekable(),
}
}
fn parse_formatted_value(&mut self) -> Result<StringGroup, FStringError> {
let mut expression = String::new();
let mut spec = String::new();
let mut delims = Vec::new();
let mut conversion = None;
while let Some(ch) = self.chars.next() {
match ch {
'!' if delims.is_empty() => {
conversion = Some(match self.chars.next() {
Some('s') => ConversionFlag::Str,
Some('a') => ConversionFlag::Ascii,
Some('r') => ConversionFlag::Repr,
Some(_) => {
return Err(InvalidConversionFlag);
}
None => {
break;
}
})
}
':' if delims.is_empty() => {
while let Some(&next) = self.chars.peek() {
if next != '}' {
spec.push(next);
self.chars.next();
} else {
break;
}
}
}
'(' | '{' | '[' => {
expression.push(ch);
delims.push(ch);
}
')' => {
if delims.pop() != Some('(') {
return Err(MismatchedDelimiter);
}
expression.push(ch);
}
']' => {
if delims.pop() != Some('[') {
return Err(MismatchedDelimiter);
}
expression.push(ch);
}
'}' if !delims.is_empty() => {
if delims.pop() != Some('{') {
return Err(MismatchedDelimiter);
}
expression.push(ch);
}
'}' => {
if expression.is_empty() {
return Err(EmptyExpression);
}
return Ok(FormattedValue {
value: Box::new(
parse_expression(expression.trim()).map_err(|_| InvalidExpression)?,
),
conversion,
spec,
});
}
'"' | '\'' => {
expression.push(ch);
while let Some(next) = self.chars.next() {
expression.push(next);
if next == ch {
break;
}
}
}
_ => {
expression.push(ch);
}
}
}
Err(UnclosedLbrace)
}
fn parse(mut self) -> Result<StringGroup, FStringError> {
let mut content = String::new();
let mut values = vec![];
while let Some(ch) = self.chars.next() {
match ch {
'{' => {
if let Some('{') = self.chars.peek() {
self.chars.next();
content.push('{');
} else {
if !content.is_empty() {
values.push(Constant {
value: mem::replace(&mut content, String::new()),
});
}
values.push(self.parse_formatted_value()?);
}
}
'}' => {
if let Some('}') = self.chars.peek() {
self.chars.next();
content.push('}');
} else {
return Err(UnopenedRbrace);
}
}
_ => {
content.push(ch);
}
}
}
if !content.is_empty() {
values.push(Constant { value: content })
}
Ok(match values.len() {
0 => Constant {
value: String::new(),
},
1 => values.into_iter().next().unwrap(),
_ => Joined { values },
})
}
}
pub fn parse_fstring(source: &str) -> Result<StringGroup, FStringError> {
FStringParser::new(source).parse()
}
#[cfg(test)]
mod tests {
use crate::ast;
use super::*;
fn mk_ident(name: &str) -> ast::Expression {
ast::Expression::Identifier {
name: name.to_owned(),
}
}
#[test]
fn test_parse_fstring() {
let source = String::from("{a}{ b }{{foo}}");
let parse_ast = parse_fstring(&source).unwrap();
assert_eq!(
parse_ast,
Joined {
values: vec![
FormattedValue {
value: Box::new(mk_ident("a")),
conversion: None,
spec: String::new(),
},
FormattedValue {
value: Box::new(mk_ident("b")),
conversion: None,
spec: String::new(),
},
Constant {
value: "{foo}".to_owned()
}
]
}
);
}
#[test]
fn test_parse_empty_fstring() {
assert_eq!(
parse_fstring(""),
Ok(Constant {
value: String::new(),
}),
);
}
#[test]
fn test_parse_invalid_fstring() {
assert_eq!(parse_fstring("{"), Err(UnclosedLbrace));
assert_eq!(parse_fstring("}"), Err(UnopenedRbrace));
assert_eq!(parse_fstring("{class}"), Err(InvalidExpression));
}
}

View File

@@ -1,50 +1,17 @@
//! This module takes care of lexing python source text. This means source
//! code is translated into separate tokens.
//! code is translated into seperate tokens.
pub use super::token::Tok;
use num_bigint::BigInt;
use num_traits::Num;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::str::FromStr;
#[derive(Clone, Copy, PartialEq, Debug)]
struct IndentationLevel {
tabs: usize,
spaces: usize,
}
impl IndentationLevel {
fn new() -> IndentationLevel {
IndentationLevel { tabs: 0, spaces: 0 }
}
fn compare_strict(&self, other: &IndentationLevel) -> Option<Ordering> {
// We only know for sure that we're smaller or bigger if tabs
// and spaces both differ in the same direction. Otherwise we're
// dependent on the size of tabs.
if self.tabs < other.tabs {
if self.spaces <= other.spaces {
Some(Ordering::Less)
} else {
None
}
} else if self.tabs > other.tabs {
if self.spaces >= other.spaces {
Some(Ordering::Greater)
} else {
None
}
} else {
Some(self.spaces.cmp(&other.spaces))
}
}
}
pub struct Lexer<T: Iterator<Item = char>> {
chars: T,
at_begin_of_line: bool,
nesting: usize, // Amount of parenthesis
indentation_stack: Vec<IndentationLevel>,
indentation_stack: Vec<usize>,
pending: Vec<Spanned<Tok>>,
chr0: Option<char>,
chr1: Option<char>,
@@ -54,8 +21,6 @@ pub struct Lexer<T: Iterator<Item = char>> {
#[derive(Debug)]
pub enum LexicalError {
StringError,
NestingError,
UnrecognizedToken { tok: char },
}
#[derive(Clone, Debug, Default, PartialEq)]
@@ -66,7 +31,10 @@ pub struct Location {
impl Location {
pub fn new(row: usize, column: usize) -> Self {
Location { row, column }
Location {
row: row,
column: column,
}
}
pub fn get_row(&self) -> usize {
@@ -125,7 +93,8 @@ pub type Spanned<Tok> = Result<(Location, Tok, Location), LexicalError>;
pub fn make_tokenizer<'a>(source: &'a str) -> impl Iterator<Item = Spanned<Tok>> + 'a {
let nlh = NewlineHandler::new(source.chars());
let lch = LineContinationHandler::new(nlh);
Lexer::new(lch)
let lexer = Lexer::new(lch);
lexer
}
// The newline handler is an iterator which collapses different newline
@@ -142,7 +111,7 @@ where
{
pub fn new(source: T) -> Self {
let mut nlh = NewlineHandler {
source,
source: source,
chr0: None,
chr1: None,
};
@@ -198,7 +167,7 @@ where
{
pub fn new(source: T) -> Self {
let mut nlh = LineContinationHandler {
source,
source: source,
chr0: None,
chr1: None,
};
@@ -249,7 +218,7 @@ where
chars: input,
at_begin_of_line: true,
nesting: 0,
indentation_stack: vec![IndentationLevel::new()],
indentation_stack: vec![0],
pending: Vec::new(),
chr0: None,
location: Location::new(0, 0),
@@ -275,6 +244,7 @@ where
let mut saw_f = false;
loop {
// Detect r"", f"", b"" and u""
// TODO: handle f-strings
if !(saw_b || saw_u || saw_f) && (self.chr0 == Some('b') || self.chr0 == Some('B')) {
saw_b = true;
} else if !(saw_b || saw_r || saw_u || saw_f)
@@ -310,7 +280,7 @@ where
if keywords.contains_key(&name) {
Ok((start_pos, keywords.remove(&name).unwrap(), end_pos))
} else {
Ok((start_pos, Tok::Name { name }, end_pos))
Ok((start_pos, Tok::Name { name: name }, end_pos))
}
}
@@ -355,7 +325,7 @@ where
let end_pos = self.get_pos();
let value = BigInt::from_str_radix(&value_text, radix).unwrap();
Ok((start_pos, Tok::Int { value }, end_pos))
Ok((start_pos, Tok::Int { value: value }, end_pos))
}
fn lex_normal_number(&mut self) -> Spanned<Tok> {
@@ -407,7 +377,7 @@ where
))
} else {
let end_pos = self.get_pos();
Ok((start_pos, Tok::Float { value }, end_pos))
Ok((start_pos, Tok::Float { value: value }, end_pos))
}
} else {
// Parse trailing 'j':
@@ -415,11 +385,18 @@ where
self.next_char();
let end_pos = self.get_pos();
let imag = f64::from_str(&value_text).unwrap();
Ok((start_pos, Tok::Complex { real: 0.0, imag }, end_pos))
Ok((
start_pos,
Tok::Complex {
real: 0.0,
imag: imag,
},
end_pos,
))
} else {
let end_pos = self.get_pos();
let value = value_text.parse::<BigInt>().unwrap();
Ok((start_pos, Tok::Int { value }, end_pos))
Ok((start_pos, Tok::Int { value: value }, end_pos))
}
}
}
@@ -429,7 +406,9 @@ where
self.next_char();
loop {
match self.chr0 {
Some('\n') => return,
Some('\n') => {
return;
}
Some(_) => {}
None => return,
}
@@ -442,7 +421,7 @@ where
is_bytes: bool,
is_raw: bool,
_is_unicode: bool,
is_fstring: bool,
_is_fstring: bool,
) -> Spanned<Tok> {
let quote_char = self.next_char().unwrap();
let mut string_content = String::new();
@@ -533,37 +512,36 @@ where
} else {
Tok::String {
value: string_content,
is_fstring,
}
};
Ok((start_pos, tok, end_pos))
return Ok((start_pos, tok, end_pos));
}
fn is_char(&self) -> bool {
match self.chr0 {
Some('a'..='z') | Some('A'..='Z') | Some('_') | Some('0'..='9') => true,
_ => false,
Some('a'...'z') | Some('A'...'Z') | Some('_') | Some('0'...'9') => return true,
_ => return false,
}
}
fn is_number(&self, radix: u32) -> bool {
match radix {
2 => match self.chr0 {
Some('0'..='1') => true,
_ => false,
Some('0'...'1') => return true,
_ => return false,
},
8 => match self.chr0 {
Some('0'..='7') => true,
_ => false,
Some('0'...'7') => return true,
_ => return false,
},
10 => match self.chr0 {
Some('0'..='9') => true,
_ => false,
Some('0'...'9') => return true,
_ => return false,
},
16 => match self.chr0 {
Some('0'..='9') | Some('a'..='f') | Some('A'..='F') => true,
_ => false,
Some('0'...'9') | Some('a'...'f') | Some('A'...'F') => return true,
_ => return false,
},
x => unimplemented!("Radix not implemented: {}", x),
}
@@ -598,23 +576,12 @@ where
self.at_begin_of_line = false;
// Determine indentation:
let mut spaces: usize = 0;
let mut tabs: usize = 0;
let mut col: usize = 0;
loop {
match self.chr0 {
Some(' ') => {
self.next_char();
spaces += 1;
}
Some('\t') => {
if spaces != 0 {
// Don't allow tabs after spaces as part of indentation.
// This is technically stricter than python3 but spaces before
// tabs is even more insane than mixing spaces and tabs.
panic!("Tabs not allowed as part of indentation after spaces");
}
self.next_char();
tabs += 1;
col += 1;
}
Some('#') => {
self.lex_comment();
@@ -634,63 +601,41 @@ where
}
}
let indentation_level = IndentationLevel { spaces, tabs };
if self.nesting == 0 {
// Determine indent or dedent:
let current_indentation = *self.indentation_stack.last().unwrap();
let ordering = indentation_level.compare_strict(&current_indentation);
match ordering {
Some(Ordering::Equal) => {
// Same same
}
Some(Ordering::Greater) => {
// New indentation level:
self.indentation_stack.push(indentation_level);
if col == current_indentation {
// Same same
} else if col > current_indentation {
// New indentation level:
self.indentation_stack.push(col);
let tok_start = self.get_pos();
let tok_end = tok_start.clone();
return Some(Ok((tok_start, Tok::Indent, tok_end)));
} else if col < current_indentation {
// One or more dedentations
// Pop off other levels until col is found:
while col < *self.indentation_stack.last().unwrap() {
self.indentation_stack.pop().unwrap();
let tok_start = self.get_pos();
let tok_end = tok_start.clone();
return Some(Ok((tok_start, Tok::Indent, tok_end)));
self.pending.push(Ok((tok_start, Tok::Dedent, tok_end)));
}
Some(Ordering::Less) => {
// One or more dedentations
// Pop off other levels until col is found:
loop {
let ordering = indentation_level
.compare_strict(self.indentation_stack.last().unwrap());
match ordering {
Some(Ordering::Less) => {
self.indentation_stack.pop();
let tok_start = self.get_pos();
let tok_end = tok_start.clone();
self.pending.push(Ok((tok_start, Tok::Dedent, tok_end)));
}
None => {
panic!("inconsistent use of tabs and spaces in indentation")
}
_ => {
break;
}
};
}
if indentation_level != *self.indentation_stack.last().unwrap() {
// TODO: handle wrong indentations
panic!("Non matching indentation levels!");
}
return Some(self.pending.remove(0));
if col != *self.indentation_stack.last().unwrap() {
// TODO: handle wrong indentations
panic!("Non matching indentation levels!");
}
None => panic!("inconsistent use of tabs and spaces in indentation"),
return Some(self.pending.remove(0));
}
}
}
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;
@@ -719,13 +664,16 @@ where
Some('+') => {
let tok_start = self.get_pos();
self.next_char();
if let Some('=') = self.chr0 {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::PlusEqual, tok_end)));
} else {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Plus, tok_end)));
match self.chr0 {
Some('=') => {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::PlusEqual, tok_end)));
}
_ => {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Plus, tok_end)));
}
}
}
Some('*') => {
@@ -789,49 +737,61 @@ where
Some('%') => {
let tok_start = self.get_pos();
self.next_char();
if let Some('=') = self.chr0 {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::PercentEqual, tok_end)));
} else {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Percent, tok_end)));
match self.chr0 {
Some('=') => {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::PercentEqual, tok_end)));
}
_ => {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Percent, tok_end)));
}
}
}
Some('|') => {
let tok_start = self.get_pos();
self.next_char();
if let Some('=') = self.chr0 {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::VbarEqual, tok_end)));
} else {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Vbar, tok_end)));
match self.chr0 {
Some('=') => {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::VbarEqual, tok_end)));
}
_ => {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Vbar, tok_end)));
}
}
}
Some('^') => {
let tok_start = self.get_pos();
self.next_char();
if let Some('=') = self.chr0 {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::CircumflexEqual, tok_end)));
} else {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::CircumFlex, tok_end)));
match self.chr0 {
Some('=') => {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::CircumflexEqual, tok_end)));
}
_ => {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::CircumFlex, tok_end)));
}
}
}
Some('&') => {
let tok_start = self.get_pos();
self.next_char();
if let Some('=') = self.chr0 {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::AmperEqual, tok_end)));
} else {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Amper, tok_end)));
match self.chr0 {
Some('=') => {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::AmperEqual, tok_end)));
}
_ => {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Amper, tok_end)));
}
}
}
Some('-') => {
@@ -857,13 +817,16 @@ where
Some('@') => {
let tok_start = self.get_pos();
self.next_char();
if let Some('=') = self.chr0 {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::AtEqual, tok_end)));
} else {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::At, tok_end)));
match self.chr0 {
Some('=') => {
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::AtEqual, tok_end)));
}
_ => {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::At, tok_end)));
}
}
}
Some('!') => {
@@ -888,9 +851,6 @@ where
}
Some(')') => {
let result = self.eat_single_char(Tok::Rpar);
if self.nesting == 0 {
return Some(Err(LexicalError::NestingError));
}
self.nesting -= 1;
return Some(result);
}
@@ -901,9 +861,6 @@ where
}
Some(']') => {
let result = self.eat_single_char(Tok::Rsqb);
if self.nesting == 0 {
return Some(Err(LexicalError::NestingError));
}
self.nesting -= 1;
return Some(result);
}
@@ -914,9 +871,6 @@ where
}
Some('}') => {
let result = self.eat_single_char(Tok::Rbrace);
if self.nesting == 0 {
return Some(Err(LexicalError::NestingError));
}
self.nesting -= 1;
return Some(result);
}
@@ -993,15 +947,8 @@ where
Some('.') => {
let tok_start = self.get_pos();
self.next_char();
if let (Some('.'), Some('.')) = (&self.chr0, &self.chr1) {
self.next_char();
self.next_char();
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Ellipsis, tok_end)));
} else {
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Dot, tok_end)));
}
let tok_end = self.get_pos();
return Some(Ok((tok_start, Tok::Dot, tok_end)));
}
Some('\n') => {
let tok_start = self.get_pos();
@@ -1025,7 +972,7 @@ where
None => return None,
_ => {
let c = self.next_char();
return Some(Err(LexicalError::UnrecognizedToken { tok: c.unwrap() }));
panic!("Not impl {:?}", c)
} // Ignore all the rest..
}
}
@@ -1100,11 +1047,9 @@ mod tests {
vec![
Tok::String {
value: "\\\\".to_string(),
is_fstring: false,
},
Tok::String {
value: "\\".to_string(),
is_fstring: false,
}
]
);
@@ -1288,56 +1233,12 @@ mod tests {
}
}
macro_rules! test_double_dedent_with_tabs {
($($name:ident: $eol:expr,)*) => {
$(
#[test]
fn $name() {
let source = String::from(format!("def foo():{}\tif x:{}{}\t return 99{}{}", $eol, $eol, $eol, $eol, $eol));
let tokens = lex_source(&source);
assert_eq!(
tokens,
vec![
Tok::Def,
Tok::Name {
name: String::from("foo"),
},
Tok::Lpar,
Tok::Rpar,
Tok::Colon,
Tok::Newline,
Tok::Indent,
Tok::If,
Tok::Name {
name: String::from("x"),
},
Tok::Colon,
Tok::Newline,
Tok::Indent,
Tok::Return,
Tok::Int { value: BigInt::from(99) },
Tok::Newline,
Tok::Dedent,
Tok::Dedent,
]
);
}
)*
}
}
test_double_dedent_with_eol! {
test_double_dedent_windows_eol: WINDOWS_EOL,
test_double_dedent_mac_eol: MAC_EOL,
test_double_dedent_unix_eol: UNIX_EOL,
}
test_double_dedent_with_tabs! {
test_double_dedent_tabs_windows_eol: WINDOWS_EOL,
test_double_dedent_tabs_mac_eol: MAC_EOL,
test_double_dedent_tabs_unix_eol: UNIX_EOL,
}
macro_rules! test_newline_in_brackets {
($($name:ident: $eol:expr,)*) => {
$(
@@ -1396,27 +1297,21 @@ mod tests {
vec![
Tok::String {
value: String::from("double"),
is_fstring: false,
},
Tok::String {
value: String::from("single"),
is_fstring: false,
},
Tok::String {
value: String::from("can't"),
is_fstring: false,
},
Tok::String {
value: String::from("\\\""),
is_fstring: false,
},
Tok::String {
value: String::from("\t\r\n"),
is_fstring: false,
},
Tok::String {
value: String::from("\\g"),
is_fstring: false,
},
]
);
@@ -1434,7 +1329,6 @@ mod tests {
vec![
Tok::String {
value: String::from("abcdef"),
is_fstring: false,
},
]
)

View File

@@ -1,11 +1,13 @@
#[macro_use]
extern crate log;
extern crate num_bigint;
extern crate num_traits;
pub mod ast;
pub mod error;
mod fstring;
pub mod lexer;
pub mod parser;
#[cfg_attr(rustfmt, rustfmt_skip)]
mod python;
pub mod token;
pub use self::parser::parse;

View File

@@ -1,10 +1,30 @@
use std::iter;
extern crate lalrpop_util;
use crate::ast;
use crate::error::ParseError;
use crate::lexer;
use crate::python;
use crate::token;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::iter;
use std::path::Path;
use super::ast;
use super::lexer;
use super::python;
use super::token;
pub fn read_file(filename: &Path) -> Result<String, String> {
info!("Loading file {:?}", filename);
match File::open(&filename) {
Ok(mut file) => {
let mut s = String::new();
match file.read_to_string(&mut s) {
Err(why) => Err(String::from("Reading file failed: ") + why.description()),
Ok(_) => Ok(s),
}
}
Err(why) => Err(String::from("Opening file failed: ") + why.description()),
}
}
/*
* Parse python code.
@@ -12,6 +32,13 @@ use crate::token;
* https://github.com/antlr/grammars-v4/tree/master/python3
*/
pub fn parse(filename: &Path) -> Result<ast::Program, String> {
info!("Parsing: {}", filename.display());
let txt = read_file(filename)?;
debug!("Read contents of file: {}", txt);
parse_program(&txt)
}
macro_rules! do_lalr_parsing {
($input: expr, $pat: ident, $tok: ident) => {{
let lxr = lexer::make_tokenizer($input);
@@ -19,7 +46,7 @@ macro_rules! do_lalr_parsing {
let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
match python::TopParser::new().parse(tokenizer) {
Err(err) => Err(ParseError::from(err)),
Err(why) => Err(format!("{:?}", why)),
Ok(top) => {
if let ast::Top::$pat(x) = top {
Ok(x)
@@ -31,11 +58,11 @@ macro_rules! do_lalr_parsing {
}};
}
pub fn parse_program(source: &str) -> Result<ast::Program, ParseError> {
pub fn parse_program(source: &str) -> Result<ast::Program, String> {
do_lalr_parsing!(source, Program, StartProgram)
}
pub fn parse_statement(source: &str) -> Result<ast::LocatedStatement, ParseError> {
pub fn parse_statement(source: &str) -> Result<ast::LocatedStatement, String> {
do_lalr_parsing!(source, Statement, StartStatement)
}
@@ -61,7 +88,7 @@ pub fn parse_statement(source: &str) -> Result<ast::LocatedStatement, ParseError
/// expr);
///
/// ```
pub fn parse_expression(source: &str) -> Result<ast::Expression, ParseError> {
pub fn parse_expression(source: &str) -> Result<ast::Expression, String> {
do_lalr_parsing!(source, Expression, StartExpression)
}
@@ -76,6 +103,7 @@ mod tests {
#[test]
fn test_parse_empty() {
let parse_ast = parse_program(&String::from("\n"));
assert_eq!(parse_ast, Ok(ast::Program { statements: vec![] }))
}
@@ -94,9 +122,7 @@ mod tests {
name: String::from("print"),
}),
args: vec![ast::Expression::String {
value: ast::StringGroup::Constant {
value: String::from("Hello world")
}
value: String::from("Hello world"),
}],
keywords: vec![],
},
@@ -122,9 +148,7 @@ mod tests {
}),
args: vec![
ast::Expression::String {
value: ast::StringGroup::Constant {
value: String::from("Hello world"),
}
value: String::from("Hello world"),
},
ast::Expression::Number {
value: ast::Number::Integer {
@@ -155,9 +179,7 @@ mod tests {
name: String::from("my_func"),
}),
args: vec![ast::Expression::String {
value: ast::StringGroup::Constant {
value: String::from("positional"),
}
value: String::from("positional"),
}],
keywords: vec![ast::Keyword {
name: Some("keyword".to_string()),
@@ -244,16 +266,7 @@ mod tests {
node: ast::Statement::Expression {
expression: ast::Expression::Lambda {
args: ast::Parameters {
args: vec![
ast::Parameter {
arg: String::from("x"),
annotation: None,
},
ast::Parameter {
arg: String::from("y"),
annotation: None,
}
],
args: vec![String::from("x"), String::from("y")],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
@@ -315,9 +328,7 @@ mod tests {
#[test]
fn test_parse_class() {
let source = String::from(
"class Foo(A, B):\n def __init__(self):\n pass\n def method_with_default(self, arg='default'):\n pass\n",
);
let source = String::from("class Foo(A, B):\n def __init__(self):\n pass\n def method_with_default(self, arg='default'):\n pass\n");
assert_eq!(
parse_statement(&source),
Ok(ast::LocatedStatement {
@@ -339,10 +350,7 @@ mod tests {
node: ast::Statement::FunctionDef {
name: String::from("__init__"),
args: ast::Parameters {
args: vec![ast::Parameter {
arg: String::from("self"),
annotation: None,
}],
args: vec![String::from("self")],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
@@ -354,7 +362,6 @@ mod tests {
node: ast::Statement::Pass,
}],
decorator_list: vec![],
returns: None,
}
},
ast::LocatedStatement {
@@ -362,23 +369,12 @@ mod tests {
node: ast::Statement::FunctionDef {
name: String::from("method_with_default"),
args: ast::Parameters {
args: vec![
ast::Parameter {
arg: String::from("self"),
annotation: None,
},
ast::Parameter {
arg: String::from("arg"),
annotation: None,
}
],
args: vec![String::from("self"), String::from("arg"),],
kwonlyargs: vec![],
vararg: None,
kwarg: None,
defaults: vec![ast::Expression::String {
value: ast::StringGroup::Constant {
value: "default".to_string()
}
value: "default".to_string()
}],
kw_defaults: vec![],
},
@@ -387,7 +383,6 @@ mod tests {
node: ast::Statement::Pass,
}],
decorator_list: vec![],
returns: None,
}
}
],

View File

@@ -4,12 +4,9 @@
// See also: https://greentreesnakes.readthedocs.io/en/latest/nodes.html#keyword
#![allow(unknown_lints,clippy)]
use super::ast;
use super::lexer;
use std::iter::FromIterator;
use crate::ast;
use crate::fstring::parse_fstring;
use crate::lexer;
use num_bigint::BigInt;
grammar;
@@ -108,11 +105,7 @@ ExpressionStatement: ast::LocatedStatement = {
let rhs = e2.into_iter().next().unwrap();
ast::LocatedStatement {
location: loc,
node: ast::Statement::AugAssign {
target: Box::new(expr),
op,
value: Box::new(rhs)
},
node: ast::Statement::AugAssign { target: expr, op: op, value: rhs },
}
},
};
@@ -446,7 +439,7 @@ WithItem: ast::WithItem = {
};
FuncDef: ast::LocatedStatement = {
<d:Decorator*> <loc:@L> "def" <i:Identifier> <a:Parameters> <r:("->" Test)?> ":" <s:Suite> => {
<d:Decorator*> <loc:@L> "def" <i:Identifier> <a:Parameters> ":" <s:Suite> => {
ast::LocatedStatement {
location: loc,
node: ast::Statement::FunctionDef {
@@ -454,14 +447,13 @@ FuncDef: ast::LocatedStatement = {
args: a,
body: s,
decorator_list: d,
returns: r.map(|x| x.1),
}
}
},
};
Parameters: ast::Parameters = {
"(" <a: (TypedArgsList<TypedParameter>)?> ")" => {
"(" <a: (TypedArgsList)?> ")" => {
match a {
Some(a) => a,
None => Default::default(),
@@ -471,10 +463,8 @@ Parameters: ast::Parameters = {
// parameters are (String, None), kwargs are (String, Some(Test)) where Test is
// the default
// Note that this is a macro which is used once for function defs, and
// once for lambda defs.
TypedArgsList<ArgType>: ast::Parameters = {
<param1:TypedParameters<ArgType>> <args2:("," ParameterListStarArgs<ArgType>)?> => {
TypedArgsList: ast::Parameters = {
<param1:TypedParameters> <args2:("," ParameterListStarArgs)?> => {
let (names, default_elements) = param1;
// Now gather rest of parameters:
@@ -492,7 +482,7 @@ TypedArgsList<ArgType>: ast::Parameters = {
kw_defaults: kw_defaults,
}
},
<param1:TypedParameters<ArgType>> <kw:("," KwargParameter<ArgType>)> => {
<param1:TypedParameters> <kw:("," KwargParameter)> => {
let (names, default_elements) = param1;
// Now gather rest of parameters:
@@ -510,7 +500,7 @@ TypedArgsList<ArgType>: ast::Parameters = {
kw_defaults: kw_defaults,
}
},
<params:ParameterListStarArgs<ArgType>> => {
<params:ParameterListStarArgs> => {
let (vararg, kwonlyargs, kw_defaults, kwarg) = params;
ast::Parameters {
args: vec![],
@@ -521,7 +511,7 @@ TypedArgsList<ArgType>: ast::Parameters = {
kw_defaults: kw_defaults,
}
},
<kw:KwargParameter<ArgType>> => {
<kw:KwargParameter> => {
ast::Parameters {
args: vec![],
kwonlyargs: vec![],
@@ -535,8 +525,8 @@ TypedArgsList<ArgType>: ast::Parameters = {
// Use inline here to make sure the "," is not creating an ambiguity.
#[inline]
TypedParameters<ArgType>: (Vec<ast::Parameter>, Vec<ast::Expression>) = {
<param1:TypedParameterDef<ArgType>> <param2:("," TypedParameterDef<ArgType>)*> => {
TypedParameters: (Vec<String>, Vec<ast::Expression>) = {
<param1:TypedParameterDef> <param2:("," TypedParameterDef)*> => {
// Combine first parameters:
let mut args = vec![param1];
args.extend(param2.into_iter().map(|x| x.1));
@@ -545,6 +535,7 @@ TypedParameters<ArgType>: (Vec<ast::Parameter>, Vec<ast::Expression>) = {
let mut default_elements = vec![];
for (name, default) in args.into_iter() {
names.push(name.clone());
if let Some(default) = default {
default_elements.push(default);
} else {
@@ -553,35 +544,28 @@ TypedParameters<ArgType>: (Vec<ast::Parameter>, Vec<ast::Expression>) = {
// have defaults
panic!(
"non-default argument follows default argument: {}",
&name.arg
name
);
}
}
names.push(name);
}
(names, default_elements)
}
};
TypedParameterDef<ArgType>: (ast::Parameter, Option<ast::Expression>) = {
<i:ArgType> => (i, None),
<i:ArgType> "=" <e:Test> => (i, Some(e)),
TypedParameterDef: (String, Option<ast::Expression>) = {
<i:TypedParameter> => (i, None),
<i:TypedParameter> "=" <e:Test> => (i, Some(e)),
};
UntypedParameter: ast::Parameter = {
<i:Identifier> => ast::Parameter { arg: i, annotation: None },
// TODO: add type annotations here:
TypedParameter: String = {
Identifier,
};
TypedParameter: ast::Parameter = {
<arg:Identifier> <a:(":" Test)?>=> {
let annotation = a.map(|x| Box::new(x.1));
ast::Parameter { arg, annotation }
},
};
ParameterListStarArgs<ArgType>: (Option<Option<ast::Parameter>>, Vec<ast::Parameter>, Vec<Option<ast::Expression>>, Option<Option<ast::Parameter>>) = {
"*" <va:ArgType?> <kw:("," TypedParameterDef<ArgType>)*> <kwarg:("," KwargParameter<ArgType>)?> => {
ParameterListStarArgs: (Option<Option<String>>, Vec<String>, Vec<Option<ast::Expression>>, Option<Option<String>>) = {
"*" <va:Identifier?> <kw:("," TypedParameterDef)*> <kwarg:("," KwargParameter)?> => {
// Extract keyword arguments:
let mut kwonlyargs = vec![];
let mut kw_defaults = vec![];
@@ -599,8 +583,8 @@ ParameterListStarArgs<ArgType>: (Option<Option<ast::Parameter>>, Vec<ast::Parame
}
};
KwargParameter<ArgType>: Option<ast::Parameter> = {
"**" <kwarg:ArgType?> => {
KwargParameter: Option<String> = {
"**" <kwarg:Identifier?> => {
kwarg
}
};
@@ -624,26 +608,17 @@ 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 = {
"@" <p:Path> <a: ("(" ArgumentList ")")?> "\n" => {
"@" <n:DottedName> <a: ("(" ArgumentList ")")?> "\n" => {
let name = ast::Expression::Identifier { name: n };
match a {
Some((_, args, _)) => ast::Expression::Call {
function: Box::new(p),
function: Box::new(name),
args: args.0,
keywords: args.1,
},
None => p,
None => name,
}
},
};
@@ -684,7 +659,7 @@ Test: ast::Expression = {
};
LambdaDef: ast::Expression = {
"lambda" <p:TypedArgsList<UntypedParameter>?> ":" <b:Test> =>
"lambda" <p:TypedArgsList?> ":" <b:Expression> =>
ast::Expression::Lambda {
args: p.unwrap_or(Default::default()),
body:Box::new(b)
@@ -810,8 +785,7 @@ SliceOp: ast::Expression = {
}
Atom: ast::Expression = {
<s:StringGroup> => ast::Expression::String { value: s },
<b:Bytes> => ast::Expression::Bytes { value: b },
StringConstant,
<n:Number> => ast::Expression::Number { value: n },
<i:Identifier> => ast::Expression::Identifier { name: i },
"[" <e:TestListComp?> "]" => {
@@ -848,7 +822,6 @@ Atom: ast::Expression = {
"True" => ast::Expression::True,
"False" => ast::Expression::False,
"None" => ast::Expression::None,
"..." => ast::Expression::Ellipsis,
};
TestListComp: Vec<ast::Expression> = {
@@ -1015,28 +988,14 @@ Number: ast::Number = {
<s:complex> => { ast::Number::Complex { real: s.0, imag: s.1 } },
};
StringGroup: ast::StringGroup = {
<s:string+> =>? {
let mut values = vec![];
for (value, is_fstring) in s {
values.push(if is_fstring {
parse_fstring(&value)?
} else {
ast::StringGroup::Constant { value }
})
}
Ok(if values.len() > 1 {
ast::StringGroup::Joined { values }
} else {
values.into_iter().next().unwrap()
})
StringConstant: ast::Expression = {
<s:string+> => {
let glued = s.join("");
ast::Expression::String { value: glued }
},
};
Bytes: Vec<u8> = {
<s:bytes+> => {
s.into_iter().flatten().collect::<Vec<u8>>()
let glued = s.into_iter().flatten().collect::<Vec<u8>>();
ast::Expression::Bytes { value: glued }
},
};
@@ -1058,7 +1017,6 @@ extern {
"~" => lexer::Tok::Tilde,
":" => lexer::Tok::Colon,
"." => lexer::Tok::Dot,
"..." => lexer::Tok::Ellipsis,
"," => lexer::Tok::Comma,
"*" => lexer::Tok::Star,
"**" => lexer::Tok::DoubleStar,
@@ -1097,7 +1055,6 @@ extern {
"<=" => lexer::Tok::LessEqual,
">" => lexer::Tok::Greater,
">=" => lexer::Tok::GreaterEqual,
"->" => lexer::Tok::Rarrow,
"and" => lexer::Tok::And,
"as" => lexer::Tok::As,
"assert" => lexer::Tok::Assert,
@@ -1135,7 +1092,7 @@ extern {
int => lexer::Tok::Int { value: <BigInt> },
float => lexer::Tok::Float { value: <f64> },
complex => lexer::Tok::Complex { real: <f64>, imag: <f64> },
string => lexer::Tok::String { value: <String>, is_fstring: <bool> },
string => lexer::Tok::String { value: <String> },
bytes => lexer::Tok::Bytes { value: <Vec<u8>> },
name => lexer::Tok::Name { name: <String> },
"\n" => lexer::Tok::Newline,

View File

@@ -9,7 +9,7 @@ pub enum Tok {
Int { value: BigInt },
Float { value: f64 },
Complex { real: f64, imag: f64 },
String { value: String, is_fstring: bool },
String { value: String },
Bytes { value: Vec<u8> },
Newline,
Indent,

View File

@@ -2,7 +2,6 @@
name = "py_code_object"
version = "0.1.0"
authors = ["Shing Lyu <shing.lyu@gmail.com>"]
edition = "2018"
[dependencies]
log = "0.3"

View File

@@ -2,7 +2,6 @@
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" }

View File

@@ -56,7 +56,7 @@ impl VirtualMachine {
}
}
// Can we get rid of the code parameter?
// Can we get rid of the code paramter?
fn make_frame(&self, code: PyCodeObject, callargs: HashMap<String, Rc<NativeType>>, globals: Option<HashMap<String, Rc<NativeType>>>) -> Frame {
//populate the globals and locals
@@ -345,7 +345,7 @@ impl VirtualMachine {
let exception = match argc {
1 => curr_frame.stack.pop().unwrap(),
0 | 2 | 3 => panic!("Not implemented!"),
_ => panic!("Invalid parameter for RAISE_VARARGS, must be between 0 to 3")
_ => panic!("Invalid paramter for RAISE_VARARGS, must be between 0 to 3")
};
panic!("{:?}", exception);
}

View File

@@ -1 +0,0 @@
edition = "2018"

View File

@@ -1,3 +1,4 @@
//extern crate rustpython_parser;
#[macro_use]
extern crate clap;
extern crate env_logger;
@@ -8,19 +9,16 @@ extern crate rustpython_vm;
extern crate rustyline;
use clap::{App, Arg};
use rustpython_parser::error::ParseError;
use rustpython_vm::{
compile,
error::CompileError,
frame::ScopeRef,
import,
obj::objstr,
print_exception,
pyobject::{AttributeProtocol, PyResult},
util, VirtualMachine,
};
use rustyline::{error::ReadlineError, Editor};
use std::path::{Path, PathBuf};
use rustpython_parser::parser;
use rustpython_vm::obj::objstr;
use rustpython_vm::print_exception;
use rustpython_vm::pyobject::{AttributeProtocol, PyObjectRef, PyResult};
use rustpython_vm::VirtualMachine;
use rustpython_vm::{compile, import};
use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::path::Path;
use std::path::PathBuf;
fn main() {
env_logger::init();
@@ -62,7 +60,7 @@ fn main() {
// Figure out if a script was passed:
match matches.value_of("script") {
None => run_shell(&mut vm),
Some(filename) => run_script(&mut vm, filename),
Some(filename) => run_script(&mut vm, &filename.to_string()),
}
};
@@ -70,17 +68,8 @@ fn main() {
handle_exception(&mut vm, result);
}
fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: String) -> PyResult {
let code_obj = compile::compile(
source,
&compile::Mode::Exec,
source_path,
vm.ctx.code_type(),
)
.map_err(|err| {
let syntax_error = vm.context().exceptions.syntax_error.clone();
vm.new_exception(syntax_error, err.to_string())
})?;
fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: Option<String>) -> PyResult {
let code_obj = compile::compile(vm, &source.to_string(), compile::Mode::Exec, source_path)?;
// trace!("Code object: {:?}", code_obj.borrow());
let builtins = vm.get_builtin_scope();
let vars = vm.context().new_scope(Some(builtins)); // Keep track of local variables
@@ -88,9 +77,12 @@ fn _run_string(vm: &mut VirtualMachine, source: &str, source_path: String) -> Py
}
fn handle_exception(vm: &mut VirtualMachine, result: PyResult) {
if let Err(err) = result {
print_exception(vm, &err);
std::process::exit(1);
match result {
Ok(_value) => {}
Err(err) => {
print_exception(vm, &err);
std::process::exit(1);
}
}
}
@@ -98,8 +90,8 @@ fn run_command(vm: &mut VirtualMachine, mut source: String) -> PyResult {
debug!("Running command {}", source);
// This works around https://github.com/RustPython/RustPython/issues/17
source.push('\n');
_run_string(vm, &source, "<stdin>".to_string())
source.push_str("\n");
_run_string(vm, &source, None)
}
fn run_module(vm: &mut VirtualMachine, module: &str) -> PyResult {
@@ -111,53 +103,43 @@ fn run_module(vm: &mut VirtualMachine, module: &str) -> PyResult {
fn run_script(vm: &mut VirtualMachine, script_file: &str) -> PyResult {
debug!("Running file {}", script_file);
// Parse an ast from it:
let file_path = Path::new(script_file);
match util::read_file(file_path) {
Ok(source) => _run_string(vm, &source, file_path.to_str().unwrap().to_string()),
Err(err) => {
error!("Failed reading file: {:?}", err.kind());
let filepath = Path::new(script_file);
match parser::read_file(filepath) {
Ok(source) => _run_string(vm, &source, Some(filepath.to_str().unwrap().to_string())),
Err(msg) => {
error!("Parsing went horribly wrong: {}", msg);
std::process::exit(1);
}
}
}
fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: ScopeRef) -> Result<(), CompileError> {
match compile::compile(
source,
&compile::Mode::Single,
"<stdin>".to_string(),
vm.ctx.code_type(),
) {
fn shell_exec(vm: &mut VirtualMachine, source: &str, scope: PyObjectRef) -> bool {
match compile::compile(vm, &source.to_string(), compile::Mode::Single, None) {
Ok(code) => {
if let Err(err) = vm.run_code_obj(code, scope) {
match vm.run_code_obj(code, scope) {
Ok(_value) => {
// Printed already.
}
Err(err) => {
print_exception(vm, &err);
}
}
}
Err(err) => {
// Enum rather than special string here.
let name = vm.new_str("msg".to_string());
let msg = match vm.get_attribute(err.clone(), name) {
Ok(value) => objstr::get_value(&value),
Err(_) => panic!("Expected msg attribute on exception object!"),
};
if msg == "Unexpected end of input." {
return false;
} else {
print_exception(vm, &err);
}
Ok(())
}
// Don't inject syntax errors for line continuation
Err(err @ CompileError::Parse(ParseError::EOF(_))) => Err(err),
Err(err) => {
let syntax_error = vm.context().exceptions.syntax_error.clone();
let exc = vm.new_exception(syntax_error, format!("{}", err));
print_exception(vm, &exc);
Err(err)
}
}
}
#[cfg(not(unix))]
fn get_history_path() -> PathBuf {
PathBuf::from(".repl_history.txt")
}
#[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.
extern crate xdg;
let xdg_dirs = xdg::BaseDirectories::with_prefix("rustpython").unwrap();
xdg_dirs.place_cache_file("repl_history.txt").unwrap()
};
true
}
fn run_shell(vm: &mut VirtualMachine) -> PyResult {
@@ -170,34 +152,57 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
// Read a single line:
let mut input = String::new();
let mut repl = Editor::<()>::new();
let mut rl = Editor::<()>::new();
// Retrieve a `history_path_str` dependent on the OS
let repl_history_path_str = &get_history_path();
if repl.load_history(repl_history_path_str).is_err() {
// TODO: Store the history in a proper XDG directory
let repl_history_path = ".repl_history.txt";
if rl.load_history(repl_history_path).is_err() {
println!("No previous history.");
}
let ps1 = &objstr::get_value(&vm.sys_module.get_attr("ps1").unwrap());
let ps2 = &objstr::get_value(&vm.sys_module.get_attr("ps2").unwrap());
let mut prompt = ps1;
loop {
match repl.readline(prompt) {
// TODO: modules dont support getattr / setattr yet
//let prompt = match vm.get_attribute(vm.sys_module.clone(), "ps1") {
// Ok(value) => objstr::get_value(&value),
// Err(_) => ">>>>> ".to_string(),
//};
// We can customize the prompt:
let ps1 = objstr::get_value(&vm.sys_module.get_attr("ps1").unwrap());
let ps2 = objstr::get_value(&vm.sys_module.get_attr("ps2").unwrap());
match rl.readline(&ps1) {
Ok(line) => {
debug!("You entered {:?}", line);
input.push_str(&line);
input.push_str("\n");
repl.add_history_entry(line.trim_end().as_ref());
match shell_exec(vm, &input, vars.clone()) {
Err(CompileError::Parse(ParseError::EOF(_))) => {
prompt = ps2;
continue;
}
_ => {
prompt = ps1;
input = String::new();
debug!("You entered {:?}", input);
if shell_exec(vm, &input, vars.clone()) {
// Line was complete.
rl.add_history_entry(input.trim_right().as_ref());
input = String::new();
} else {
loop {
// until an empty line is pressed AND the code is complete
//let prompt = match vm.get_attribute(vm.sys_module.clone(), "ps2") {
// Ok(value) => objstr::get_value(&value),
// Err(_) => "..... ".to_string(),
//};
match rl.readline(&ps2) {
Ok(line) => {
if line.len() == 0 {
if shell_exec(vm, &input, vars.clone()) {
rl.add_history_entry(input.trim_right().as_ref());
input = String::new();
break;
}
} else {
input.push_str(&line);
input.push_str("\n");
}
}
Err(msg) => panic!("Error: {:?}", msg),
}
}
}
}
@@ -215,7 +220,7 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
}
};
}
repl.save_history(repl_history_path_str).unwrap();
rl.save_history(repl_history_path).unwrap();
Ok(vm.get_none())
}

View File

@@ -10,32 +10,7 @@ pip install pipenv
(cd tests; pipenv install)
# Build outside of the test runner
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
cargo build --verbose --release
# 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

View File

@@ -44,12 +44,7 @@ assert int() == 0
a = complex(2, 4)
assert type(a) is complex
assert type(a + a) is complex
assert repr(a) == '(2+4j)'
a = 10j
assert repr(a) == '10j'
a = 1
assert a.conjugate() == a
a = 12345

View File

@@ -16,9 +16,6 @@ assert bool() == False
assert bool(1) == True
assert bool({}) == False
assert bool(NotImplemented) == True
assert bool(...) == True
if not 1:
raise BaseException
@@ -49,5 +46,3 @@ assert True + True == 2
assert False * 7 == 0
assert True > 0
assert int(True) == 1
assert True.conjugate() == 1
assert isinstance(True.conjugate(), int)

View File

@@ -1,26 +0,0 @@
assert not callable(1)
def f(): pass
# TODO uncomment when callable types get unified __call__ (or equivalent)
#assert callable(f)
#assert callable(len)
#assert callable(lambda: 1)
assert callable(int)
class C:
def __init__(self):
# must be defined on class
self.__call__ = lambda self: 1
def f(self): pass
assert callable(C)
assert not callable(C())
#assert callable(C().f)
class C:
def __call__(self): pass
assert callable(C())
class C1(C): pass
assert callable(C1())
class C:
__call__ = 1
# CPython returns true here, but fails when actually calling it
assert callable(C())

View File

@@ -1,46 +0,0 @@
# __abs__
assert abs(complex(3, 4)) == 5
assert abs(complex(3, -4)) == 5
assert abs(complex(1.5, 2.5)) == 2.9154759474226504
# __eq__
assert complex(1, -1) == complex(1, -1)
assert complex(1, 0) == 1
assert 1 == complex(1, 0)
assert complex(1, 1) != 1
assert 1 != complex(1, 1)
assert complex(1, 0) == 1.0
assert 1.0 == complex(1, 0)
assert complex(1, 1) != 1.0
assert 1.0 != complex(1, 1)
assert complex(1, 0) != 1.5
assert not 1.0 != complex(1, 0)
assert bool(complex(1, 0))
assert complex(1, 2) != complex(1, 1)
assert complex(1, 2) != 'foo'
assert complex(1, 2).__eq__('foo') == NotImplemented
# __neg__
assert -complex(1, -1) == complex(-1, 1)
assert -complex(0, 0) == complex(0, 0)
# real
a = complex(3, 4)
b = 4j
assert a.real == 3
assert b.real == 0
# imag
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)

View File

@@ -4,7 +4,3 @@ assert len({}) == 0
assert len({"a": "b"}) == 1
assert len({"a": "b", "b": 1}) == 2
assert len({"a": "b", "b": 1, "a" + "b": 2*2}) == 3
d = {}
d['a'] = d
assert repr(d) == "{'a': {...}}"

View File

@@ -1,12 +0,0 @@
class A:
def test():
pass
a = A()
assert "test" in dir(a)
import socket
assert "AF_INET" in dir(socket)

View File

@@ -1,8 +1,3 @@
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)
assert_raises(ZeroDivisionError, lambda: divmod(5, 0), 'divmod by zero')
assert_raises(ZeroDivisionError, lambda: divmod(5.0, 0.0), 'divmod by zero')

View File

@@ -1,22 +0,0 @@
assert list(enumerate(['a', 'b', 'c'])) == [(0, 'a'), (1, 'b'), (2, 'c')]
assert type(enumerate([])) == enumerate
assert list(enumerate(['a', 'b', 'c'], -100)) == [(-100, 'a'), (-99, 'b'), (-98, 'c')]
assert list(enumerate(['a', 'b', 'c'], 2**200)) == [(2**200, 'a'), (2**200 + 1, 'b'), (2**200 + 2, 'c')]
# test infinite iterator
class Counter(object):
counter = 0
def __next__(self):
self.counter += 1
return self.counter
def __iter__(self):
return self
it = enumerate(Counter())
assert next(it) == (0, 1)
assert next(it) == (1, 2)

View File

@@ -1,32 +0,0 @@
assert list(filter(lambda x: ((x % 2) == 0), [0, 1, 2])) == [0, 2]
# None implies identity
assert list(filter(None, [0, 1, 2])) == [1, 2]
assert type(filter(None, [])) == filter
# test infinite iterator
class Counter(object):
counter = 0
def __next__(self):
self.counter += 1
return self.counter
def __iter__(self):
return self
it = filter(lambda x: ((x % 2) == 0), Counter())
assert next(it) == 2
assert next(it) == 4
def predicate(x):
if x == 0:
raise StopIteration()
return True
assert list(filter(predicate, [1, 2, 0, 4, 5])) == [1, 2]

View File

@@ -1,9 +0,0 @@
from testutils import assert_raises
assert format(5, "b") == "101"
assert_raises(TypeError, lambda: format(2, 3), 'format called with number')
assert format({}) == "{}"
assert_raises(TypeError, lambda: format({}, 'b'), 'format_spec not empty for dict')

View File

@@ -1,6 +1,9 @@
from testutils import assert_raises
assert hex(16) == '0x10'
assert hex(-16) == '-0x10'
assert_raises(TypeError, lambda: hex({}), 'ord() called with dict')
try:
hex({})
except TypeError:
pass
else:
assert False, "TypeError not raised when ord() is called with a dict"

View File

@@ -1,19 +0,0 @@
a = 5
b = 6
loc = locals()
assert loc['a'] == 5
assert loc['b'] == 6
def f():
c = 4
a = 7
loc = locals()
assert loc['a'] == 4
assert loc['c'] == 7
assert not 'b' in loc

View File

@@ -1,34 +0,0 @@
a = list(map(str, [1, 2, 3]))
assert a == ['1', '2', '3']
b = list(map(lambda x, y: x + y, [1, 2, 4], [3, 5]))
assert b == [4, 7]
assert type(map(lambda x: x, [])) == map
# test infinite iterator
class Counter(object):
counter = 0
def __next__(self):
self.counter += 1
return self.counter
def __iter__(self):
return self
it = map(lambda x: x+1, Counter())
assert next(it) == 2
assert next(it) == 3
def mapping(x):
if x == 0:
raise StopIteration()
return x
assert list(map(mapping, [1, 2, 0, 4, 5])) == [1, 2]

View File

@@ -1,5 +1,3 @@
from testutils import assert_raises
# simple values
assert max(0, 0) == 0
assert max(1, 0) == 1
@@ -16,17 +14,32 @@ assert max({
}) == "b"
assert max([1, 2], default=0) == 2
assert max([], default=0) == 0
assert_raises(ValueError, lambda: max([]))
try:
max([])
except ValueError:
pass
else:
assert False, "ValueError was not raised"
# key parameter
assert max(1, 2, -3, key=abs) == -3
assert max([1, 2, -3], key=abs) == -3
# no argument
assert_raises(TypeError, lambda: max())
try:
max()
except TypeError:
pass
else:
assert False, "TypeError was not raised"
# one non-iterable argument
assert_raises(TypeError, lambda: max(1))
try:
max(1)
except TypeError:
pass
else:
assert False, "TypeError was not raised"
# custom class
@@ -51,4 +64,9 @@ class MyNotComparable():
pass
assert_raises(TypeError, lambda: max(MyNotComparable(), MyNotComparable()))
try:
max(MyNotComparable(), MyNotComparable())
except TypeError:
pass
else:
assert False, "TypeError was not raised"

View File

@@ -1,5 +1,3 @@
from testutils import assert_raises
# simple values
assert min(0, 0) == 0
assert min(1, 0) == 0
@@ -16,18 +14,32 @@ assert min({
}) == "a"
assert min([1, 2], default=0) == 1
assert min([], default=0) == 0
assert_raises(ValueError, lambda: min([]))
try:
min([])
except ValueError:
pass
else:
assert False, "ValueError was not raised"
# key parameter
assert min(1, 2, -3, key=abs) == 1
assert min([1, 2, -3], key=abs) == 1
# no argument
assert_raises(TypeError, lambda: min())
try:
min()
except TypeError:
pass
else:
assert False, "TypeError was not raised"
# one non-iterable argument
assert_raises(TypeError, lambda: min(1))
try:
min(1)
except TypeError:
pass
else:
assert False, "TypeError was not raised"
# custom class
@@ -52,4 +64,9 @@ class MyNotComparable():
pass
assert_raises(TypeError, lambda: min(MyNotComparable(), MyNotComparable()))
try:
min(MyNotComparable(), MyNotComparable())
except TypeError:
pass
else:
assert False, "TypeError was not raised"

View File

@@ -1,6 +0,0 @@
from testutils import assert_raises
fd = open('README.md')
assert 'RustPython' in fd.read()
assert_raises(FileNotFoundError, lambda: open('DoesNotExist'))

View File

@@ -1,9 +1,23 @@
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"
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")
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"

View File

@@ -1,52 +0,0 @@
from testutils import assert_raises
assert range(2**63+1)[2**63] == 9223372036854775808
# len tests
assert len(range(10, 5)) == 0, 'Range with no elements should have length = 0'
assert len(range(10, 5, -2)) == 3, 'Expected length 3, for elements: 10, 8, 6'
assert len(range(5, 10, 2)) == 3, 'Expected length 3, for elements: 5, 7, 9'
# index tests
assert range(10).index(6) == 6
assert range(4, 10).index(6) == 2
assert range(4, 10, 2).index(6) == 1
assert range(10, 4, -2).index(8) == 1
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
assert range(10).count(11) == 0
assert range(10).count(-1) == 0
assert range(9, 12).count(10) == 1
assert range(4, 10, 2).count(4) == 1
assert range(4, 10, 2).count(7) == 0
assert range(10).count("foo") == 0
# __bool__
assert bool(range(1))
assert bool(range(1, 2))
assert not bool(range(0))
assert not bool(range(1, 1))
# __contains__
assert 6 in range(10)
assert 6 in range(4, 10)
assert 6 in range(4, 10, 2)
assert 10 in range(10, 4, -2)
assert 8 in range(10, 4, -2)
assert -1 not in range(10)
assert 9 not in range(10, 4, -2)
assert 4 not in range(10, 4, -2)
assert 'foo' not in range(10)
# __reversed__
assert list(reversed(range(5))) == [4, 3, 2, 1, 0]
assert list(reversed(range(5, 0, -1))) == [1, 2, 3, 4, 5]
assert list(reversed(range(1,10,5))) == [6, 1]

View File

@@ -1 +0,0 @@
assert list(reversed(range(5))) == [4, 3, 2, 1, 0]

View File

@@ -1,73 +0,0 @@
from testutils import assert_raises
a = []
assert a[:] == []
assert a[:2**100] == []
assert a[-2**100:] == []
assert a[::2**100] == []
assert a[10:20] == []
assert a[-20:-10] == []
b = [1, 2]
assert b[:] == [1, 2]
assert b[:2**100] == [1, 2]
assert b[-2**100:] == [1, 2]
assert b[2**100:] == []
assert b[::2**100] == [1]
assert b[-10:1] == [1]
assert b[0:0] == []
assert b[1:0] == []
assert_raises(ValueError, lambda: b[::0], 'zero step slice')
assert b[::-1] == [2, 1]
assert b[1::-1] == [2, 1]
assert b[0::-1] == [1]
assert b[0:-5:-1] == [1]
assert b[:0:-1] == [2]
assert b[5:0:-1] == [2]
c = list(range(10))
assert c[9:6:-3] == [9]
assert c[9::-3] == [9, 6, 3, 0]
assert c[9::-4] == [9, 5, 1]
assert c[8::-2**100] == [8]
assert c[7:7:-2] == []
assert c[7:8:-2] == []
d = "123456"
assert d[3::-1] == "4321"
assert d[4::-3] == "52"
slice_a = slice(5)
assert slice_a.start is None
assert slice_a.stop == 5
assert slice_a.step is None
slice_b = slice(1, 5)
assert slice_b.start == 1
assert slice_b.stop == 5
assert slice_b.step is None
slice_c = slice(1, 5, 2)
assert slice_c.start == 1
assert slice_c.stop == 5
assert slice_c.step == 2
class SubScript(object):
def __getitem__(self, item):
assert type(item) == slice
def __setitem__(self, key, value):
assert type(key) == slice
ss = SubScript()
_ = ss[:]
ss[:1] = 1

View File

@@ -1,24 +0,0 @@
assert list(zip(['a', 'b', 'c'], range(3), [9, 8, 7, 99])) == [('a', 0, 9), ('b', 1, 8), ('c', 2, 7)]
assert list(zip(['a', 'b', 'c'])) == [('a',), ('b',), ('c',)]
assert list(zip()) == []
assert list(zip(*zip(['a', 'b', 'c'], range(1, 4)))) == [('a', 'b', 'c'), (1, 2, 3)]
# test infinite iterator
class Counter(object):
def __init__(self, counter=0):
self.counter = counter
def __next__(self):
self.counter += 1
return self.counter
def __iter__(self):
return self
it = zip(Counter(), Counter(3))
assert next(it) == (1, 4)
assert next(it) == (2, 5)

View File

@@ -1,12 +1,22 @@
x = sum(map(int, ['1', '2', '3']))
a = list(map(str, [1, 2, 3]))
assert a == ['1', '2', '3']
x = sum(map(int, a))
assert x == 6
assert callable(type)
# TODO:
# assert callable(callable)
assert list(enumerate(['a', 'b', 'c'])) == [(0, 'a'), (1, 'b'), (2, 'c')]
assert type(frozenset) is type
assert list(zip(['a', 'b', 'c'], range(3), [9, 8, 7, 99])) == [('a', 0, 9), ('b', 1, 8), ('c', 2, 7)]
assert list(filter(lambda x: ((x % 2) == 0), [0, 1, 2])) == [0, 2]
assert 3 == eval('1+2')
code = compile('5+3', 'x.py', 'eval')

View File

@@ -1,67 +0,0 @@
#__getitem__ not implemented yet
#a = bytearray(b'abc')
#assert a[0] == b'a'
#assert a[1] == b'b'
assert len(bytearray([1,2,3])) == 3
assert bytearray(b'1a23').isalnum()
assert not bytearray(b'1%a23').isalnum()
assert bytearray(b'abc').isalpha()
assert not bytearray(b'abc1').isalpha()
# travis doesn't like this
#assert bytearray(b'xyz').isascii()
#assert not bytearray([128, 157, 32]).isascii()
assert bytearray(b'1234567890').isdigit()
assert not bytearray(b'12ab').isdigit()
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()
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

View File

@@ -1,31 +0,0 @@
c1 = compile("1 + 1", "", 'eval')
code_class = type(c1)
def f(x, y, *args, power=1, **kwargs):
print("Constant String", 2, None, (2, 4))
assert code_class == type(c1)
z = x * y
return z ** power
c2 = f.__code__
# print(c2)
assert type(c2) == code_class
# print(dir(c2))
assert c2.co_argcount == 2
# assert c2.co_cellvars == ()
# assert isinstance(c2.co_code, bytes)
assert "Constant String" in c2.co_consts, c2.co_consts
print(c2.co_consts)
assert 2 in c2.co_consts, c2.co_consts
assert "code.py" in c2.co_filename
assert c2.co_firstlineno == 5, str(c2.co_firstlineno)
# assert isinstance(c2.co_flags, int) # 'OPTIMIZED, NEWLOCALS, NOFREE'
# assert c2.co_freevars == (), str(c2.co_freevars)
assert c2.co_kwonlyargcount == 1, (c2.co_kwonlyargcount)
# assert c2.co_lnotab == 0, c2.co_lnotab # b'\x00\x01' # Line number table
assert c2.co_name == 'f', c2.co_name
# assert c2.co_names == ('code_class', 'type', 'c1', 'AssertionError'), c2.co_names # , c2.co_names
# assert c2.co_nlocals == 4, c2.co_nlocals #
# assert c2.co_stacksize == 2, 'co_stacksize',
# assert c2.co_varnames == ('x', 'y', 'power', 'z'), c2.co_varnames

View File

@@ -1,33 +0,0 @@
# 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]

View File

@@ -14,15 +14,3 @@ 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

View File

@@ -1,19 +0,0 @@
def dict_eq(d1, d2):
return (all(k in d2 and d1[k] == d2[k] for k in d1)
and all(k in d1 and d1[k] == d2[k] for k in d2))
assert dict_eq(dict(a=2, b=3), {'a': 2, 'b': 3})
assert dict_eq(dict({'a': 2, 'b': 3}, b=4), {'a': 2, 'b': 4})
assert dict_eq(dict([('a', 2), ('b', 3)]), {'a': 2, 'b': 3})
a = {'g': 5}
b = {'a': a, 'd': 9}
c = dict(b)
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

View File

@@ -1,34 +0,0 @@
import dis
dis.dis(compile("5 + x + 5 or 2", "", "eval"))
print("\n")
dis.dis(compile("def f(x):\n return 1", "", "exec"))
print("\n")
dis.dis(compile("if a:\n 1 or 2\nelif x == 'hello':\n 3\nelse:\n 4", "", "exec"))
print("\n")
dis.dis(compile("f(x=1, y=2)", "", "eval"))
print("\n")
def f():
with g():
try:
for a in {1: 4, 2: 5}:
yield [True and False or True, []]
except Exception:
raise not ValueError({1 for i in [1,2,3]})
dis.dis(f)
class A(object):
def f():
x += 1
pass
def g():
for i in range(5):
if i:
continue
else:
break
print("A.f\n")
dis.dis(A.f)

View File

@@ -1,11 +0,0 @@
from testutils import assert_raises
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))
assert issubclass(ZeroDivisionError, ArithmeticError)

View File

@@ -1,19 +0,0 @@
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
# 95.23809523809524
res = 10**3000 / (10**2998 + 5 * 10**2996)
assert 95.238095 <= res <= 95.238096
assert 10**500 / (2*10**(500-308)) == 5e307
assert 10**500 / (10**(500-308)) == 1e308
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
assert_raises(OverflowError, lambda: (2 * 10**308) / 2.0, 'division of big int by float')

View File

@@ -1,8 +0,0 @@
a = ...
b = ...
c = type(a)() # Test singleton behavior
assert a is b
assert b is c

View File

@@ -1,7 +1,3 @@
import math
from testutils import assert_raises
1 + 1.1
a = 1.2
@@ -19,90 +15,3 @@ assert b >= a
assert c >= a
assert not a >= b
assert a + b == 2.5
assert a - c == 0
assert a / c == 1
assert a < 5
assert a <= 5
try:
assert a < 'a'
except TypeError:
pass
try:
assert a <= 'a'
except TypeError:
pass
assert a > 1
assert a >= 1
try:
assert a > 'a'
except TypeError:
pass
try:
assert a >= 'a'
except TypeError:
pass
assert math.isnan(float('nan'))
assert math.isnan(float('NaN'))
assert math.isnan(float('+NaN'))
assert math.isnan(float('-NaN'))
assert math.isinf(float('inf'))
assert math.isinf(float('Inf'))
assert math.isinf(float('+Inf'))
assert math.isinf(float('-Inf'))
assert float('+Inf') > 0
assert float('-Inf') < 0
assert float('3.14') == 3.14
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(ValueError, lambda: float('foo'))
assert_raises(OverflowError, lambda: float(2**10000))
# check that magic methods are implemented for ints and floats
assert 1.0.__add__(1.0) == 2.0
assert 1.0.__radd__(1.0) == 2.0
assert 2.0.__sub__(1.0) == 1.0
assert 2.0.__rmul__(1.0) == 2.0
assert 1.0.__truediv__(2.0) == 0.5
assert 1.0.__rtruediv__(2.0) == 2.0
assert 1.0.__add__(1) == 2.0
assert 1.0.__radd__(1) == 2.0
assert 2.0.__sub__(1) == 1.0
assert 2.0.__rmul__(1) == 2.0
assert 1.0.__truediv__(2) == 0.5
assert 1.0.__rtruediv__(2) == 2.0
assert 2.0.__mul__(1) == 2.0
assert 2.0.__rsub__(1) == -1.0
assert (1.7).real == 1.7
assert (1.3).is_integer() == False
assert (1.0).is_integer() == True
assert (0.875).as_integer_ratio() == (7, 8)
assert (-0.875).as_integer_ratio() == (-7, 8)
assert (0.0).as_integer_ratio() == (0, 1)
assert (11.5).as_integer_ratio() == (23, 2)
assert (0.0).as_integer_ratio() == (0, 1)
assert (2.5).as_integer_ratio() == (5, 2)
assert (0.5).as_integer_ratio() == (1, 2)
assert (2.1).as_integer_ratio() == (4728779608739021, 2251799813685248)
assert (-2.1).as_integer_ratio() == (-4728779608739021, 2251799813685248)
assert (-2100.0).as_integer_ratio() == (-2100, 1)
assert (2.220446049250313e-16).as_integer_ratio() == (1, 4503599627370496)
assert (1.7976931348623157e+308).as_integer_ratio() == (179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368, 1)
assert (2.2250738585072014e-308).as_integer_ratio() == (1, 44942328371557897693232629769725618340449424473557664318357520289433168951375240783177119330601884005280028469967848339414697442203604155623211857659868531094441973356216371319075554900311523529863270738021251442209537670585615720368478277635206809290837627671146574559986811484619929076208839082406056034304)
assert_raises(OverflowError, float('inf').as_integer_ratio)
assert_raises(OverflowError, float('-inf').as_integer_ratio)
assert_raises(ValueError, float('nan').as_integer_ratio)

View File

@@ -1,41 +0,0 @@
foo = 'bar'
assert f"{''}" == ''
assert f"{f'{foo}'}" == 'bar'
assert f"foo{foo}" == 'foobar'
assert f"{foo}foo" == 'barfoo'
assert f"foo{foo}foo" == 'foobarfoo'
assert f"{{foo}}" == '{foo}'
assert f"{ {foo} }" == "{'bar'}"
assert f"{f'{{}}'}" == '{}' # don't include escaped braces in nested f-strings
assert f'{f"{{"}' == '{'
assert f'{f"}}"}' == '}'
assert f'{foo}' f"{foo}" 'foo' == 'barbarfoo'
assert f'{"!:"}' == '!:'
assert fr'x={4*10}\n' == 'x=40\\n'
assert f'{16:0>+#10x}' == '00000+0x10'
assert f"{{{(lambda x: f'hello, {x}')('world}')}" == '{hello, world}'
# Normally `!` cannot appear outside of delimiters in the expression but
# cpython makes an exception for `!=`, so we should too.
# assert f'{1 != 2}' == 'True'
# conversion flags
class Value:
def __format__(self, spec):
return "foo"
def __repr__(self):
return "bar"
def __str__(self):
return "baz"
v = Value()
assert f'{v}' == 'foo'
assert f'{v!r}' == 'bar'
assert f'{v!s}' == 'baz'

View File

@@ -1,12 +1,21 @@
from testutils import assert_raises
def no_args():
pass
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')
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'
def one_arg(arg):
@@ -15,20 +24,40 @@ def one_arg(arg):
one_arg('one_arg')
assert "arg" == one_arg(arg="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()
except TypeError:
pass
else:
assert False, 'no TypeError raised: no args to one_arg'
assert_raises(TypeError,
lambda: one_arg('one_arg', arg='duplicate'),
'same pos and 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'
def one_default_arg(arg="default"):
@@ -38,9 +67,12 @@ assert 'default' == one_default_arg()
assert 'arg' == one_default_arg('arg')
assert 'kwarg' == one_default_arg(arg='kwarg')
assert_raises(TypeError,
lambda: one_default_arg('one_arg', 'two_arg'),
'two args to one_default_arg')
try:
one_default_arg('one_arg', 'two_arg')
except TypeError:
pass
else:
assert False, 'no TypeError raised: two args to one_default_arg'
def one_normal_one_default_arg(pos, arg="default"):
@@ -49,13 +81,19 @@ 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')
assert_raises(TypeError,
lambda: one_normal_one_default_arg(),
'no args to one_normal_one_default_arg')
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('one', 'two', 'three'),
'three 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'
def two_pos(a, b):

View File

@@ -5,10 +5,4 @@ assert b == 6
c = 2 + 4 if a > 5 else 'boe'
assert c == 'boe'
d = lambda x, y: x > y
assert d(5, 4)
e = lambda x: 1 if x else 0
assert e(True) == 1
assert e(False) == 0

View File

@@ -10,7 +10,6 @@ def test_function():
x = 17
assert sys._getframe().f_locals is not locals_dict
assert sys._getframe().f_locals['x'] == 17
assert sys._getframe(1).f_locals['foo'] == 'bar'
test_function()

View File

@@ -1,7 +1,6 @@
import import_target, import_target as aliased
from import_target import func, other_func
from import_target import func as aliased_func, other_func as aliased_other_func
from import_star import *
assert import_target.X == import_target.func()
assert import_target.X == func()
@@ -14,14 +13,6 @@ assert import_target.Y == aliased.Y
assert import_target.X == aliased_func()
assert import_target.Y == aliased_other_func()
assert STAR_IMPORT == '123'
try:
from import_target import func, unknown_name
raise AssertionError('`unknown_name` does not cause an exception')
except ImportError:
pass
# TODO: Once we can determine current directory, use that to construct this
# path:
#import sys

View File

@@ -1,3 +0,0 @@
# This is used by import.py; the two should be modified in concert
STAR_IMPORT = '123'

View File

@@ -1,11 +0,0 @@
# WARNING! This file contains mixed tabs and spaces
# (because that's what it is testing)
def weird_indentation():
return_value = "hi"
if False:
return return_value
return "hi"
assert weird_indentation() == "hi"

View File

@@ -1,26 +0,0 @@
import sys
def expect_cannot_fit_index_error(s, index):
try:
s[index]
except IndexError:
pass
# TODO: Replace current except block with commented
# after solving https://github.com/RustPython/RustPython/issues/322
# except IndexError as error:
# assert str(error) == "cannot fit 'int' into an index-sized integer"
else:
assert False
MAX_INDEX = sys.maxsize + 1
MIN_INDEX = -(MAX_INDEX + 1)
test_str = "test"
expect_cannot_fit_index_error(test_str, MIN_INDEX)
expect_cannot_fit_index_error(test_str, MAX_INDEX)
test_list = [0, 1, 2, 3]
expect_cannot_fit_index_error(test_list, MIN_INDEX)
expect_cannot_fit_index_error(test_list, MAX_INDEX)

View File

@@ -1,109 +0,0 @@
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

View File

@@ -1,15 +0,0 @@
# 10**308 cannot be represented exactly in f64, thus it is not equal to 1e308 float
assert not (10**308 == 1e308)
# but the 1e308 float can be converted to big int and then it still should be equal to itself
assert int(1e308) == 1e308
# and the equalities should be the same when operands switch sides
assert not (1e308 == 10**308)
assert 1e308 == int(1e308)
# floats that cannot be converted to big ints shouldnt crash the vm
import math
assert not (10**500 == math.inf)
assert not (math.inf == 10**500)
assert not (10**500 == math.nan)
assert not (math.nan == 10**500)

View File

@@ -1,60 +0,0 @@
from testutils import assert_raises
# int to int comparisons
assert 1 == 1
assert not 1 != 1
assert (1).__eq__(1)
assert not (1).__ne__(1)
# int to float comparisons
assert 1 == 1.0
assert not 1 != 1.0
assert not 1 > 1.0
assert not 1 < 1.0
assert 1 >= 1.0
assert 1 <= 1.0
# check for argument handling
assert int("101", base=2) == 5
# magic methods should only be implemented for other ints
assert (1).__eq__(1) == True
assert (1).__ne__(1) == False
assert (1).__gt__(1) == False
assert (1).__ge__(1) == True
assert (1).__lt__(1) == False
assert (1).__le__(1) == True
assert (1).__add__(1) == 2
assert (1).__radd__(1) == 2
assert (2).__sub__(1) == 1
assert (2).__rsub__(1) == -1
assert (2).__mul__(1) == 2
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_raises(OverflowError, lambda: 1 << 10 ** 100000)
assert (1).__eq__(1.0) == NotImplemented
assert (1).__ne__(1.0) == NotImplemented
assert (1).__gt__(1.0) == NotImplemented
assert (1).__ge__(1.0) == NotImplemented
assert (1).__lt__(1.0) == NotImplemented
assert (1).__le__(1.0) == NotImplemented
assert (1).__add__(1.0) == NotImplemented
assert (2).__sub__(1.0) == NotImplemented
assert (1).__radd__(1.0) == NotImplemented
assert (2).__rsub__(1.0) == NotImplemented
assert (2).__mul__(1.0) == NotImplemented
assert (2).__rmul__(1.0) == NotImplemented
assert (2).__truediv__(1.0) == NotImplemented
assert (2).__rtruediv__(1.0) == NotImplemented

View File

@@ -1,54 +0,0 @@
class Regular:
pass
assert isinstance(Regular(), Regular)
class MCNotInstanceOf(type):
def __instancecheck__(self, instance):
return False
class NotInstanceOf(metaclass=MCNotInstanceOf):
pass
class InheritedNotInstanceOf(NotInstanceOf):
pass
assert not isinstance(Regular(), NotInstanceOf)
assert not isinstance(1, NotInstanceOf)
# weird cpython behaviour if exact match then isinstance return true
assert isinstance(NotInstanceOf(), NotInstanceOf)
assert not NotInstanceOf.__instancecheck__(NotInstanceOf())
assert not isinstance(InheritedNotInstanceOf(), NotInstanceOf)
class MCAlwaysInstanceOf(type):
def __instancecheck__(self, instance):
return True
class AlwaysInstanceOf(metaclass=MCAlwaysInstanceOf):
pass
assert isinstance(AlwaysInstanceOf(), AlwaysInstanceOf)
assert isinstance(Regular(), AlwaysInstanceOf)
assert isinstance(1, AlwaysInstanceOf)
class MCReturnInt(type):
def __instancecheck__(self, instance):
return 3
class ReturnInt(metaclass=MCReturnInt):
pass
assert isinstance("a", ReturnInt) is True

View File

@@ -1,63 +0,0 @@
class A:
pass
class B(A):
pass
assert issubclass(A, A)
assert issubclass(B, A)
assert not issubclass(A, B)
class MCNotSubClass(type):
def __subclasscheck__(self, subclass):
return False
class NotSubClass(metaclass=MCNotSubClass):
pass
class InheritedNotSubClass(NotSubClass):
pass
assert not issubclass(A, NotSubClass)
assert not issubclass(NotSubClass, NotSubClass)
assert not issubclass(InheritedNotSubClass, NotSubClass)
assert not issubclass(NotSubClass, InheritedNotSubClass)
class MCAlwaysSubClass(type):
def __subclasscheck__(self, subclass):
return True
class AlwaysSubClass(metaclass=MCAlwaysSubClass):
pass
class InheritedAlwaysSubClass(AlwaysSubClass):
pass
assert issubclass(A, AlwaysSubClass)
assert issubclass(AlwaysSubClass, AlwaysSubClass)
assert issubclass(InheritedAlwaysSubClass, AlwaysSubClass)
assert issubclass(AlwaysSubClass, InheritedAlwaysSubClass)
class MCAVirtualSubClass(type):
def __subclasscheck__(self, subclass):
return subclass is A
class AVirtualSubClass(metaclass=MCAVirtualSubClass):
pass
assert issubclass(A, AVirtualSubClass)
assert not isinstance(B, AVirtualSubClass)

View File

@@ -31,7 +31,8 @@ assert '{}' == json.dumps({})
assert 1 == json.loads("1")
assert -1 == json.loads("-1")
assert 1.0 == json.loads("1.0")
assert -1.0 == json.loads("-1.0")
# TODO: uncomment once negative floats are implemented
# assert -1.0 == json.loads("-1.0")
assert "str" == json.loads('"str"')
assert True is json.loads('true')
assert False is json.loads('false')

View File

@@ -1,5 +1,3 @@
from testutils import assert_raises
x = [1, 2, 3]
assert x[0] == 1
assert x[1] == 2
@@ -11,148 +9,3 @@ assert y == [2, 1, 2, 3]
y.extend(x)
assert y == [2, 1, 2, 3, 1, 2, 3]
assert x * 0 == [], "list __mul__ by 0 failed"
assert x * -1 == [], "list __mul__ by -1 failed"
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
assert_raises(ValueError, lambda: ['a', 'b', 'c'].index('z'))
x = [[1,0,-3], 'a', 1]
y = [[3,2,1], 'z', 2]
assert x < y, "list __lt__ failed"
x = [5, 13, 31]
y = [1, 10, 29]
assert x > y, "list __gt__ failed"
assert [1,2,'a'].pop() == 'a', "list pop failed"
assert_raises(IndexError, lambda: [].pop())
recursive = []
recursive.append(recursive)
assert repr(recursive) == "[[...]]"
# insert()
x = ['a', 'b', 'c']
x.insert(0, 'z') # insert is in-place, no return value
assert x == ['z', 'a', 'b', 'c']
x = ['a', 'b', 'c']
x.insert(100, 'z')
assert x == ['a', 'b', 'c', 'z']
x = ['a', 'b', 'c']
x.insert(-1, 'z')
assert x == ['a', 'b', 'z', 'c']
x = ['a', 'b', 'c']
x.insert(-100, 'z')
assert x == ['z', 'a', 'b', 'c']
assert_raises(OverflowError, lambda: x.insert(100000000000000000000, 'z'))
x = [[], 2, {}]
y = x.copy()
assert x is not y
assert x == y
assert all(a is b for a, b in zip(x, y))
y.append(4)
assert x != y
a = [1, 2, 3]
assert len(a) == 3
a.remove(1)
assert len(a) == 2
assert not 1 in a
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]
for size in [1, 2, 3, 4, 5, 8, 10, 100, 1000]:
lst = list(range(size))
orig = lst[:]
lst.sort()
assert lst == orig
assert sorted(lst) == orig
assert_raises(ZeroDivisionError, lambda: sorted(lst, key=lambda x: 1/x))
lst.reverse()
assert sorted(lst) == orig
assert sorted(lst, reverse=True) == lst
assert sorted(lst, key=lambda x: -x) == lst
assert sorted(lst, key=lambda x: -x, reverse=True) == orig
assert sorted([(1, 2, 3), (0, 3, 6)]) == [(0, 3, 6), (1, 2, 3)]
assert sorted([(1, 2, 3), (0, 3, 6)], key=lambda x: x[0]) == [(0, 3, 6), (1, 2, 3)]
assert sorted([(1, 2, 3), (0, 3, 6)], key=lambda x: x[1]) == [(1, 2, 3), (0, 3, 6)]
assert sorted([(1, 2), (), (5,)], key=len) == [(), (5,), (1, 2)]
lst = [3, 1, 5, 2, 4]
class C:
def __init__(self, x): self.x = x
def __lt__(self, other): return self.x < other.x
lst.sort(key=C)
assert lst == [1, 2, 3, 4, 5]
lst = [3, 1, 5, 2, 4]
class C:
def __init__(self, x): self.x = x
def __gt__(self, other): return self.x > other.x
lst.sort(key=C)
assert lst == [1, 2, 3, 4, 5]
lst = [5, 1, 2, 3, 4]
def f(x):
lst.append(1)
return x
assert_raises(ValueError, lambda: lst.sort(key=f)) # "list modified during sort"
assert lst == [1, 2, 3, 4, 5]

View File

@@ -18,12 +18,4 @@ assert -a == -4
assert +a == 4
# import math
# assert(math.exp(2) == math.exp(2.0))
# assert(math.exp(True) == math.exp(1.0))
#
# class Conversible():
# def __float__(self):
# print("Converting to float now!")
# return 1.1111
#
# assert math.log(1.1111) == math.log(Conversible())
# print(math.cos(1.2))

View File

@@ -1,5 +1,3 @@
from testutils import assert_raises
# test lists
assert 3 in [1, 2, 3]
assert 3 not in [1, 2]
@@ -15,13 +13,6 @@ assert "whatever" not in "foobar"
# TODO: uncomment this when bytes are implemented
# assert b"foo" in b"foobar"
# assert b"whatever" not in b"foobar"
assert b"1" < b"2"
assert b"1" <= b"2"
assert b"5" <= b"5"
assert b"4" > b"2"
assert not b"1" >= b"2"
assert b"10" >= b"10"
assert_raises(TypeError, lambda: bytes() > 2)
# test tuple
assert 1 in (1, 2)
@@ -50,7 +41,12 @@ class MyNotContainingClass():
pass
assert_raises(TypeError, lambda: 1 in MyNotContainingClass())
try:
1 in MyNotContainingClass()
except TypeError:
pass
else:
assert False, "TypeError not raised"
class MyContainingClass():

View File

@@ -14,7 +14,3 @@ assert none() is none()
assert none() is x
assert none() is none2()
assert str(None) == 'None'
assert repr(None) == 'None'
assert type(None)() is None

View File

@@ -2,43 +2,9 @@ x = 5
x.__init__(6)
assert x == 5
class A(int):
pass
x = A(7)
assert x == 7
assert type(x) is A
assert int(2).__index__() == 2
assert int(2).__trunc__() == 2
assert int(2).__ceil__() == 2
assert int(2).__floor__() == 2
assert int(2).__round__() == 2
assert int(2).__round__(3) == 2
assert int(-2).__index__() == -2
assert int(-2).__trunc__() == -2
assert int(-2).__ceil__() == -2
assert int(-2).__floor__() == -2
assert int(-2).__round__() == -2
assert int(-2).__round__(3) == -2
assert round(10) == 10
assert round(10, 2) == 10
assert round(10, -1) == 10
assert int(2).__bool__() == True
assert int(0.5).__bool__() == False
assert int(-1).__bool__() == True
assert int(0).__invert__() == -1
assert int(-3).__invert__() == 2
assert int(4).__invert__() == -5
assert int(0).__rxor__(0) == 0
assert int(1).__rxor__(0) == 1
assert int(0).__rxor__(1) == 1
assert int(1).__rxor__(1) == 0
assert int(3).__rxor__(-3) == -2
assert int(3).__rxor__(4) == 7

View File

@@ -1,15 +0,0 @@
class MyObject:
pass
assert not MyObject() == MyObject()
assert MyObject() != MyObject()
myobj = MyObject()
assert myobj == myobj
assert not myobj != myobj
assert MyObject().__eq__(MyObject()) == NotImplemented
assert MyObject().__ne__(MyObject()) == NotImplemented
assert MyObject().__lt__(MyObject()) == NotImplemented
assert MyObject().__le__(MyObject()) == NotImplemented
assert MyObject().__gt__(MyObject()) == NotImplemented
assert MyObject().__ge__(MyObject()) == NotImplemented

View File

@@ -1,3 +0,0 @@
import os
assert os.name == 'posix' or os.name == 'nt'

View File

@@ -0,0 +1 @@
print(2 + 3)

View File

@@ -1,11 +0,0 @@
from testutils import assert_raises
print(2 + 3)
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)
except:
assert False, 'Expected None passed to end, sep, and flush to not raise errors'

View File

@@ -1,146 +0,0 @@
from testutils import assert_raises, assertRaises
assert set([1,2]) == set([1,2])
assert not set([1,2,3]) == set([1,2])
assert set([1,2,3]) >= set([1,2])
assert set([1,2]) >= set([1,2])
assert not set([1,3]) >= set([1,2])
assert set([1,2,3]).issuperset(set([1,2]))
assert set([1,2]).issuperset(set([1,2]))
assert not set([1,3]).issuperset(set([1,2]))
assert set([1,2,3]) > set([1,2])
assert not set([1,2]) > set([1,2])
assert not set([1,3]) > set([1,2])
assert set([1,2]) <= set([1,2,3])
assert set([1,2]) <= set([1,2])
assert not set([1,3]) <= set([1,2])
assert set([1,2]).issubset(set([1,2,3]))
assert set([1,2]).issubset(set([1,2]))
assert not set([1,3]).issubset(set([1,2]))
assert set([1,2]) < set([1,2,3])
assert not set([1,2]) < set([1,2])
assert not set([1,3]) < set([1,2])
class Hashable(object):
def __init__(self, obj):
self.obj = obj
def __repr__(self):
return repr(self.obj)
def __hash__(self):
return id(self)
recursive = set()
recursive.add(Hashable(recursive))
assert repr(recursive) == "{set(...)}"
a = set([1, 2, 3])
assert len(a) == 3
a.clear()
assert len(a) == 0
assert set([1,2,3]).union(set([4,5])) == set([1,2,3,4,5])
assert set([1,2,3]).union(set([1,2,3,4,5])) == set([1,2,3,4,5])
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([1,2,3,4,5])
assert set([1,2,3]).intersection(set([1,2])) == set([1,2])
assert set([1,2,3]).intersection(set([5,6])) == set([])
assert set([1,2,3]) & set([4,5]) == set([])
assert set([1,2,3]) & set([1,2,3,4,5]) == set([1,2,3])
assert set([1,2,3]).difference(set([1,2])) == set([3])
assert set([1,2,3]).difference(set([5,6])) == set([1,2,3])
assert set([1,2,3]) - set([4,5]) == set([1,2,3])
assert set([1,2,3]) - set([1,2,3,4,5]) == set([])
assert set([1,2,3]).symmetric_difference(set([1,2])) == set([3])
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])
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

View File

@@ -1,10 +0,0 @@
from io import BufferedReader, FileIO
fi = FileIO('README.md')
bb = BufferedReader(fi)
result = bb.read()
assert len(result) <= 8*1024
assert len(result) >= 0
assert isinstance(result, bytes)

View File

@@ -1,13 +0,0 @@
import os
from testutils import assert_raises
assert os.open('README.md', 0) > 0
assert_raises(FileNotFoundError, lambda: os.open('DOES_NOT_EXIST', 0))
assert os.O_RDONLY == 0
assert os.O_WRONLY == 1
assert os.O_RDWR == 2

View File

@@ -1,75 +0,0 @@
import socket
from testutils import assertRaises
MESSAGE_A = b'aaaa'
MESSAGE_B= b'bbbbb'
# TCP
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.bind(("127.0.0.1", 0))
listener.listen(1)
connector = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connector.connect(("127.0.0.1", listener.getsockname()[1]))
(connection, addr) = listener.accept()
assert addr == connector.getsockname()
connector.send(MESSAGE_A)
connection.send(MESSAGE_B)
recv_a = connection.recv(len(MESSAGE_A))
recv_b = connector.recv(len(MESSAGE_B))
assert recv_a == MESSAGE_A
assert recv_b == MESSAGE_B
connection.close()
connector.close()
listener.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
with assertRaises(TypeError):
s.connect(("127.0.0.1", 8888, 8888))
with assertRaises(TypeError):
s.bind(("127.0.0.1", 8888, 8888))
with assertRaises(TypeError):
s.bind((888, 8888))
s.close()
# UDP
sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock1.bind(("127.0.0.1", 0))
sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock2.sendto(MESSAGE_A, sock1.getsockname())
(recv_a, addr1) = sock1.recvfrom(len(MESSAGE_A))
assert recv_a == MESSAGE_A
sock2.sendto(MESSAGE_B, sock1.getsockname())
(recv_b, addr2) = sock1.recvfrom(len(MESSAGE_B))
assert recv_b == MESSAGE_B
assert addr1[0] == addr2[0]
assert addr1[1] == addr2[1]
sock2.close()
sock3 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock3.bind(("127.0.0.1", 0))
sock3.sendto(MESSAGE_A, sock1.getsockname())
(recv_a, addr) = sock1.recvfrom(len(MESSAGE_A))
assert recv_a == MESSAGE_A
assert addr == sock3.getsockname()
sock1.connect(("127.0.0.1", sock3.getsockname()[1]))
sock3.connect(("127.0.0.1", sock1.getsockname()[1]))
sock1.send(MESSAGE_A)
sock3.send(MESSAGE_B)
recv_a = sock3.recv(len(MESSAGE_A))
recv_b = sock1.recv(len(MESSAGE_B))
assert recv_a == MESSAGE_A
assert recv_b == MESSAGE_B
sock1.close()
sock3.close()

View File

@@ -8,9 +8,6 @@ assert "\n" == """
"""
assert len(""" " \" """) == 5
assert len("é") == 1
assert len("") == 2
assert len("") == 1
assert type("") is str
assert type(b"") is bytes
@@ -35,15 +32,6 @@ assert a.startswith('H')
assert not a.startswith('f')
assert a.endswith('llo')
assert not a.endswith('on')
assert a.zfill(8) == '000Hallo'
assert a.isalnum()
assert not a.isdigit()
assert not a.isdecimal()
assert not a.isnumeric()
assert a.istitle()
assert a.isalpha()
b = ' hallo '
assert b.strip() == 'hallo'
@@ -52,36 +40,3 @@ assert b.rstrip() == ' hallo'
c = 'hallo'
assert c.capitalize() == 'Hallo'
assert c.center(11, '-') == '---hallo---'
# assert c.isascii()
assert c.index('a') == 1
assert c.rindex('l') == 3
assert c.find('h') == 0
assert c.rfind('x') == -1
assert c.islower()
assert c.title() == 'Hallo'
assert c.count('l') == 2
assert ' '.isspace()
assert 'hello\nhallo\nHallo'.splitlines() == ['hello', 'hallo', 'Hallo']
assert 'abc\t12345\txyz'.expandtabs() == 'abc 12345 xyz'
assert '-'.join(['1', '2', '3']) == '1-2-3'
assert 'HALLO'.isupper()
assert "hello, my name is".partition("my ") == ('hello, ', 'my ', 'name is')
assert "hello, my name is".rpartition("is") == ('hello, my name ', 'is', '')
assert not ''.isdecimal()
assert '123'.isdecimal()
assert not '\u00B2'.isdecimal()
# String Formatting
assert "{} {}".format(1,2) == "1 2"
assert "{0} {1}".format(2,3) == "2 3"
assert "--{:s>4}--".format(1) == "--sss1--"
assert "{keyword} {0}".format(1, keyword=2) == "2 1"
assert 'a' < 'b'
assert 'a' <= 'b'
assert 'a' <= 'a'
assert 'z' > 'b'
assert 'z' >= 'b'
assert 'a' >= 'a'

View File

@@ -1,21 +0,0 @@
from testutils import assert_raises
#
# Tests
#
assert 8 >> 3 == 1
assert 8 << 3 == 64
# Left shift raises type error
assert_raises(TypeError, lambda: 1 << 0.1)
assert_raises(TypeError, lambda: 1 << "abc")
# Right shift raises type error
assert_raises(TypeError, lambda: 1 >> 0.1)
assert_raises(TypeError, lambda: 1 >> "abc")
# Left shift raises value error on negative
assert_raises(ValueError, lambda: 1 << -1)
# Right shift raises value error on negative
assert_raises(ValueError, lambda: 1 >> -1)

View File

@@ -1,42 +0,0 @@
exec("def square(x):\n return x * x\n")
assert 16 == square(4)
d = {}
exec("def square(x):\n return x * x\n", {}, d)
assert 16 == d['square'](4)
exec("assert 2 == x", {}, {'x': 2})
exec("assert 2 == x", {'x': 2}, {})
exec("assert 4 == x", {'x': 2}, {'x': 4})
exec("assert max(1, 2) == 2", {}, {})
exec("assert max(1, 5, square(5)) == 25", None)
#
# These doesn't work yet:
#
# Local environment shouldn't replace global environment:
#
# exec("assert max(1, 5, square(5)) == 25", None, {})
#
# Closures aren't available if local scope is replaced:
#
# def g():
# seven = "seven"
# def f():
# try:
# exec("seven", None, {})
# except NameError:
# pass
# else:
# raise NameError("seven shouldn't be in scope")
# f()
# g()
try:
exec("", 1)
except TypeError:
pass
else:
raise TypeError("exec should fail unless globals is a dict or None")

View File

@@ -1,20 +0,0 @@
empty_set = set()
non_empty_set = set([1,2,3])
set_from_literal = {1,2,3}
assert 1 in non_empty_set
assert 4 not in non_empty_set
assert 1 in set_from_literal
assert 4 not in set_from_literal
# TODO: Assert that empty aruguments raises exception.
non_empty_set.add('a')
assert 'a' in non_empty_set
# TODO: Assert that empty arguments, or item not in set raises exception.
non_empty_set.remove(1)
assert 1 not in non_empty_set
# TODO: Assert that adding the same thing to a set once it's already there doesn't do anything.

View File

@@ -1,13 +0,0 @@
import string
assert string.ascii_letters == 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
assert string.ascii_lowercase == 'abcdefghijklmnopqrstuvwxyz'
assert string.ascii_uppercase == 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
assert string.digits == '0123456789'
assert string.hexdigits == '0123456789abcdefABCDEF'
assert string.octdigits == '01234567'
assert string.punctuation == '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
# FIXME
#assert string.whitespace == ' \t\n\r\x0b\x0c', string.whitespace
#assert string.printable == '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'

View File

@@ -1,36 +0,0 @@
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

View File

@@ -8,19 +8,6 @@ except BaseException as ex:
# print(ex.__traceback__)
# print(type(ex.__traceback__))
try:
raise ZeroDivisionError
except ZeroDivisionError as ex:
pass
class E(Exception):
def __init__(self):
asdf
try:
raise E
except NameError as ex:
pass
l = []
try:

View File

@@ -5,32 +5,3 @@ assert x[0] == 1
y = (1,)
assert y[0] == 1
assert x + y == (1, 2, 1)
assert x * 3 == (1, 2, 1, 2, 1, 2)
# assert 3 * x == (1, 2, 1, 2, 1, 2)
assert x * 0 == ()
assert x * -1 == () # integers less than zero treated as 0
assert y < x, "tuple __lt__ failed"
assert x > y, "tuple __gt__ failed"
b = (1,2,3)
assert b.index(2) == 1
recursive_list = []
recursive = (recursive_list,)
recursive_list.append(recursive)
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,)

View File

@@ -1,7 +0,0 @@
# See also: https://github.com/RustPython/RustPython/issues/587
def curry(foo: int) -> float:
return foo * 3.1415926 * 2
assert curry(2) > 10

View File

@@ -1,33 +0,0 @@
def test_slice_bounds(s):
# End out of range
assert s[0:100] == s
assert s[0:-100] == ''
# Start out of range
assert s[100:1] == ''
# Out of range both sides
# This is the behaviour in cpython
# assert s[-100:100] == s
def expect_index_error(s, index):
try:
s[index]
except IndexError:
pass
else:
assert False
unicode_str = "∀∂"
assert unicode_str[0] == ""
assert unicode_str[1] == ""
assert unicode_str[-1] == ""
test_slice_bounds(unicode_str)
expect_index_error(unicode_str, 100)
expect_index_error(unicode_str, -100)
ascii_str = "hello world"
test_slice_bounds(ascii_str)
assert ascii_str[0] == "h"
assert ascii_str[1] == "e"
assert ascii_str[-1] == "d"

View File

@@ -8,6 +8,5 @@ class X:
a = X()
b = ref(a)
assert callable(b)
assert b() is a

View File

@@ -1,7 +1,4 @@
expected_methods = []
# TODO: using tuple could have been better
expected_methods.append({'name': 'bool', 'methods': [
bool_expected_methods = [
'__abs__',
'__add__',
'__and__',
@@ -72,8 +69,9 @@ expected_methods.append({'name': 'bool', 'methods': [
'numerator',
'real',
'to_bytes',
], 'type': bool})
expected_methods.append({'name': 'bytearray', 'type': bytearray, 'methods': [
]
bytearray_expected_methods = [
'__add__',
'__alloc__',
'__class__',
@@ -159,8 +157,9 @@ expected_methods.append({'name': 'bytearray', 'type': bytearray, 'methods': [
'translate',
'upper',
'zfill',
]})
expected_methods.append({'name': 'bytes', 'type': bytes, 'methods': [
]
bytes_expected_methods = [
'__add__',
'__class__',
'__contains__',
@@ -234,8 +233,9 @@ expected_methods.append({'name': 'bytes', 'type': bytes, 'methods': [
'translate',
'upper',
'zfill',
]})
expected_methods.append({'name': 'complex', 'type': complex, 'methods': [
]
complex_expected_methods = [
'__abs__',
'__add__',
'__bool__',
@@ -285,8 +285,9 @@ expected_methods.append({'name': 'complex', 'type': complex, 'methods': [
'conjugate',
'imag',
'real',
]})
expected_methods.append({'name': 'dict', 'type': dict, 'methods': [
]
dict_expected_methods = [
'__class__',
'__contains__',
'__delattr__',
@@ -327,8 +328,9 @@ expected_methods.append({'name': 'dict', 'type': dict, 'methods': [
'setdefault',
'update',
'values',
]})
expected_methods.append({'name': 'float','type':float,'methods':[
]
float_expected_methods = [
'__abs__',
'__add__',
'__bool__',
@@ -386,8 +388,9 @@ expected_methods.append({'name': 'float','type':float,'methods':[
'imag',
'is_integer',
'real',
]})
expected_methods.append({'name': 'frozenset','type':frozenset, 'methods': [
]
frozenset_expected_methods = [
'__and__',
'__class__',
'__contains__',
@@ -430,8 +433,9 @@ expected_methods.append({'name': 'frozenset','type':frozenset, 'methods': [
'issuperset',
'symmetric_difference',
'union',
]})
expected_methods.append({'name': 'int', 'type':int, 'methods': [
]
int_expected_methods = [
'__abs__',
'__add__',
'__and__',
@@ -502,8 +506,9 @@ expected_methods.append({'name': 'int', 'type':int, 'methods': [
'numerator',
'real',
'to_bytes',
]})
expected_methods.append({'name': 'iter','type':iter,'methods':[
]
iter_expected_methods = [
'__class__',
'__delattr__',
'__dir__',
@@ -531,8 +536,9 @@ expected_methods.append({'name': 'iter','type':iter,'methods':[
'__sizeof__',
'__str__',
'__subclasshook__',
]})
expected_methods.append({'name': 'list','type':list,'methods':[
]
list_expected_methods = [
'__add__',
'__class__',
'__contains__',
@@ -579,8 +585,9 @@ expected_methods.append({'name': 'list','type':list,'methods':[
'remove',
'reverse',
'sort',
]})
expected_methods.append({'name': 'memoryview','type':memoryview,'methods':[
]
memoryview_expected_methods = [
'__class__',
'__delattr__',
'__delitem__',
@@ -627,8 +634,9 @@ expected_methods.append({'name': 'memoryview','type':memoryview,'methods':[
'suboffsets',
'tobytes',
'tolist',
]})
expected_methods.append({'name': 'range','type':range,'methods':[
]
range_expected_methods = [
'__bool__',
'__class__',
'__contains__',
@@ -663,8 +671,9 @@ expected_methods.append({'name': 'range','type':range,'methods':[
'start',
'step',
'stop',
]})
expected_methods.append({'name': 'set','type':set,'methods':[
]
set_expected_methods = [
'__and__',
'__class__',
'__contains__',
@@ -720,8 +729,9 @@ expected_methods.append({'name': 'set','type':set,'methods':[
'symmetric_difference_update',
'union',
'update',
]})
expected_methods.append({'name': 'string','type':str,'methods':[
]
string_expected_methods = [
'__add__',
'__class__',
'__contains__',
@@ -800,8 +810,9 @@ expected_methods.append({'name': 'string','type':str,'methods':[
'translate',
'upper',
'zfill'
]})
expected_methods.append({'name': 'tuple','type':tuple, 'methods': [
]
tuple_expected_methods = [
'__add__',
'__class__',
'__contains__',
@@ -835,42 +846,116 @@ expected_methods.append({'name': 'tuple','type':tuple, 'methods': [
'__subclasshook__',
'count',
'index',
]})
expected_methods.append({'name': 'object', 'type':object, 'methods':[
'__repr__',
'__hash__',
'__str__',
'__getattribute__',
'__setattr__',
'__delattr__',
'__lt__',
'__le__',
'__eq__',
'__ne__',
'__gt__',
'__ge__',
'__init__',
'__new__',
'__reduce_ex__',
'__reduce__',
'__subclasshook__',
'__init_subclass__',
'__format__',
'__sizeof__',
'__dir__',
'__class__',
'__doc__'
]})
]
not_implemented = []
for item in expected_methods:
for method in item['methods']:
try:
if not hasattr(item['type'], method):
not_implemented.append((item['name'], method))
except NameError:
not_implemented.append((item['name'], method))
for method in bool_expected_methods:
try:
if not hasattr(bool, method):
not_implemented.append(("bool", method))
except NameError:
not_implemented.append(("bool", method))
for method in bytearray_expected_methods:
try:
if not hasattr(bytearray(), method):
not_implemented.append(("bytearray", method))
except NameError:
not_implemented.append(("bytearray", method))
for method in bytes_expected_methods:
try:
if not hasattr(bytes, method):
not_implemented.append(("bytes", method))
except NameError:
not_implemented.append(("bytes", method))
for method in complex_expected_methods:
try:
if not hasattr(complex, method):
not_implemented.append(("complex", method))
except NameError:
not_implemented.append(("complex", method))
for method in dict_expected_methods:
try:
if not hasattr(dict, method):
not_implemented.append(("dict", method))
except NameError:
not_implemented.append(("dict", method))
for method in float_expected_methods:
try:
if not hasattr(float, method):
not_implemented.append(("float", method))
except NameError:
not_implemented.append(("float", method))
for method in frozenset_expected_methods:
# TODO: uncomment this when frozenset is implemented
# try:
# if not hasattr(frozenset, method):
# not_implemented.append(("frozenset", method))
# except NameError:
not_implemented.append(("frozenset", method))
for method in int_expected_methods:
try:
if not hasattr(int, method):
not_implemented.append(("int", method))
except NameError:
not_implemented.append(("int", method))
for method in iter_expected_methods:
try:
if not hasattr(iter([]), method):
not_implemented.append(("iter", method))
except NameError:
not_implemented.append(("iter", method))
for method in list_expected_methods:
try:
if not hasattr(list, method):
not_implemented.append(("list", method))
except NameError:
not_implemented.append(("list", method))
for method in memoryview_expected_methods:
# TODO: uncomment this when memoryview is implemented
# try:
# if not hasattr(memoryview, method):
# not_implemented.append(("memoryview", method))
# except NameError:
not_implemented.append(("memoryview", method))
for method in range_expected_methods:
try:
if not hasattr(range, method):
not_implemented.append(("range", method))
except NameError:
not_implemented.append(("range", method))
for method in set_expected_methods:
try:
if not hasattr(set, method):
not_implemented.append(("set", method))
except NameError:
not_implemented.append(("set", method))
for method in string_expected_methods:
try:
if not hasattr(str, method):
not_implemented.append(("string", method))
except NameError:
not_implemented.append(("string", method))
for method in tuple_expected_methods:
try:
if not hasattr(tuple, method):
not_implemented.append(("tuple", method))
except NameError:
not_implemented.append(("tuple", method))
for r in not_implemented:
print(r[0], ".", r[1])

View File

@@ -77,12 +77,8 @@ 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'
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)
subprocess.check_call(
['cargo', 'run', '--release', filename], env=env)
def create_test_function(cls, filename, method, test_type):

View File

@@ -2,15 +2,12 @@
name = "rustpython_vm"
version = "0.1.0"
authors = ["Shing Lyu <shing.lyu@gmail.com>"]
edition = "2018"
[dependencies]
bitflags = "1.0.4"
num-complex = "0.2"
num-bigint = "0.2.1"
num-traits = "0.2"
num-integer = "0.1.39"
num-rational = "0.2.1"
rand = "0.5"
log = "0.3"
rustpython_parser = {path = "../parser"}
@@ -19,9 +16,4 @@ serde_derive = "1.0.66"
serde_json = "1.0.26"
byteorder = "1.2.6"
regex = "1"
rustc_version_runtime = "0.1.*"
statrs = "0.10.0"
caseless = "0.2.1"
unicode-segmentation = "1.2.1"
lazy_static = "^1.0.1"
lexical = "2.0.0"

Some files were not shown because too many files have changed in this diff Show More