From 277124fc1ffc19e328a061748355ed43d6fd99b1 Mon Sep 17 00:00:00 2001 From: Shing Lyu Date: Thu, 7 Jun 2018 00:09:09 +0200 Subject: [PATCH] Make the parser and vm two separate crates --- Cargo.lock | 927 ++++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- parser/Cargo.toml | 3 +- parser/src/compiler/mod.rs | 2 +- parser/src/lib.rs | 4 + src/main.rs | 3 + vm/RustPython/Cargo.toml | 2 +- vm/RustPython/src/lib.rs | 970 +++++++++++++++++++++++++++++++++++++ vm/RustPython/src/main.rs | 961 +----------------------------------- 9 files changed, 1910 insertions(+), 966 deletions(-) create mode 100644 parser/src/lib.rs create mode 100644 vm/RustPython/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f90d9eb171..f6336ceeeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,4 +1,927 @@ [[package]] -name = "RustPython" -version = "0.1.0" +name = "aho-corasick" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] +[[package]] +name = "aho-corasick" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +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 = "arrayref" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ascii-canvas" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit-set" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit-vec" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "diff" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "digest" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "docopt" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", + "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dtoa" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "either" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ena" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "env_logger" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.5.10" +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.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 = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fixedbitset" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "generic-array" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "humantime" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lalrpop" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lalrpop-snap 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lalrpop-util 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (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)", + "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (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 = "lalrpop-snap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lalrpop-util 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (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 = "lalrpop-util" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.42" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.1" +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 = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ordermap" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "petgraph" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_generator" +version = "0.7.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_shared" +version = "0.7.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex-syntax" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex-syntax" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustpython" +version = "0.1.0" +dependencies = [ + "rustpython_parser 0.0.1", + "rustpython_vm 0.1.0", +] + +[[package]] +name = "rustpython_parser" +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)", + "lalrpop 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lalrpop-util 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustpython_vm" +version = "0.1.0" +dependencies = [ + "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_codegen" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_codegen_internals" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_codegen 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sha2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "siphasher" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "string_cache" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", + "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "string_cache_codegen" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "string_cache_shared" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.6 (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 = "term" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread-id" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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]] +name = "typenum" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "utf8-ranges" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf8-ranges" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wincolor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" +"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0fd1479b7c29641adbd35ff3b5c293922d696a92f25c8c975da3e0acbc87258f" +"checksum ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b385d69402821a1c254533a011a312531cbcc0e3e24f19bbb4747a5a2daf37e2" +"checksum atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0fd4c0631f06448cc45a6bbb3b710ebb7ff8ccb96a0800c994afe23a70d5df2" +"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" +"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" +"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" +"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +"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 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" +"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" +"checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a" +"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d" +"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.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" +"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" +"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 generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +"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.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum 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.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" +"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" +"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" +"checksum petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8b30dc85588cd02b9b76f5e386535db546d21dc68506cff2abebee0b6445e8e4" +"checksum phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "05a079dd052e7b674d21cb31cbb6c05efd56a2cd2827db7692e2f1a507ebd998" +"checksum phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2261d544c2bb6aa3b10022b0be371b9c7c64f762ef28c6f5d4f1ef6d97b5930" +"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" +"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" +"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" +"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" +"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" +"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" +"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" +"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 serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" +"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" +"checksum serde_codegen 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c5d8a33087d8984f9535daa62a6498a08f6476050b00ab9339dd847e4c25cc" +"checksum serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "afad7924a009f859f380e4a2e3a509a845c2ac66435fcead74a4d983b21ae806" +"checksum serde_derive 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "ce44e5f4264b39e9d29c875357b7cc3ebdfb967bb9e22bfb5e44ffa400af5306" +"checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" +"checksum serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "67f7d2e9edc3523a9c8ec8cd6ec481b3a27810aafee3e625d311febd3e656b4c" +"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 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" +"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" +"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.10.8 (registry+https://github.com/rust-lang/crates.io-index)" = "58fd09df59565db3399efbba34ba8a2fec1307511ebd245d0061ff9d42691673" +"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" +"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 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-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" +"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" +"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" +"checksum 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-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" +"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum 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 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-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" diff --git a/Cargo.toml b/Cargo.toml index 7b6810b7f9..b64bb456c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,8 @@ [package] -name = "RustPython" +name = "rustpython" version = "0.1.0" authors = ["Windel Bouwman", "Shing Lyu "] [dependencies] +rustpython_parser = {path = "parser"} +rustpython_vm = {path = "vm/RustPython"} diff --git a/parser/Cargo.toml b/parser/Cargo.toml index e647fa7af9..c2e84b5d7a 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -1,6 +1,5 @@ - [package] -name = "RustPython" +name = "rustpython_parser" version = "0.0.1" authors = [ "Shing Lyu", "Windel Bouwman" ] build = "build.rs" diff --git a/parser/src/compiler/mod.rs b/parser/src/compiler/mod.rs index f14365bf12..9c210f48f9 100644 --- a/parser/src/compiler/mod.rs +++ b/parser/src/compiler/mod.rs @@ -19,4 +19,4 @@ pub use self::vm::evaluate; // Mimic eval code objects: //pub fn eval_code() -> pyobject::PyObjectRef { -//} \ No newline at end of file +//} diff --git a/parser/src/lib.rs b/parser/src/lib.rs new file mode 100644 index 0000000000..d8cba2c32f --- /dev/null +++ b/parser/src/lib.rs @@ -0,0 +1,4 @@ +#[macro_use] +extern crate log; + +mod compiler; diff --git a/src/main.rs b/src/main.rs index ee80563901..1d64191077 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +//extern crate rustpython_parser; +extern crate rustpython_vm; + fn main() { unimplemented!(); } diff --git a/vm/RustPython/Cargo.toml b/vm/RustPython/Cargo.toml index 39d864dcfb..24a2e6fbda 100644 --- a/vm/RustPython/Cargo.toml +++ b/vm/RustPython/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rustpython" +name = "rustpython_vm" version = "0.1.0" authors = ["Shing Lyu "] diff --git a/vm/RustPython/src/lib.rs b/vm/RustPython/src/lib.rs new file mode 100644 index 0000000000..c8f3119e1b --- /dev/null +++ b/vm/RustPython/src/lib.rs @@ -0,0 +1,970 @@ +#[macro_use] +extern crate log; +extern crate env_logger; + +#[macro_use] +extern crate serde_derive; +extern crate serde_json; + +//extern crate eval; use eval::eval::*; +use std::collections::HashMap; +use std::cell::RefCell; +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::rc::Rc; +use std::ops::Deref; + +mod builtins; + +#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] +pub enum NativeType{ + NoneType, + Boolean(bool), + Int(i32), + Float(f64), + Str(String), + Unicode(String), + #[serde(skip_serializing, skip_deserializing)] + List(RefCell>), + Tuple(Vec), + Iter(Vec), // TODO: use Iterator instead + Code(PyCodeObject), + Function(Function), + Slice(Option, Option, Option), // start, stop, step + #[serde(skip_serializing, skip_deserializing)] + NativeFunction(fn(Vec>) -> NativeType ), +} + +const CMP_OP: &'static [&'static str] = &[">", + "<=", + "==", + "!=", + ">", + ">=", + "in", + "not in", + "is", + "is not", + "exception match", + "BAD" + ]; + +#[derive(Clone)] +struct Block { + block_type: String, //Enum? + handler: usize // The destination we should jump to if the block finishes + // level? +} + +struct Frame { + // TODO: We are using Option in stack for handline None return value + code: PyCodeObject, + // We need 1 stack per frame + stack: Vec>, // The main data frame of the stack machine + blocks: Vec, // Block frames, for controling loops and exceptions + globals: HashMap>, // Variables + locals: HashMap>, // Variables + labels: HashMap, // Maps label id to line number, just for speedup + lasti: usize, // index of last instruction ran + return_value: NativeType, + why: String, //Not sure why we need this //Maybe use a enum if we have fininte options + // cmp_op: Vec<&'a Fn(NativeType, NativeType) -> bool>, // TODO: change compare to a function list +} + +impl Frame { + /// Get the current bytecode offset calculated from curr_frame.lasti + fn get_bytecode_offset(&self) -> Option { + // Linear search the labels HashMap, inefficient. Consider build a reverse HashMap + let mut last_offset = None; + for (offset, instr_idx) in self.labels.iter() { + if *instr_idx == self.lasti { + last_offset = Some(*offset) + } + } + last_offset + } +} + +#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +pub struct Function { + code: PyCodeObject +} + +impl Function { + fn new(code: PyCodeObject) -> Function { + Function { + code: code + } + } +} + + +pub struct VirtualMachine{ + frames: Vec, +} + +impl VirtualMachine { + pub fn new() -> VirtualMachine { + VirtualMachine { + frames: vec![], + } + } + + fn curr_frame(&mut self) -> &mut Frame { + self.frames.last_mut().unwrap() + } + + fn pop_frame(&mut self) { + self.frames.pop().unwrap(); + } + + fn unwind(&mut self, reason: String) { + let curr_frame = self.curr_frame(); + let curr_block = curr_frame.blocks[curr_frame.blocks.len()-1].clone(); // use last? + curr_frame.why = reason; // Why do we need this? + debug!("block status: {:?}, {:?}", curr_block.block_type, curr_frame.why); + match (curr_block.block_type.as_ref(), curr_frame.why.as_ref()) { + ("loop", "break") => { + curr_frame.lasti = curr_block.handler; //curr_frame.labels[curr_block.handler]; // Jump to the end + // Return the why as None + curr_frame.blocks.pop(); + }, + ("loop", "none") => (), //skipped + _ => panic!("block stack operation not implemented") + } + } + + // Can we get rid of the code paramter? + + fn make_frame(&self, code: PyCodeObject, callargs: HashMap>, globals: Option>>) -> Frame { + //populate the globals and locals + let mut labels = HashMap::new(); + let mut curr_offset = 0; + for (idx, op) in code.co_code.iter().enumerate() { + labels.insert(curr_offset, idx); + curr_offset += op.0; + } + //TODO: This is wrong, check https://github.com/nedbat/byterun/blob/31e6c4a8212c35b5157919abff43a7daa0f377c6/byterun/pyvm2.py#L95 + let globals = match globals { + Some(g) => g, + None => HashMap::new(), + }; + let mut locals = globals; + locals.extend(callargs); + + //TODO: move this into the __builtin__ module when we have a module type + locals.insert("print".to_string(), Rc::new(NativeType::NativeFunction(builtins::print))); + locals.insert("len".to_string(), Rc::new(NativeType::NativeFunction(builtins::len))); + Frame { + code: code, + stack: vec![], + blocks: vec![], + // save the callargs as locals + globals: locals.clone(), + locals: locals, + labels: labels, + lasti: 0, + return_value: NativeType::NoneType, + why: "none".to_string(), + } + } + + // The Option is the return value of the frame, remove when we have implemented frame + // TODO: read the op codes directly from the internal code object + fn run_frame(&mut self, frame: Frame) -> NativeType { + self.frames.push(frame); + + //let mut why = None; + // Change this to a loop for jump + loop { + //while curr_frame.lasti < curr_frame.code.co_code.len() { + let op_code = { + let curr_frame = self.curr_frame(); + let op_code = curr_frame.code.co_code[curr_frame.lasti].clone(); + curr_frame.lasti += 1; + op_code + }; + let why = self.dispatch(op_code); + /*if curr_frame.blocks.len() > 0 { + self.manage_block_stack(&why); + } + */ + if let Some(_) = why { + break; + } + } + let return_value = { + //let curr_frame = self.frames.last_mut().unwrap(); + self.curr_frame().return_value.clone() + }; + self.pop_frame(); + return_value + } + + pub fn run_code(&mut self, code: PyCodeObject) { + let frame = self.make_frame(code, HashMap::new(), None); + self.run_frame(frame); + // check if there are any leftover frame, fail if any + } + + fn dispatch(&mut self, op_code: (usize, String, Option)) -> Option { + { + debug!("stack:{:?}", self.curr_frame().stack); + debug!("env :{:?}", self.curr_frame().locals); + debug!("Executing op code: {:?}", op_code); + } + match (op_code.1.as_ref(), op_code.2) { + ("LOAD_CONST", Some(consti)) => { + // println!("Loading const at index: {}", consti); + let curr_frame = self.curr_frame(); + curr_frame.stack.push(Rc::new(curr_frame.code.co_consts[consti].clone())); + None + }, + + // TODO: universal stack element type + ("LOAD_CONST", None) => { + // println!("Loading const at index: {}", consti); + self.curr_frame().stack.push(Rc::new(NativeType::NoneType)); + None + }, + ("POP_TOP", None) => { + self.curr_frame().stack.pop(); + None + }, + ("LOAD_FAST", Some(var_num)) => { + // println!("Loading const at index: {}", consti); + let curr_frame = self.curr_frame(); + let ref name = curr_frame.code.co_varnames[var_num]; + curr_frame.stack.push(curr_frame.locals.get::(name).unwrap().clone()); + None + }, + ("STORE_NAME", Some(namei)) => { + // println!("Loading const at index: {}", consti); + let curr_frame = self.curr_frame(); + curr_frame.locals.insert(curr_frame.code.co_names[namei].clone(), curr_frame.stack.pop().unwrap().clone()); + None + }, + ("LOAD_NAME", Some(namei)) => { + // println!("Loading const at index: {}", consti); + let curr_frame = self.curr_frame(); + if let Some(code) = curr_frame.locals.get::(&curr_frame.code.co_names[namei]) { + curr_frame.stack.push(code.clone()); + } + else { + panic!("Can't find symbol {:?} in the current frame", &curr_frame.code.co_names[namei]); + } + None + }, + ("LOAD_GLOBAL", Some(namei)) => { + // We need to load the underlying value the name points to, but stuff like + // AssertionError is in the names right after compile, so we load the string + // instead for now + let curr_frame = self.curr_frame(); + let name = &curr_frame.code.co_names[namei]; + curr_frame.stack.push(curr_frame.globals.get::(name).unwrap().clone()); + None + }, + + ("BUILD_LIST", Some(count)) => { + let curr_frame = self.curr_frame(); + let mut vec = vec!(); + for _ in 0..count { + vec.push((*curr_frame.stack.pop().unwrap()).clone()); + } + vec.reverse(); + curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(vec)))); + None + }, + + ("BUILD_SLICE", Some(count)) => { + let curr_frame = self.curr_frame(); + assert!(count == 2 || count == 3); + let mut vec = vec!(); + for _ in 0..count { + vec.push(curr_frame.stack.pop().unwrap()); + } + vec.reverse(); + let mut out:Vec> = vec.into_iter().map(|x| match *x { + NativeType::Int(n) => Some(n), + NativeType::NoneType => None, + _ => panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x), + }).collect(); + + if out.len() == 2 { + out.push(None); + } + assert!(out.len() == 3); + // TODO: assert the stop start and step are NativeType::Int + // See https://users.rust-lang.org/t/how-do-you-assert-enums/1187/8 + curr_frame.stack.push(Rc::new(NativeType::Slice(out[0], out[1], out[2]))); + None + }, + + ("GET_ITER", None) => { + let curr_frame = self.curr_frame(); + let tos = curr_frame.stack.pop().unwrap(); + let iter = match *tos { + //TODO: is this clone right? + // Return a Iterator instead vvv + NativeType::Tuple(ref vec) => NativeType::Iter(vec.clone()), + NativeType::List(ref vec) => NativeType::Iter(vec.borrow().clone()), + _ => panic!("TypeError: object is not iterable") + }; + curr_frame.stack.push(Rc::new(iter)); + None + }, + + ("FOR_ITER", Some(delta)) => { + // This function should be rewrote to use Rust native iterator + let curr_frame = self.curr_frame(); + let tos = curr_frame.stack.pop().unwrap(); + let result = match *tos { + NativeType::Iter(ref v) => { + if v.len() > 0 { + Some(v.clone()) // Unnessary clone here + } + else { + None + } + } + _ => panic!("FOR_ITER: Not an iterator") + }; + if let Some(vec) = result { + let (first, rest) = vec.split_first().unwrap(); + // Unnessary clone here + curr_frame.stack.push(Rc::new(NativeType::Iter(rest.to_vec()))); + curr_frame.stack.push(Rc::new(first.clone())); + } + else { + // Iterator was already poped in the first line of this function + let last_offset = curr_frame.get_bytecode_offset().unwrap(); + curr_frame.lasti = curr_frame.labels.get(&(last_offset + delta)).unwrap().clone(); + + } + None + }, + + ("COMPARE_OP", Some(cmp_op_i)) => { + let curr_frame = self.curr_frame(); + let v1 = curr_frame.stack.pop().unwrap(); + let v2 = curr_frame.stack.pop().unwrap(); + match CMP_OP[cmp_op_i] { + // To avoid branch explotion, use an array of callables instead + "==" => { + match (v1.deref(), v2.deref()) { + (&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Boolean(v2i == v1i))); + }, + (&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => { + curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f == v1f))); + }, + (&NativeType::Str(ref v1s), &NativeType::Str(ref v2s)) => { + curr_frame.stack.push(Rc::new(NativeType::Boolean(v2s == v1s))); + }, + (&NativeType::Int(ref v1i), &NativeType::Float(ref v2f)) => { + curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f == &(*v1i as f64)))); + }, + (&NativeType::List(ref l1), &NativeType::List(ref l2)) => { + curr_frame.stack.push(Rc::new(NativeType::Boolean(l2 == l1))); + }, + _ => panic!("TypeError in COMPARE_OP: can't compare {:?} with {:?}", v1, v2) + }; + } + ">" => { + match (v1.deref(), v2.deref()) { + (&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Boolean(v2i < v1i))); + }, + (&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => { + curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f < v1f))); + }, + _ => panic!("TypeError in COMPARE_OP") + }; + } + _ => panic!("Unimplemented COMPARE_OP operator") + + } + None + + }, + ("POP_JUMP_IF_TRUE", Some(ref target)) => { + let curr_frame = self.curr_frame(); + let v = curr_frame.stack.pop().unwrap(); + if *v == NativeType::Boolean(true) { + curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone(); + } + None + + } + ("POP_JUMP_IF_FALSE", Some(ref target)) => { + let curr_frame = self.curr_frame(); + let v = curr_frame.stack.pop().unwrap(); + if *v == NativeType::Boolean(false) { + curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone(); + } + None + + } + ("JUMP_FORWARD", Some(ref delta)) => { + let curr_frame = self.curr_frame(); + let last_offset = curr_frame.get_bytecode_offset().unwrap(); + curr_frame.lasti = curr_frame.labels.get(&(last_offset + delta)).unwrap().clone(); + None + }, + ("JUMP_ABSOLUTE", Some(ref target)) => { + let curr_frame = self.curr_frame(); + curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone(); + None + }, + ("BREAK_LOOP", None) => { + // Do we still need to return the why if we use unwind from jsapy? + self.unwind("break".to_string()); + None //? + }, + ("RAISE_VARARGS", Some(argc)) => { + let curr_frame = self.curr_frame(); + // let (exception, params, traceback) = match argc { + let exception = match argc { + 1 => curr_frame.stack.pop().unwrap(), + 0 | 2 | 3 => panic!("Not implemented!"), + _ => panic!("Invalid paramter for RAISE_VARARGS, must be between 0 to 3") + }; + panic!("{:?}", exception); + } + ("INPLACE_ADD", None) => { + let curr_frame = self.curr_frame(); + let tos = curr_frame.stack.pop().unwrap(); + let tos1 = curr_frame.stack.pop().unwrap(); + match (tos.deref(), tos1.deref()) { + (&NativeType::Int(ref tosi), &NativeType::Int(ref tos1i)) => { + curr_frame.stack.push(Rc::new(NativeType::Int(tos1i + tosi))); + }, + _ => panic!("TypeError in BINARY_ADD") + } + None + }, + + ("STORE_SUBSCR", None) => { + let curr_frame = self.curr_frame(); + let tos = curr_frame.stack.pop().unwrap(); + let tos1 = curr_frame.stack.pop().unwrap(); + let tos2 = curr_frame.stack.pop().unwrap(); + match (tos1.deref(), tos.deref()) { + (&NativeType::List(ref refl), &NativeType::Int(index)) => { + refl.borrow_mut()[index as usize] = (*tos2).clone(); + }, + (&NativeType::Str(_), &NativeType::Int(_)) => { + // TODO: raise TypeError: 'str' object does not support item assignment + panic!("TypeError: 'str' object does not support item assignment") + }, + _ => panic!("TypeError in STORE_SUBSCR") + } + curr_frame.stack.push(tos1); + None + }, + + ("BINARY_ADD", None) => { + let curr_frame = self.curr_frame(); + let v1 = curr_frame.stack.pop().unwrap(); + let v2 = curr_frame.stack.pop().unwrap(); + match (v1.deref(), v2.deref()) { + (&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Int(v2i + v1i))); + } + (&NativeType::Float(ref v1f), &NativeType::Int(ref v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Float(*v2i as f64 + v1f))); + } + (&NativeType::Int(ref v1i), &NativeType::Float(ref v2f)) => { + curr_frame.stack.push(Rc::new(NativeType::Float(v2f + *v1i as f64))); + } + (&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => { + curr_frame.stack.push(Rc::new(NativeType::Float(v2f + v1f))); + } + (&NativeType::Str(ref str1), &NativeType::Str(ref str2)) => { + curr_frame.stack.push(Rc::new(NativeType::Str(format!("{}{}", str2, str1)))); + } + (&NativeType::List(ref l1), &NativeType::List(ref l2)) => { + let mut new_l = l2.clone(); + // TODO: remove unnessary copy + new_l.borrow_mut().append(&mut l1.borrow().clone()); + curr_frame.stack.push(Rc::new(NativeType::List(new_l))); + + } + _ => panic!("TypeError in BINARY_ADD") + } + None + }, + ("BINARY_POWER", None) => { + let curr_frame = self.curr_frame(); + let v1 = curr_frame.stack.pop().unwrap(); + let v2 = curr_frame.stack.pop().unwrap(); + match (v1.deref(), v2.deref()) { + (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Int(v2i.pow(v1i as u32)))); + } + (&NativeType::Float(v1f), &NativeType::Int(v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Float((v2i as f64).powf(v1f)))); + } + (&NativeType::Int(v1i), &NativeType::Float(v2f)) => { + curr_frame.stack.push(Rc::new(NativeType::Float(v2f.powi(v1i)))); + } + (&NativeType::Float(v1f), &NativeType::Float(v2f)) => { + curr_frame.stack.push(Rc::new(NativeType::Float(v2f.powf(v1f)))); + } + _ => panic!("TypeError in BINARY_POWER") + } + None + }, + ("BINARY_MULTIPLY", None) => { + let curr_frame = self.curr_frame(); + let v1 = curr_frame.stack.pop().unwrap(); + let v2 = curr_frame.stack.pop().unwrap(); + match (v1.deref(), v2.deref()) { + (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Int(v2i * v1i))); + }, + /* + (NativeType::Float(v1f), NativeType::Int(v2i)) => { + curr_frame.stack.push(NativeType::Float((v2i as f64) * v1f)); + }, + (NativeType::Int(v1i), NativeType::Float(v2f)) => { + curr_frame.stack.push(NativeType::Float(v2f * (v1i as f64))); + }, + (NativeType::Float(v1f), NativeType::Float(v2f)) => { + curr_frame.stack.push(NativeType::Float(v2f * v1f)); + }, + */ + //TODO: String multiply + _ => panic!("TypeError in BINARY_MULTIPLY") + } + None + }, + ("BINARY_TRUE_DIVIDE", None) => { + let curr_frame = self.curr_frame(); + let v1 = curr_frame.stack.pop().unwrap(); + let v2 = curr_frame.stack.pop().unwrap(); + match (v1.deref(), v2.deref()) { + (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Int(v2i / v1i))); + }, + _ => panic!("TypeError in BINARY_DIVIDE") + } + None + }, + ("BINARY_MODULO", None) => { + let curr_frame = self.curr_frame(); + let v1 = curr_frame.stack.pop().unwrap(); + let v2 = curr_frame.stack.pop().unwrap(); + match (v1.deref(), v2.deref()) { + (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Int(v2i % v1i))); + }, + _ => panic!("TypeError in BINARY_MODULO") + } + None + }, + ("BINARY_SUBTRACT", None) => { + let curr_frame = self.curr_frame(); + let v1 = curr_frame.stack.pop().unwrap(); + let v2 = curr_frame.stack.pop().unwrap(); + match (v1.deref(), v2.deref()) { + (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { + curr_frame.stack.push(Rc::new(NativeType::Int(v2i - v1i))); + }, + _ => panic!("TypeError in BINARY_SUBSTRACT") + } + None + }, + + ("BINARY_SUBSCR", None) => { + let curr_frame = self.curr_frame(); + let tos = curr_frame.stack.pop().unwrap(); + let tos1 = curr_frame.stack.pop().unwrap(); + debug!("tos: {:?}, tos1: {:?}", tos, tos1); + match (tos1.deref(), tos.deref()) { + (&NativeType::List(ref l), &NativeType::Int(ref index)) => { + let pos_index = (index + l.borrow().len() as i32) % l.borrow().len() as i32; + curr_frame.stack.push(Rc::new(l.borrow()[pos_index as usize].clone())) + }, + (&NativeType::List(ref l), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => { + let start = match opt_start { + &Some(start) => ((start + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, + &None => 0, + }; + let stop = match opt_stop { + &Some(stop) => ((stop + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, + &None => l.borrow().len() as usize, + }; + let step = match opt_step { + //Some(step) => step as usize, + &None => 1 as usize, + _ => unimplemented!(), + }; + // TODO: we could potentially avoid this copy and use slice + curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(l.borrow()[start..stop].to_vec())))); + }, + (&NativeType::Tuple(ref t), &NativeType::Int(ref index)) => curr_frame.stack.push(Rc::new(t[*index as usize].clone())), + (&NativeType::Str(ref s), &NativeType::Int(ref index)) => { + let idx = (index + s.len() as i32) % s.len() as i32; + curr_frame.stack.push(Rc::new(NativeType::Str(s.chars().nth(idx as usize).unwrap().to_string()))); + }, + (&NativeType::Str(ref s), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => { + let start = match opt_start { + &Some(start) if start > s.len() as i32 => s.len(), + &Some(start) if start <= s.len() as i32 => ((start + s.len() as i32) % s.len() as i32) as usize, + &Some(_) => panic!("Bad start index for string slicing"), + &Some(start) => ((start + s.len() as i32) % s.len() as i32) as usize, + &None => 0, + }; + let stop = match opt_stop { + &Some(stop) if stop > s.len() as i32 => s.len(), + &Some(stop) if stop <= s.len() as i32 => ((stop + s.len() as i32) % s.len() as i32) as usize, // Do we need this modding? + &Some(_) => panic!("Bad stop index for string slicing"), + &None => s.len() as usize, + }; + let step = match opt_step { + //Some(step) => step as usize, + &None => 1 as usize, + _ => unimplemented!(), + }; + curr_frame.stack.push(Rc::new(NativeType::Str(s[start..stop].to_string()))); + }, + // TODO: implement other Slice possibilities + _ => panic!("TypeError: indexing type {:?} with index {:?} is not supported (yet?)", tos1, tos) + }; + None + }, + ("ROT_TWO", None) => { + let curr_frame = self.curr_frame(); + let tos = curr_frame.stack.pop().unwrap(); + let tos1 = curr_frame.stack.pop().unwrap(); + curr_frame.stack.push(tos); + curr_frame.stack.push(tos1); + None + } + ("UNARY_NEGATIVE", None) => { + let curr_frame = self.curr_frame(); + let v = curr_frame.stack.pop().unwrap(); + match v.deref() { + &NativeType::Int(v1i) => { + curr_frame.stack.push(Rc::new(NativeType::Int(-v1i))); + }, + _ => panic!("TypeError in UINARY_NEGATIVE") + } + None + }, + ("UNARY_POSITIVE", None) => { + let curr_frame = self.curr_frame(); + let v = curr_frame.stack.pop().unwrap(); + // Any case that is not just push back? + curr_frame.stack.push(v); + None + }, + ("PRINT_ITEM", None) => { + let curr_frame = self.curr_frame(); + // TODO: Print without the (...) + println!("{:?}", curr_frame.stack.pop().unwrap()); + None + }, + ("PRINT_NEWLINE", None) => { + print!("\n"); + None + }, + ("MAKE_FUNCTION", Some(argc)) => { + // https://docs.python.org/3.4/library/dis.html#opcode-MAKE_FUNCTION + let curr_frame = self.curr_frame(); + let qualified_name = curr_frame.stack.pop().unwrap(); + let code_obj = match curr_frame.stack.pop().unwrap().deref() { + &NativeType::Code(ref code) => code.clone(), + _ => panic!("Second item on the stack should be a code object") + }; + // pop argc arguments + // argument: name, args, globals + let func = Function::new(code_obj); + curr_frame.stack.push(Rc::new(NativeType::Function(func))); + None + }, + ("CALL_FUNCTION", Some(argc)) => { + let kw_count = (argc >> 8) as u8; + let pos_count = (argc & 0xFF) as u8; + // Pop the arguments based on argc + let mut kw_args = HashMap::new(); + let mut pos_args = Vec::new(); + { + let curr_frame = self.curr_frame(); + for _ in 0..kw_count { + let native_val = curr_frame.stack.pop().unwrap(); + let native_key = curr_frame.stack.pop().unwrap(); + if let (ref val, &NativeType::Str(ref key)) = (native_val, native_key.deref()) { + + kw_args.insert(key.clone(), val.clone()); + } + else { + panic!("Incorrect type found while building keyword argument list") + } + } + for _ in 0..pos_count { + pos_args.push(curr_frame.stack.pop().unwrap()); + } + } + let locals = { + // FIXME: no clone here + self.curr_frame().locals.clone() + }; + + let func = { + match self.curr_frame().stack.pop().unwrap().deref() { + &NativeType::Function(ref func) => { + // pop argc arguments + // argument: name, args, globals + // build the callargs hashmap + pos_args.reverse(); + let mut callargs = HashMap::new(); + for (name, val) in func.code.co_varnames.iter().zip(pos_args) { + callargs.insert(name.to_string(), val); + } + // merge callargs with kw_args + let return_value = { + let frame = self.make_frame(func.code.clone(), callargs, Some(locals)); + self.run_frame(frame) + }; + self.curr_frame().stack.push(Rc::new(return_value)); + }, + &NativeType::NativeFunction(func) => { + pos_args.reverse(); + let return_value = func(pos_args); + self.curr_frame().stack.push(Rc::new(return_value)); + }, + _ => panic!("The item on the stack should be a code object") + } + }; + None + }, + ("RETURN_VALUE", None) => { + // Hmmm... what is this used? + // I believe we need to push this to the next frame + self.curr_frame().return_value = (*self.curr_frame().stack.pop().unwrap()).clone(); + Some("return".to_string()) + }, + ("SETUP_LOOP", Some(delta)) => { + let curr_frame = self.curr_frame(); + let curr_offset = curr_frame.get_bytecode_offset().unwrap(); + curr_frame.blocks.push(Block { + block_type: "loop".to_string(), + handler: *curr_frame.labels.get(&(curr_offset + delta)).unwrap(), + }); + None + }, + ("POP_BLOCK", None) => { + self.curr_frame().blocks.pop(); + None + } + ("SetLineno", _) | ("LABEL", _)=> { + // Skip + None + }, + (name, _) => { + panic!("Unrecongnizable op code: {}", name); + } + } // end match + } // end dispatch function +} + +#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] +pub struct PyCodeObject { + co_consts: Vec, + co_names: Vec, + co_code: Vec<(usize, String, Option)>, //size, name, args + co_varnames: Vec, +} + + +/* +fn parse_native_type(val_str: &str) -> Result { + // println!("{:?}", val_str); + match val_str { + "None" => Ok(NativeType::NoneType), + "True" => Ok(NativeType::Boolean(true)), + "False" => Ok(NativeType::Boolean(false)), + _ => { + if let Ok(int) = val_str.parse::() { + return Ok(NativeType::Int(int)) + } + + if let Ok(float) = val_str.parse::() { + return Ok(NativeType::Float(float)) + } + + if val_str.starts_with("\'") && val_str.ends_with("\'") { + return Ok(NativeType::Str(val_str[1..val_str.len()-1].to_string())) + } + + if val_str.starts_with("u\'") && val_str.ends_with("\'") { + return Ok(NativeType::Unicode(val_str[2..val_str.len()-1].to_string())) + } + + if val_str.starts_with("(") && val_str.ends_with(")") { + return Ok(NativeType::Str(val_str[1..val_str.len()-1].to_string())) + } + + Err(()) + } + + } +} + +fn parse_bytecode(s: &str) -> Code { + let lines: Vec<&str> = s.split('\n').collect(); + + let (metadata, ops) = lines.split_at(2); + // Parsing the first line CONSTS + let consts_str: &str = metadata[0]; // line 0 is empty + let values_str = &consts_str[("CONSTS: (".len())..(consts_str.len()-1)]; + let values: Vec<&str> = values_str.split(",").collect(); + // We need better type definition here + let consts: Vec= values.into_iter() + .map(|x| x.trim()) + .filter(|x| x.len() > 0) + .map(|x| parse_native_type(x).unwrap()) + .collect(); + + // Parsing the second line NAMES + let names_str: &str = metadata[1]; // line 0 is empty + let values_str = &names_str[("NAMES: (".len())..(names_str.len()-1)]; + let values: Vec<&str> = values_str.split(",").collect(); + // We are assuming the first and last chars are \' + let names: Vec<&str>= values.into_iter().map(|x| x.trim()) + .filter(|x| x.len() > 0) + .map(|x| &x[1..(x.len()-1)]).collect(); + + // Parsing the op_codes + let op_codes: Vec<(&str, Option)>= ops.into_iter() + .map(|x| x.trim()) + .filter(|x| x.len() > 0) + .map(|x| { + let op: Vec<&str> = x.split(", ").collect(); + // println!("{:?}", op); + (op[0], op[1].parse::().ok()) + }).collect(); + + + Code { + consts: consts, + op_codes: op_codes, + names: names, + } +} +*/ + +/* +#[test] +fn test_parse_native_type() { + + assert_eq!(NativeType::NoneType, parse_native_type("None").unwrap()); + assert_eq!(NativeType::Boolean(true), parse_native_type("True").unwrap()); + assert_eq!(NativeType::Boolean(false), parse_native_type("False").unwrap()); + assert_eq!(NativeType::Int(3), parse_native_type("3").unwrap()); + assert_eq!(NativeType::Float(3.0), parse_native_type("3.0").unwrap()); + assert_eq!(NativeType::Float(3.5), parse_native_type("3.5").unwrap()); + assert_eq!(NativeType::Str("foo".to_string()), parse_native_type("\'foo\'").unwrap()); + assert_eq!(NativeType::Unicode("foo".to_string()), parse_native_type("u\'foo\'").unwrap()); +} + +#[test] +fn test_parse_bytecode() { + + let input = "CONSTS: (1, None, 2) +NAMES: ('a', 'b') +SetLineno, 1 +LOAD_CONST, 2 +PRINT_ITEM, None +PRINT_NEWLINE, None +LOAD_CONST, None +RETURN_VALUE, None + "; + let expected = Code { // Fill me with a more sensible data + consts: vec![NativeType::Int(1), NativeType::NoneType, NativeType::Int(2)], + names: vec!["a", "b"], + op_codes: vec![ + ("SetLineno", Some(1)), + ("LOAD_CONST", Some(2)), + ("PRINT_ITEM", None), + ("PRINT_NEWLINE", None), + ("LOAD_CONST", None), + ("RETURN_VALUE", None) + ] + }; + + assert_eq!(expected, parse_bytecode(input)); +} + +#[test] +fn test_single_const_tuple() { + let input = "CONSTS: (None,) +NAMES: () +SetLineno, 1 +LOAD_CONST, 0 +RETURN_VALUE, None +"; + let expected = Code { // Fill me with a more sensible data + consts: vec![NativeType::NoneType], + names: vec![], + op_codes: vec![ + ("SetLineno", Some(1)), + ("LOAD_CONST", Some(0)), + ("RETURN_VALUE", None) + ] + }; + + assert_eq!(expected, parse_bytecode(input)); +} + +#[test] +fn test_vm() { + + let code = PyCodeObject { + co_consts: vec![NativeType::Int(1), NativeType::NoneType, NativeType::Int(2)], + co_names: vec![], + co_code: vec![ + (3, "LOAD_CONST".to_string(), Some(2)), + (1, "PRINT_ITEM".to_string(), None), + (1, "PRINT_NEWLINE".to_string(), None), + (3, "LOAD_CONST".to_string(), None), + (1, "RETURN_VALUE".to_string(), None) + ] + }; + let mut vm = VirtualMachine::new(); + assert_eq!((), vm.exec(&code)); +} + + +#[test] +fn test_parse_jsonbytecode() { + +let input = "{\"co_consts\":[{\"Int\":1},\"NoneType\",{\"Int\":2}],\"co_names\":[\"print\"],\"co_code\":[[3,\"LOAD_CONST\",2],[1,\"PRINT_ITEM\",null],[1,\"PRINT_NEWLINE\",null],[3,\"LOAD_CONST\",null],[1,\"RETURN_VALUE\",null]]}"; +// let input = "{\"co_names\": [\"print\"], \"co_code\": [[\"LOAD_CONST\", 0], [\"LOAD_CONST\", 0], [\"COMPARE_OP\", 2], [\"POP_JUMP_IF_FALSE\", 25], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 1], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"JUMP_FORWARD\", 10], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 2], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"LOAD_CONST\", 0], [\"LOAD_CONST\", 3], [\"COMPARE_OP\", 2], [\"POP_JUMP_IF_FALSE\", 60], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 1], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"JUMP_FORWARD\", 10], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 2], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"LOAD_CONST\", 4], [\"RETURN_VALUE\", null]], \"co_consts\": [{\"Int\": 1}, {\"Str\": \"equal\"}, {\"Str\": \"not equal\"}, {\"Int\": 2}, {\"NoneType\": null}]}"; + + let expected = PyCodeObject { // Fill me with a more sensible data + co_consts: vec![NativeType::Int(1), NativeType::NoneType, NativeType::Int(2)], + co_names: vec!["print".to_string()], + co_code: vec![ + (3, "LOAD_CONST".to_string(), Some(2)), + (1, "PRINT_ITEM".to_string(), None), + (1, "PRINT_NEWLINE".to_string(), None), + (3, "LOAD_CONST".to_string(), None), + (1, "RETURN_VALUE".to_string(), None) + ] + }; + println!("{}", serde_json::to_string(&expected).unwrap()); + + let deserialized: PyCodeObject = serde_json::from_str(&input).unwrap(); + assert_eq!(expected, deserialized) +} +*/ + +#[test] +fn test_tuple_serialization(){ + let tuple = NativeType::Tuple(vec![NativeType::Int(1),NativeType::Int(2)]); + println!("{}", serde_json::to_string(&tuple).unwrap()); +} diff --git a/vm/RustPython/src/main.rs b/vm/RustPython/src/main.rs index 6b61c3aad7..1b40339181 100644 --- a/vm/RustPython/src/main.rs +++ b/vm/RustPython/src/main.rs @@ -1,861 +1,16 @@ #[macro_use] extern crate log; extern crate env_logger; - +extern crate rustpython_vm; #[macro_use] extern crate serde_derive; extern crate serde_json; -//extern crate eval; use eval::eval::*; -use std::collections::HashMap; -use std::cell::RefCell; +use rustpython_vm::*; use std::env; use std::fs::File; use std::io::prelude::*; -use std::rc::Rc; -use std::ops::Deref; -mod builtins; - -#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] -pub enum NativeType{ - NoneType, - Boolean(bool), - Int(i32), - Float(f64), - Str(String), - Unicode(String), - #[serde(skip_serializing, skip_deserializing)] - List(RefCell>), - Tuple(Vec), - Iter(Vec), // TODO: use Iterator instead - Code(PyCodeObject), - Function(Function), - Slice(Option, Option, Option), // start, stop, step - #[serde(skip_serializing, skip_deserializing)] - NativeFunction(fn(Vec>) -> NativeType ), -} - -const CMP_OP: &'static [&'static str] = &[">", - "<=", - "==", - "!=", - ">", - ">=", - "in", - "not in", - "is", - "is not", - "exception match", - "BAD" - ]; - -#[derive(Clone)] -struct Block { - block_type: String, //Enum? - handler: usize // The destination we should jump to if the block finishes - // level? -} - -struct Frame { - // TODO: We are using Option in stack for handline None return value - code: PyCodeObject, - // We need 1 stack per frame - stack: Vec>, // The main data frame of the stack machine - blocks: Vec, // Block frames, for controling loops and exceptions - globals: HashMap>, // Variables - locals: HashMap>, // Variables - labels: HashMap, // Maps label id to line number, just for speedup - lasti: usize, // index of last instruction ran - return_value: NativeType, - why: String, //Not sure why we need this //Maybe use a enum if we have fininte options - // cmp_op: Vec<&'a Fn(NativeType, NativeType) -> bool>, // TODO: change compare to a function list -} - -impl Frame { - /// Get the current bytecode offset calculated from curr_frame.lasti - fn get_bytecode_offset(&self) -> Option { - // Linear search the labels HashMap, inefficient. Consider build a reverse HashMap - let mut last_offset = None; - for (offset, instr_idx) in self.labels.iter() { - if *instr_idx == self.lasti { - last_offset = Some(*offset) - } - } - last_offset - } -} - -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct Function { - code: PyCodeObject -} - -impl Function { - fn new(code: PyCodeObject) -> Function { - Function { - code: code - } - } -} - - -struct VirtualMachine{ - frames: Vec, -} - -impl VirtualMachine { - fn new() -> VirtualMachine { - VirtualMachine { - frames: vec![], - } - } - - fn curr_frame(&mut self) -> &mut Frame { - self.frames.last_mut().unwrap() - } - - fn pop_frame(&mut self) { - self.frames.pop().unwrap(); - } - - fn unwind(&mut self, reason: String) { - let curr_frame = self.curr_frame(); - let curr_block = curr_frame.blocks[curr_frame.blocks.len()-1].clone(); // use last? - curr_frame.why = reason; // Why do we need this? - debug!("block status: {:?}, {:?}", curr_block.block_type, curr_frame.why); - match (curr_block.block_type.as_ref(), curr_frame.why.as_ref()) { - ("loop", "break") => { - curr_frame.lasti = curr_block.handler; //curr_frame.labels[curr_block.handler]; // Jump to the end - // Return the why as None - curr_frame.blocks.pop(); - }, - ("loop", "none") => (), //skipped - _ => panic!("block stack operation not implemented") - } - } - - // Can we get rid of the code paramter? - - fn make_frame(&self, code: PyCodeObject, callargs: HashMap>, globals: Option>>) -> Frame { - //populate the globals and locals - let mut labels = HashMap::new(); - let mut curr_offset = 0; - for (idx, op) in code.co_code.iter().enumerate() { - labels.insert(curr_offset, idx); - curr_offset += op.0; - } - //TODO: This is wrong, check https://github.com/nedbat/byterun/blob/31e6c4a8212c35b5157919abff43a7daa0f377c6/byterun/pyvm2.py#L95 - let globals = match globals { - Some(g) => g, - None => HashMap::new(), - }; - let mut locals = globals; - locals.extend(callargs); - - //TODO: move this into the __builtin__ module when we have a module type - locals.insert("print".to_string(), Rc::new(NativeType::NativeFunction(builtins::print))); - locals.insert("len".to_string(), Rc::new(NativeType::NativeFunction(builtins::len))); - Frame { - code: code, - stack: vec![], - blocks: vec![], - // save the callargs as locals - globals: locals.clone(), - locals: locals, - labels: labels, - lasti: 0, - return_value: NativeType::NoneType, - why: "none".to_string(), - } - } - - // The Option is the return value of the frame, remove when we have implemented frame - // TODO: read the op codes directly from the internal code object - fn run_frame(&mut self, frame: Frame) -> NativeType { - self.frames.push(frame); - - //let mut why = None; - // Change this to a loop for jump - loop { - //while curr_frame.lasti < curr_frame.code.co_code.len() { - let op_code = { - let curr_frame = self.curr_frame(); - let op_code = curr_frame.code.co_code[curr_frame.lasti].clone(); - curr_frame.lasti += 1; - op_code - }; - let why = self.dispatch(op_code); - /*if curr_frame.blocks.len() > 0 { - self.manage_block_stack(&why); - } - */ - if let Some(_) = why { - break; - } - } - let return_value = { - //let curr_frame = self.frames.last_mut().unwrap(); - self.curr_frame().return_value.clone() - }; - self.pop_frame(); - return_value - } - - fn run_code(&mut self, code: PyCodeObject) { - let frame = self.make_frame(code, HashMap::new(), None); - self.run_frame(frame); - // check if there are any leftover frame, fail if any - } - - fn dispatch(&mut self, op_code: (usize, String, Option)) -> Option { - { - debug!("stack:{:?}", self.curr_frame().stack); - debug!("env :{:?}", self.curr_frame().locals); - debug!("Executing op code: {:?}", op_code); - } - match (op_code.1.as_ref(), op_code.2) { - ("LOAD_CONST", Some(consti)) => { - // println!("Loading const at index: {}", consti); - let curr_frame = self.curr_frame(); - curr_frame.stack.push(Rc::new(curr_frame.code.co_consts[consti].clone())); - None - }, - - // TODO: universal stack element type - ("LOAD_CONST", None) => { - // println!("Loading const at index: {}", consti); - self.curr_frame().stack.push(Rc::new(NativeType::NoneType)); - None - }, - ("POP_TOP", None) => { - self.curr_frame().stack.pop(); - None - }, - ("LOAD_FAST", Some(var_num)) => { - // println!("Loading const at index: {}", consti); - let curr_frame = self.curr_frame(); - let ref name = curr_frame.code.co_varnames[var_num]; - curr_frame.stack.push(curr_frame.locals.get::(name).unwrap().clone()); - None - }, - ("STORE_NAME", Some(namei)) => { - // println!("Loading const at index: {}", consti); - let curr_frame = self.curr_frame(); - curr_frame.locals.insert(curr_frame.code.co_names[namei].clone(), curr_frame.stack.pop().unwrap().clone()); - None - }, - ("LOAD_NAME", Some(namei)) => { - // println!("Loading const at index: {}", consti); - let curr_frame = self.curr_frame(); - if let Some(code) = curr_frame.locals.get::(&curr_frame.code.co_names[namei]) { - curr_frame.stack.push(code.clone()); - } - else { - panic!("Can't find symbol {:?} in the current frame", &curr_frame.code.co_names[namei]); - } - None - }, - ("LOAD_GLOBAL", Some(namei)) => { - // We need to load the underlying value the name points to, but stuff like - // AssertionError is in the names right after compile, so we load the string - // instead for now - let curr_frame = self.curr_frame(); - let name = &curr_frame.code.co_names[namei]; - curr_frame.stack.push(curr_frame.globals.get::(name).unwrap().clone()); - None - }, - - ("BUILD_LIST", Some(count)) => { - let curr_frame = self.curr_frame(); - let mut vec = vec!(); - for _ in 0..count { - vec.push((*curr_frame.stack.pop().unwrap()).clone()); - } - vec.reverse(); - curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(vec)))); - None - }, - - ("BUILD_SLICE", Some(count)) => { - let curr_frame = self.curr_frame(); - assert!(count == 2 || count == 3); - let mut vec = vec!(); - for _ in 0..count { - vec.push(curr_frame.stack.pop().unwrap()); - } - vec.reverse(); - let mut out:Vec> = vec.into_iter().map(|x| match *x { - NativeType::Int(n) => Some(n), - NativeType::NoneType => None, - _ => panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x), - }).collect(); - - if out.len() == 2 { - out.push(None); - } - assert!(out.len() == 3); - // TODO: assert the stop start and step are NativeType::Int - // See https://users.rust-lang.org/t/how-do-you-assert-enums/1187/8 - curr_frame.stack.push(Rc::new(NativeType::Slice(out[0], out[1], out[2]))); - None - }, - - ("GET_ITER", None) => { - let curr_frame = self.curr_frame(); - let tos = curr_frame.stack.pop().unwrap(); - let iter = match *tos { - //TODO: is this clone right? - // Return a Iterator instead vvv - NativeType::Tuple(ref vec) => NativeType::Iter(vec.clone()), - NativeType::List(ref vec) => NativeType::Iter(vec.borrow().clone()), - _ => panic!("TypeError: object is not iterable") - }; - curr_frame.stack.push(Rc::new(iter)); - None - }, - - ("FOR_ITER", Some(delta)) => { - // This function should be rewrote to use Rust native iterator - let curr_frame = self.curr_frame(); - let tos = curr_frame.stack.pop().unwrap(); - let result = match *tos { - NativeType::Iter(ref v) => { - if v.len() > 0 { - Some(v.clone()) // Unnessary clone here - } - else { - None - } - } - _ => panic!("FOR_ITER: Not an iterator") - }; - if let Some(vec) = result { - let (first, rest) = vec.split_first().unwrap(); - // Unnessary clone here - curr_frame.stack.push(Rc::new(NativeType::Iter(rest.to_vec()))); - curr_frame.stack.push(Rc::new(first.clone())); - } - else { - // Iterator was already poped in the first line of this function - let last_offset = curr_frame.get_bytecode_offset().unwrap(); - curr_frame.lasti = curr_frame.labels.get(&(last_offset + delta)).unwrap().clone(); - - } - None - }, - - ("COMPARE_OP", Some(cmp_op_i)) => { - let curr_frame = self.curr_frame(); - let v1 = curr_frame.stack.pop().unwrap(); - let v2 = curr_frame.stack.pop().unwrap(); - match CMP_OP[cmp_op_i] { - // To avoid branch explotion, use an array of callables instead - "==" => { - match (v1.deref(), v2.deref()) { - (&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(v2i == v1i))); - }, - (&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f == v1f))); - }, - (&NativeType::Str(ref v1s), &NativeType::Str(ref v2s)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(v2s == v1s))); - }, - (&NativeType::Int(ref v1i), &NativeType::Float(ref v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f == &(*v1i as f64)))); - }, - (&NativeType::List(ref l1), &NativeType::List(ref l2)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(l2 == l1))); - }, - _ => panic!("TypeError in COMPARE_OP: can't compare {:?} with {:?}", v1, v2) - }; - } - ">" => { - match (v1.deref(), v2.deref()) { - (&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(v2i < v1i))); - }, - (&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Boolean(v2f < v1f))); - }, - _ => panic!("TypeError in COMPARE_OP") - }; - } - _ => panic!("Unimplemented COMPARE_OP operator") - - } - None - - }, - ("POP_JUMP_IF_TRUE", Some(ref target)) => { - let curr_frame = self.curr_frame(); - let v = curr_frame.stack.pop().unwrap(); - if *v == NativeType::Boolean(true) { - curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone(); - } - None - - } - ("POP_JUMP_IF_FALSE", Some(ref target)) => { - let curr_frame = self.curr_frame(); - let v = curr_frame.stack.pop().unwrap(); - if *v == NativeType::Boolean(false) { - curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone(); - } - None - - } - ("JUMP_FORWARD", Some(ref delta)) => { - let curr_frame = self.curr_frame(); - let last_offset = curr_frame.get_bytecode_offset().unwrap(); - curr_frame.lasti = curr_frame.labels.get(&(last_offset + delta)).unwrap().clone(); - None - }, - ("JUMP_ABSOLUTE", Some(ref target)) => { - let curr_frame = self.curr_frame(); - curr_frame.lasti = curr_frame.labels.get(target).unwrap().clone(); - None - }, - ("BREAK_LOOP", None) => { - // Do we still need to return the why if we use unwind from jsapy? - self.unwind("break".to_string()); - None //? - }, - ("RAISE_VARARGS", Some(argc)) => { - let curr_frame = self.curr_frame(); - // let (exception, params, traceback) = match argc { - let exception = match argc { - 1 => curr_frame.stack.pop().unwrap(), - 0 | 2 | 3 => panic!("Not implemented!"), - _ => panic!("Invalid paramter for RAISE_VARARGS, must be between 0 to 3") - }; - panic!("{:?}", exception); - } - ("INPLACE_ADD", None) => { - let curr_frame = self.curr_frame(); - let tos = curr_frame.stack.pop().unwrap(); - let tos1 = curr_frame.stack.pop().unwrap(); - match (tos.deref(), tos1.deref()) { - (&NativeType::Int(ref tosi), &NativeType::Int(ref tos1i)) => { - curr_frame.stack.push(Rc::new(NativeType::Int(tos1i + tosi))); - }, - _ => panic!("TypeError in BINARY_ADD") - } - None - }, - - ("STORE_SUBSCR", None) => { - let curr_frame = self.curr_frame(); - let tos = curr_frame.stack.pop().unwrap(); - let tos1 = curr_frame.stack.pop().unwrap(); - let tos2 = curr_frame.stack.pop().unwrap(); - match (tos1.deref(), tos.deref()) { - (&NativeType::List(ref refl), &NativeType::Int(index)) => { - refl.borrow_mut()[index as usize] = (*tos2).clone(); - }, - (&NativeType::Str(_), &NativeType::Int(_)) => { - // TODO: raise TypeError: 'str' object does not support item assignment - panic!("TypeError: 'str' object does not support item assignment") - }, - _ => panic!("TypeError in STORE_SUBSCR") - } - curr_frame.stack.push(tos1); - None - }, - - ("BINARY_ADD", None) => { - let curr_frame = self.curr_frame(); - let v1 = curr_frame.stack.pop().unwrap(); - let v2 = curr_frame.stack.pop().unwrap(); - match (v1.deref(), v2.deref()) { - (&NativeType::Int(ref v1i), &NativeType::Int(ref v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Int(v2i + v1i))); - } - (&NativeType::Float(ref v1f), &NativeType::Int(ref v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Float(*v2i as f64 + v1f))); - } - (&NativeType::Int(ref v1i), &NativeType::Float(ref v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Float(v2f + *v1i as f64))); - } - (&NativeType::Float(ref v1f), &NativeType::Float(ref v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Float(v2f + v1f))); - } - (&NativeType::Str(ref str1), &NativeType::Str(ref str2)) => { - curr_frame.stack.push(Rc::new(NativeType::Str(format!("{}{}", str2, str1)))); - } - (&NativeType::List(ref l1), &NativeType::List(ref l2)) => { - let mut new_l = l2.clone(); - // TODO: remove unnessary copy - new_l.borrow_mut().append(&mut l1.borrow().clone()); - curr_frame.stack.push(Rc::new(NativeType::List(new_l))); - - } - _ => panic!("TypeError in BINARY_ADD") - } - None - }, - ("BINARY_POWER", None) => { - let curr_frame = self.curr_frame(); - let v1 = curr_frame.stack.pop().unwrap(); - let v2 = curr_frame.stack.pop().unwrap(); - match (v1.deref(), v2.deref()) { - (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Int(v2i.pow(v1i as u32)))); - } - (&NativeType::Float(v1f), &NativeType::Int(v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Float((v2i as f64).powf(v1f)))); - } - (&NativeType::Int(v1i), &NativeType::Float(v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Float(v2f.powi(v1i)))); - } - (&NativeType::Float(v1f), &NativeType::Float(v2f)) => { - curr_frame.stack.push(Rc::new(NativeType::Float(v2f.powf(v1f)))); - } - _ => panic!("TypeError in BINARY_POWER") - } - None - }, - ("BINARY_MULTIPLY", None) => { - let curr_frame = self.curr_frame(); - let v1 = curr_frame.stack.pop().unwrap(); - let v2 = curr_frame.stack.pop().unwrap(); - match (v1.deref(), v2.deref()) { - (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Int(v2i * v1i))); - }, - /* - (NativeType::Float(v1f), NativeType::Int(v2i)) => { - curr_frame.stack.push(NativeType::Float((v2i as f64) * v1f)); - }, - (NativeType::Int(v1i), NativeType::Float(v2f)) => { - curr_frame.stack.push(NativeType::Float(v2f * (v1i as f64))); - }, - (NativeType::Float(v1f), NativeType::Float(v2f)) => { - curr_frame.stack.push(NativeType::Float(v2f * v1f)); - }, - */ - //TODO: String multiply - _ => panic!("TypeError in BINARY_MULTIPLY") - } - None - }, - ("BINARY_TRUE_DIVIDE", None) => { - let curr_frame = self.curr_frame(); - let v1 = curr_frame.stack.pop().unwrap(); - let v2 = curr_frame.stack.pop().unwrap(); - match (v1.deref(), v2.deref()) { - (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Int(v2i / v1i))); - }, - _ => panic!("TypeError in BINARY_DIVIDE") - } - None - }, - ("BINARY_MODULO", None) => { - let curr_frame = self.curr_frame(); - let v1 = curr_frame.stack.pop().unwrap(); - let v2 = curr_frame.stack.pop().unwrap(); - match (v1.deref(), v2.deref()) { - (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Int(v2i % v1i))); - }, - _ => panic!("TypeError in BINARY_MODULO") - } - None - }, - ("BINARY_SUBTRACT", None) => { - let curr_frame = self.curr_frame(); - let v1 = curr_frame.stack.pop().unwrap(); - let v2 = curr_frame.stack.pop().unwrap(); - match (v1.deref(), v2.deref()) { - (&NativeType::Int(v1i), &NativeType::Int(v2i)) => { - curr_frame.stack.push(Rc::new(NativeType::Int(v2i - v1i))); - }, - _ => panic!("TypeError in BINARY_SUBSTRACT") - } - None - }, - - ("BINARY_SUBSCR", None) => { - let curr_frame = self.curr_frame(); - let tos = curr_frame.stack.pop().unwrap(); - let tos1 = curr_frame.stack.pop().unwrap(); - debug!("tos: {:?}, tos1: {:?}", tos, tos1); - match (tos1.deref(), tos.deref()) { - (&NativeType::List(ref l), &NativeType::Int(ref index)) => { - let pos_index = (index + l.borrow().len() as i32) % l.borrow().len() as i32; - curr_frame.stack.push(Rc::new(l.borrow()[pos_index as usize].clone())) - }, - (&NativeType::List(ref l), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => { - let start = match opt_start { - &Some(start) => ((start + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, - &None => 0, - }; - let stop = match opt_stop { - &Some(stop) => ((stop + l.borrow().len() as i32) % l.borrow().len() as i32) as usize, - &None => l.borrow().len() as usize, - }; - let step = match opt_step { - //Some(step) => step as usize, - &None => 1 as usize, - _ => unimplemented!(), - }; - // TODO: we could potentially avoid this copy and use slice - curr_frame.stack.push(Rc::new(NativeType::List(RefCell::new(l.borrow()[start..stop].to_vec())))); - }, - (&NativeType::Tuple(ref t), &NativeType::Int(ref index)) => curr_frame.stack.push(Rc::new(t[*index as usize].clone())), - (&NativeType::Str(ref s), &NativeType::Int(ref index)) => { - let idx = (index + s.len() as i32) % s.len() as i32; - curr_frame.stack.push(Rc::new(NativeType::Str(s.chars().nth(idx as usize).unwrap().to_string()))); - }, - (&NativeType::Str(ref s), &NativeType::Slice(ref opt_start, ref opt_stop, ref opt_step)) => { - let start = match opt_start { - &Some(start) if start > s.len() as i32 => s.len(), - &Some(start) if start <= s.len() as i32 => ((start + s.len() as i32) % s.len() as i32) as usize, - &Some(_) => panic!("Bad start index for string slicing"), - &Some(start) => ((start + s.len() as i32) % s.len() as i32) as usize, - &None => 0, - }; - let stop = match opt_stop { - &Some(stop) if stop > s.len() as i32 => s.len(), - &Some(stop) if stop <= s.len() as i32 => ((stop + s.len() as i32) % s.len() as i32) as usize, // Do we need this modding? - &Some(_) => panic!("Bad stop index for string slicing"), - &None => s.len() as usize, - }; - let step = match opt_step { - //Some(step) => step as usize, - &None => 1 as usize, - _ => unimplemented!(), - }; - curr_frame.stack.push(Rc::new(NativeType::Str(s[start..stop].to_string()))); - }, - // TODO: implement other Slice possibilities - _ => panic!("TypeError: indexing type {:?} with index {:?} is not supported (yet?)", tos1, tos) - }; - None - }, - ("ROT_TWO", None) => { - let curr_frame = self.curr_frame(); - let tos = curr_frame.stack.pop().unwrap(); - let tos1 = curr_frame.stack.pop().unwrap(); - curr_frame.stack.push(tos); - curr_frame.stack.push(tos1); - None - } - ("UNARY_NEGATIVE", None) => { - let curr_frame = self.curr_frame(); - let v = curr_frame.stack.pop().unwrap(); - match v.deref() { - &NativeType::Int(v1i) => { - curr_frame.stack.push(Rc::new(NativeType::Int(-v1i))); - }, - _ => panic!("TypeError in UINARY_NEGATIVE") - } - None - }, - ("UNARY_POSITIVE", None) => { - let curr_frame = self.curr_frame(); - let v = curr_frame.stack.pop().unwrap(); - // Any case that is not just push back? - curr_frame.stack.push(v); - None - }, - ("PRINT_ITEM", None) => { - let curr_frame = self.curr_frame(); - // TODO: Print without the (...) - println!("{:?}", curr_frame.stack.pop().unwrap()); - None - }, - ("PRINT_NEWLINE", None) => { - print!("\n"); - None - }, - ("MAKE_FUNCTION", Some(argc)) => { - // https://docs.python.org/3.4/library/dis.html#opcode-MAKE_FUNCTION - let curr_frame = self.curr_frame(); - let qualified_name = curr_frame.stack.pop().unwrap(); - let code_obj = match curr_frame.stack.pop().unwrap().deref() { - &NativeType::Code(ref code) => code.clone(), - _ => panic!("Second item on the stack should be a code object") - }; - // pop argc arguments - // argument: name, args, globals - let func = Function::new(code_obj); - curr_frame.stack.push(Rc::new(NativeType::Function(func))); - None - }, - ("CALL_FUNCTION", Some(argc)) => { - let kw_count = (argc >> 8) as u8; - let pos_count = (argc & 0xFF) as u8; - // Pop the arguments based on argc - let mut kw_args = HashMap::new(); - let mut pos_args = Vec::new(); - { - let curr_frame = self.curr_frame(); - for _ in 0..kw_count { - let native_val = curr_frame.stack.pop().unwrap(); - let native_key = curr_frame.stack.pop().unwrap(); - if let (ref val, &NativeType::Str(ref key)) = (native_val, native_key.deref()) { - - kw_args.insert(key.clone(), val.clone()); - } - else { - panic!("Incorrect type found while building keyword argument list") - } - } - for _ in 0..pos_count { - pos_args.push(curr_frame.stack.pop().unwrap()); - } - } - let locals = { - // FIXME: no clone here - self.curr_frame().locals.clone() - }; - - let func = { - match self.curr_frame().stack.pop().unwrap().deref() { - &NativeType::Function(ref func) => { - // pop argc arguments - // argument: name, args, globals - // build the callargs hashmap - pos_args.reverse(); - let mut callargs = HashMap::new(); - for (name, val) in func.code.co_varnames.iter().zip(pos_args) { - callargs.insert(name.to_string(), val); - } - // merge callargs with kw_args - let return_value = { - let frame = self.make_frame(func.code.clone(), callargs, Some(locals)); - self.run_frame(frame) - }; - self.curr_frame().stack.push(Rc::new(return_value)); - }, - &NativeType::NativeFunction(func) => { - pos_args.reverse(); - let return_value = func(pos_args); - self.curr_frame().stack.push(Rc::new(return_value)); - }, - _ => panic!("The item on the stack should be a code object") - } - }; - None - }, - ("RETURN_VALUE", None) => { - // Hmmm... what is this used? - // I believe we need to push this to the next frame - self.curr_frame().return_value = (*self.curr_frame().stack.pop().unwrap()).clone(); - Some("return".to_string()) - }, - ("SETUP_LOOP", Some(delta)) => { - let curr_frame = self.curr_frame(); - let curr_offset = curr_frame.get_bytecode_offset().unwrap(); - curr_frame.blocks.push(Block { - block_type: "loop".to_string(), - handler: *curr_frame.labels.get(&(curr_offset + delta)).unwrap(), - }); - None - }, - ("POP_BLOCK", None) => { - self.curr_frame().blocks.pop(); - None - } - ("SetLineno", _) | ("LABEL", _)=> { - // Skip - None - }, - (name, _) => { - panic!("Unrecongnizable op code: {}", name); - } - } // end match - } // end dispatch function -} - -#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] -pub struct PyCodeObject { - co_consts: Vec, - co_names: Vec, - co_code: Vec<(usize, String, Option)>, //size, name, args - co_varnames: Vec, -} - - -/* -fn parse_native_type(val_str: &str) -> Result { - // println!("{:?}", val_str); - match val_str { - "None" => Ok(NativeType::NoneType), - "True" => Ok(NativeType::Boolean(true)), - "False" => Ok(NativeType::Boolean(false)), - _ => { - if let Ok(int) = val_str.parse::() { - return Ok(NativeType::Int(int)) - } - - if let Ok(float) = val_str.parse::() { - return Ok(NativeType::Float(float)) - } - - if val_str.starts_with("\'") && val_str.ends_with("\'") { - return Ok(NativeType::Str(val_str[1..val_str.len()-1].to_string())) - } - - if val_str.starts_with("u\'") && val_str.ends_with("\'") { - return Ok(NativeType::Unicode(val_str[2..val_str.len()-1].to_string())) - } - - if val_str.starts_with("(") && val_str.ends_with(")") { - return Ok(NativeType::Str(val_str[1..val_str.len()-1].to_string())) - } - - Err(()) - } - - } -} - -fn parse_bytecode(s: &str) -> Code { - let lines: Vec<&str> = s.split('\n').collect(); - - let (metadata, ops) = lines.split_at(2); - // Parsing the first line CONSTS - let consts_str: &str = metadata[0]; // line 0 is empty - let values_str = &consts_str[("CONSTS: (".len())..(consts_str.len()-1)]; - let values: Vec<&str> = values_str.split(",").collect(); - // We need better type definition here - let consts: Vec= values.into_iter() - .map(|x| x.trim()) - .filter(|x| x.len() > 0) - .map(|x| parse_native_type(x).unwrap()) - .collect(); - - // Parsing the second line NAMES - let names_str: &str = metadata[1]; // line 0 is empty - let values_str = &names_str[("NAMES: (".len())..(names_str.len()-1)]; - let values: Vec<&str> = values_str.split(",").collect(); - // We are assuming the first and last chars are \' - let names: Vec<&str>= values.into_iter().map(|x| x.trim()) - .filter(|x| x.len() > 0) - .map(|x| &x[1..(x.len()-1)]).collect(); - - // Parsing the op_codes - let op_codes: Vec<(&str, Option)>= ops.into_iter() - .map(|x| x.trim()) - .filter(|x| x.len() > 0) - .map(|x| { - let op: Vec<&str> = x.split(", ").collect(); - // println!("{:?}", op); - (op[0], op[1].parse::().ok()) - }).collect(); - - - Code { - consts: consts, - op_codes: op_codes, - names: names, - } -} -*/ fn main() { env_logger::init().unwrap(); // TODO: read this from args @@ -876,115 +31,3 @@ fn main() { vm.run_code(code); // println!("Done"); } - -/* -#[test] -fn test_parse_native_type() { - - assert_eq!(NativeType::NoneType, parse_native_type("None").unwrap()); - assert_eq!(NativeType::Boolean(true), parse_native_type("True").unwrap()); - assert_eq!(NativeType::Boolean(false), parse_native_type("False").unwrap()); - assert_eq!(NativeType::Int(3), parse_native_type("3").unwrap()); - assert_eq!(NativeType::Float(3.0), parse_native_type("3.0").unwrap()); - assert_eq!(NativeType::Float(3.5), parse_native_type("3.5").unwrap()); - assert_eq!(NativeType::Str("foo".to_string()), parse_native_type("\'foo\'").unwrap()); - assert_eq!(NativeType::Unicode("foo".to_string()), parse_native_type("u\'foo\'").unwrap()); -} - -#[test] -fn test_parse_bytecode() { - - let input = "CONSTS: (1, None, 2) -NAMES: ('a', 'b') -SetLineno, 1 -LOAD_CONST, 2 -PRINT_ITEM, None -PRINT_NEWLINE, None -LOAD_CONST, None -RETURN_VALUE, None - "; - let expected = Code { // Fill me with a more sensible data - consts: vec![NativeType::Int(1), NativeType::NoneType, NativeType::Int(2)], - names: vec!["a", "b"], - op_codes: vec![ - ("SetLineno", Some(1)), - ("LOAD_CONST", Some(2)), - ("PRINT_ITEM", None), - ("PRINT_NEWLINE", None), - ("LOAD_CONST", None), - ("RETURN_VALUE", None) - ] - }; - - assert_eq!(expected, parse_bytecode(input)); -} - -#[test] -fn test_single_const_tuple() { - let input = "CONSTS: (None,) -NAMES: () -SetLineno, 1 -LOAD_CONST, 0 -RETURN_VALUE, None -"; - let expected = Code { // Fill me with a more sensible data - consts: vec![NativeType::NoneType], - names: vec![], - op_codes: vec![ - ("SetLineno", Some(1)), - ("LOAD_CONST", Some(0)), - ("RETURN_VALUE", None) - ] - }; - - assert_eq!(expected, parse_bytecode(input)); -} - -#[test] -fn test_vm() { - - let code = PyCodeObject { - co_consts: vec![NativeType::Int(1), NativeType::NoneType, NativeType::Int(2)], - co_names: vec![], - co_code: vec![ - (3, "LOAD_CONST".to_string(), Some(2)), - (1, "PRINT_ITEM".to_string(), None), - (1, "PRINT_NEWLINE".to_string(), None), - (3, "LOAD_CONST".to_string(), None), - (1, "RETURN_VALUE".to_string(), None) - ] - }; - let mut vm = VirtualMachine::new(); - assert_eq!((), vm.exec(&code)); -} - - -#[test] -fn test_parse_jsonbytecode() { - -let input = "{\"co_consts\":[{\"Int\":1},\"NoneType\",{\"Int\":2}],\"co_names\":[\"print\"],\"co_code\":[[3,\"LOAD_CONST\",2],[1,\"PRINT_ITEM\",null],[1,\"PRINT_NEWLINE\",null],[3,\"LOAD_CONST\",null],[1,\"RETURN_VALUE\",null]]}"; -// let input = "{\"co_names\": [\"print\"], \"co_code\": [[\"LOAD_CONST\", 0], [\"LOAD_CONST\", 0], [\"COMPARE_OP\", 2], [\"POP_JUMP_IF_FALSE\", 25], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 1], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"JUMP_FORWARD\", 10], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 2], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"LOAD_CONST\", 0], [\"LOAD_CONST\", 3], [\"COMPARE_OP\", 2], [\"POP_JUMP_IF_FALSE\", 60], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 1], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"JUMP_FORWARD\", 10], [\"LOAD_NAME\", 0], [\"LOAD_CONST\", 2], [\"CALL_FUNCTION\", 1], [\"POP_TOP\", null], [\"LOAD_CONST\", 4], [\"RETURN_VALUE\", null]], \"co_consts\": [{\"Int\": 1}, {\"Str\": \"equal\"}, {\"Str\": \"not equal\"}, {\"Int\": 2}, {\"NoneType\": null}]}"; - - let expected = PyCodeObject { // Fill me with a more sensible data - co_consts: vec![NativeType::Int(1), NativeType::NoneType, NativeType::Int(2)], - co_names: vec!["print".to_string()], - co_code: vec![ - (3, "LOAD_CONST".to_string(), Some(2)), - (1, "PRINT_ITEM".to_string(), None), - (1, "PRINT_NEWLINE".to_string(), None), - (3, "LOAD_CONST".to_string(), None), - (1, "RETURN_VALUE".to_string(), None) - ] - }; - println!("{}", serde_json::to_string(&expected).unwrap()); - - let deserialized: PyCodeObject = serde_json::from_str(&input).unwrap(); - assert_eq!(expected, deserialized) -} -*/ - -#[test] -fn test_tuple_serialization(){ - let tuple = NativeType::Tuple(vec![NativeType::Int(1),NativeType::Int(2)]); - println!("{}", serde_json::to_string(&tuple).unwrap()); -}