Compare commits

..

91 Commits

Author SHA1 Message Date
Noah
a784d2f0f8 Add a std feature to vm 2021-01-14 12:48:54 -06:00
Noah
bf1e9832f7 Make compiler/porcelain no_std compatible 2021-01-14 12:48:54 -06:00
Noah
5f5d36cc74 Make parser no_std compatible 2021-01-14 12:48:52 -06:00
Noah
313c30c51b Make ast no_std compatible 2021-01-14 12:45:32 -06:00
Noah
d375710650 Make compiler no_std compatible 2021-01-14 12:45:32 -06:00
Noah
c49cc8f419 Make bytecode no_std compatible 2021-01-14 12:45:32 -06:00
Jeong YunWon
39c18fe9a8 Merge pull request #2146 from RustPython/coolreader18/test_ftplib
Add ftplib + test_ftplib
2021-01-13 08:05:15 +09:00
Noah
abe9e2322e Remove extra ahash dep 2021-01-11 19:42:05 -06:00
Noah
07cad58292 Skip test_ftplib on windows 2021-01-11 17:32:30 -06:00
Noah
fe15286c1c Use PyRwBytesLike 2021-01-11 17:32:30 -06:00
Noah
a5ba2038fb Add SSLContext.options 2021-01-11 17:32:29 -06:00
Noah
10a7f5d9af Fix SslSocket methods, sorta 2021-01-11 17:32:29 -06:00
Noah
9647fce6d5 Add some more socket methods + other misc fixes 2021-01-11 17:32:29 -06:00
Noah
5ead2864ae Skip unsupported tests 2021-01-11 17:32:29 -06:00
Noah
8d95d642df Add keycert files from CPython 3.8.3 2021-01-11 17:32:29 -06:00
Noah
47e268a98c Add test.test_ftplib from CPython 3.8.3 2021-01-11 17:32:18 -06:00
Jeong YunWon
eb6edabfd3 Merge pull request #2397 from RustPython/coolreader18/fasthash
Use ahash instead of siphash in a few places
2021-01-11 01:37:12 +09:00
Jeong YunWon
d2abad5647 Merge pull request #2398 from RustPython/coolreader18/update-cranelift
Update cranelift deps
2021-01-11 01:31:12 +09:00
Noah
cbd229c754 Update cranelift deps 2021-01-08 18:47:54 -06:00
Noah
8cdef9e1fa Use ahash in the vm 2021-01-08 18:08:21 -06:00
Noah
77ab7628fe Upgrade lz4_flex + lalrpop 2021-01-08 17:22:42 -06:00
Noah
56c225c748 Use ahash/phf in parser 2021-01-08 17:09:09 -06:00
Noah
688880c540 Use ahash in the compiler 2021-01-08 17:00:23 -06:00
Noah
0fe96f16b0 Update Cargo.lock 2021-01-08 17:00:03 -06:00
Jeong YunWon
70c96258b1 Merge pull request #2379 from RustPython/coolreader18/rework-pystruct
Rework pystruct, again
2021-01-08 16:15:14 +09:00
Jeong YunWon
7417c377a9 Merge pull request #2359 from youknowone/return-type
Fix return types
2021-01-08 15:46:37 +09:00
Noah
75f9ea2f29 Update rand deps, replace statrs with puruspe 2021-01-07 23:44:45 -06:00
Noah
76306b2260 Add half-float support for struct 2021-01-07 23:44:44 -06:00
Noah
108e1ef38b Rework pystruct, again 2021-01-07 23:44:44 -06:00
Jeong YunWon
0b58527c6a Merge pull request #2373 from RustPython/coolreader18/blockir
Have a block-based IR for compiling, calculate max stack size
2021-01-08 13:16:31 +09:00
Jeong YunWon
d15da722ce Fix return types 2021-01-08 13:10:06 +09:00
Jeong YunWon
1c12a80682 Merge pull request #2392 from RustPython/fix-clippy-1.49
Fix clippy lints for Rust 1.49
2021-01-08 11:32:45 +09:00
Noah
3dbe94c9cf Merge pull request #2394 from pca006132/master
Implements AST Customization (#2388)
2021-01-04 01:01:22 -06:00
pca006132
0af925051c changed Default::default() to () 2021-01-04 14:45:36 +08:00
pca006132
d04c0777fb formatting 2021-01-04 11:21:25 +08:00
pca006132
af3e7dee69 Implements AST Customization (#2388) 2021-01-04 10:33:22 +08:00
Noah
b0183b2d09 Merge pull request #2383 from qingshi163/memoryview-cast
Implement Memoryview cast
2021-01-03 13:31:13 -06:00
Noah
0786e4c440 Merge pull request #2393 from nomeata/master
Arguments to builtin.compile() can be named
2021-01-03 11:35:33 -06:00
Joachim Breitner
a41fa97bfc Arguments to builtin.compile() can be named
fixes #2390
2021-01-03 11:06:28 +01:00
Noah
be40a5d7b9 Fix clippy lints for Rust 1.49 2021-01-02 19:30:57 -06:00
Noah
8b31efb862 Merge pull request #2389 from carbotaniuman/delete_macro
Delete no_kwargs! macro
2021-01-02 18:25:47 -06:00
carbotaniuman
2dcd811ece Delete no_kwargs! macro 2021-01-02 12:05:38 -06:00
Noah
abb1f28f2e Merge pull request #2387 from carbotaniuman/magic-methods
use unsigned abs to avoid overflow
2020-12-30 15:12:44 -06:00
carbotaniuman
3ca003a94d Fix test 2020-12-30 11:53:49 -06:00
carbotaniuman
eecebef0e0 Add test 2020-12-30 10:56:00 -06:00
Kangzhi Shi
06ff99725b fix memoryview cast 2020-12-30 14:30:27 +02:00
carbotaniuman
9a717a319a use unsigned abs to avoid overflow 2020-12-29 22:17:15 -06:00
Kangzhi Shi
fcca2d72f4 Fix memoryview toreadonly 2020-12-27 19:05:33 +02:00
Kangzhi Shi
44048f60cb Implement memoryview cast 2020-12-27 19:03:05 +02:00
Noah
d177b8f1a3 Merge pull request #2377 from carbotaniuman/fsum
Add fsum to the math module
2020-12-23 20:49:12 -06:00
Noah
559123c617 Don't push something on the stack when starting a generator 2020-12-23 17:40:33 -06:00
carbotaniuman
353f558f67 Format 2020-12-22 16:25:28 -06:00
carbotaniuman
d9b9aea9f5 Address clippy 2020-12-22 11:31:40 -06:00
carbotaniuman
9faed3582a Address review 2020-12-21 22:29:15 -06:00
Noah
2123df6017 Don't keep a separate blockorder vec 2020-12-21 18:49:00 -06:00
Noah
8f536b986d Use boxvec for frame.stack 2020-12-21 18:48:56 -06:00
Noah
1ca5ca74dc Add common::BoxVec 2020-12-21 18:47:59 -06:00
Noah
5f0a13c1f9 Make get_value(PyObjectRef)->T functions pub(crate) 2020-12-21 18:47:59 -06:00
Noah
32a1dd60be Have a block-based IR for compiling, calculate max stack size 2020-12-21 18:47:58 -06:00
Noah
5d6c323989 Merge pull request #2376 from RustPython/coolreader18/bytecode-crate-reorganize
Flatten rustpython_bytecode::bytecode into the root of the crate
2020-12-20 09:26:30 -06:00
Jeong YunWon
ca91bdaa2a Merge pull request #2374 from RustPython/coolreader18/no-arr_macro
Remove arr_macro dependency
2020-12-21 00:05:28 +09:00
Jeong YunWon
7067119379 Merge pull request #2375 from RustPython/coolreader18/coros-have-names-too
Give generators, coroutines, async generators __name__s
2020-12-21 00:00:50 +09:00
carbotaniuman
0ff37540ab Add fsum to the math module 2020-12-19 19:32:08 -06:00
Noah
99a8d68933 Fix test_exceptions.testRaising 2020-12-19 15:09:20 -06:00
Noah
2246f8b6f0 marshal can give better error messages on eof 2020-12-19 15:00:47 -06:00
Noah
a5d45124fd Update other stuff to use the root of rustpython_bytecode 2020-12-19 14:59:07 -06:00
Noah
3627e4ace1 Move bytecode.rs to lib.rs 2020-12-19 14:59:06 -06:00
Noah
f1807c7675 Remove bytecode lib.rs 2020-12-19 14:59:06 -06:00
Noah
a7363110ae Update lz4_flex version 2020-12-19 14:59:06 -06:00
Noah
82c8e5434f Give generators, coroutines, async generators __name__s 2020-12-19 12:57:11 -06:00
Noah
96ae54ae5e Remove arr_macro dependency 2020-12-19 00:16:17 -06:00
Jeong YunWon
57805f791f Merge pull request #2372 from RustPython/coolreader18/functions-have-names
Show functions' names
2020-12-19 01:02:27 +09:00
Noah
13ea0efa9f sock.recv_into takes any rw buffer 2020-12-17 16:29:44 -06:00
Noah
5a56dd1a77 repr() functions with their names 2020-12-17 16:29:44 -06:00
Noah
a4aef93327 Make all builtin functions have names 2020-12-17 16:29:43 -06:00
Noah
b01cca97f4 Merge pull request #2361 from RustPython/fmt-prettier
Format the wasm/ directory using prettier
2020-12-16 10:27:08 -06:00
Noah
f958c8230c Add prettier checking to CI 2020-12-16 09:21:36 -06:00
Noah
dd14bb3516 Format wasm/ according to prettier rules 2020-12-16 09:21:07 -06:00
Noah
2d246f0ce9 Merge pull request #2365 from RustPython/coolreader18/optimize-bytecode-format
Optimize the size of Instruction
2020-12-16 09:01:27 -06:00
Jeong YunWon
aa625cb847 Merge pull request #2368 from RustPython/coolreader18/fix-redox
Fix compilation on redox
2020-12-16 22:51:09 +09:00
Noah
090720ab34 Fix jit 2020-12-14 16:33:05 -06:00
Noah
1be79c93b0 Make Instruction only 8 bytes 2020-12-14 15:55:47 -06:00
Noah
e87144e2c5 Add flags to the MakeFunction instruction 2020-12-14 14:35:17 -06:00
Noah
98c3df2a94 Manage the stack a bit more efficiently 2020-12-14 14:32:31 -06:00
Noah
9c895c268a Add label_arg{,_mut} methods 2020-12-14 14:25:20 -06:00
Noah
057b5e8eda Fix jit 2020-12-14 14:25:20 -06:00
Noah
60b2884afa Use lz4_flex instead of lz-fear 2020-12-14 14:25:19 -06:00
Noah
f93934f0c6 Make Continue have the target it's continuing to 2020-12-14 14:25:19 -06:00
Noah
3280a1655a Optimize the size of Instruction 2020-12-14 14:25:19 -06:00
Noah
43860902e6 Import ConstantData in compile.rs 2020-12-14 14:25:19 -06:00
Noah
881b280c46 Fix compilation on redox 2020-12-14 12:12:44 -06:00
124 changed files with 6504 additions and 3186 deletions

View File

@@ -161,6 +161,11 @@ jobs:
run: python -m pip install flake8
- name: run lint
run: flake8 . --count --exclude=./.*,./Lib,./vm/Lib,./benches/ --select=E9,F63,F7,F82 --show-source --statistics
- name: install prettier
run: yarn global add prettier && echo "$(yarn global bin)" >>$GITHUB_PATH
- name: check wasm code with prettier
# prettier doesn't handle ignore files very well: https://github.com/prettier/prettier/issues/8506
run: cd wasm && git ls-files -z | xargs -0 prettier --check -u
miri:
name: Run tests under miri
runs-on: ubuntu-latest

404
Cargo.lock generated
View File

@@ -24,6 +24,23 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
[[package]]
name = "ahash"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75b7e6a93ecd6dbd2c225154d0fa7f86205574ecaa6c87429fb5f66ee677c44"
dependencies = [
"getrandom 0.2.1",
"lazy_static 1.4.0",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.15"
@@ -57,27 +74,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "arr_macro"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a105bfda48707cf19220129e78fca01e9639433ffaef4163546ed8fb04120a5"
dependencies = [
"arr_macro_impl",
"proc-macro-hack",
]
[[package]]
name = "arr_macro_impl"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0609c78bd572f4edc74310dfb63a01f5609d53fa8b4dd7c4d98aef3b3e8d72d1"
dependencies = [
"proc-macro-hack",
"quote",
"syn",
]
[[package]]
name = "arrayref"
version = "0.3.6"
@@ -294,7 +290,7 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim 0.8.0",
"strsim",
"textwrap 0.11.0",
"unicode-width",
"vec_map",
@@ -340,9 +336,9 @@ dependencies = [
[[package]]
name = "cranelift"
version = "0.68.0"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60686f89c5145bc9a961dabbb83954baa429bde4c5977a0a5d3f8552f2990273"
checksum = "910322bd748b9b2450947659a48a928f35b8ba7212d80d719ff85e4b7cde62b7"
dependencies = [
"cranelift-codegen",
"cranelift-frontend",
@@ -350,18 +346,18 @@ dependencies = [
[[package]]
name = "cranelift-bforest"
version = "0.68.0"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9221545c0507dc08a62b2d8b5ffe8e17ac580b0a74d1813b496b8d70b070fbd0"
checksum = "4066fd63b502d73eb8c5fa6bcab9c7962b05cd580f6b149ee83a8e730d8ce7fb"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.68.0"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e9936ea608b6cd176f107037f6adbb4deac933466fc7231154f96598b2d3ab1"
checksum = "1a54e4beb833a3c873a18a8fe735d73d732044004c7539a072c8faa35ccb0c60"
dependencies = [
"byteorder",
"cranelift-bforest",
@@ -377,9 +373,9 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.68.0"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ef2b2768568306540f4c8db3acce9105534d34c4a1e440529c1e702d7f8c8d7"
checksum = "c54cac7cacb443658d8f0ff36a3545822613fa202c946c0891897843bc933810"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
@@ -387,21 +383,21 @@ dependencies = [
[[package]]
name = "cranelift-codegen-shared"
version = "0.68.0"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6759012d6d19c4caec95793f052613e9d4113e925e7f14154defbac0f1d4c938"
checksum = "a109760aff76788b2cdaeefad6875a73c2b450be13906524f6c2a81e05b8d83c"
[[package]]
name = "cranelift-entity"
version = "0.68.0"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86badbce14e15f52a45b666b38abe47b204969dd7f8fb7488cb55dd46b361fa6"
checksum = "3b044234aa32531f89a08b487630ddc6744696ec04c8123a1ad388de837f5de3"
[[package]]
name = "cranelift-frontend"
version = "0.68.0"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b608bb7656c554d0a4cf8f50c7a10b857e80306f6ff829ad6d468a7e2323c8d8"
checksum = "5452b3e4e97538ee5ef2cc071301c69a86c7adf2770916b9d04e9727096abd93"
dependencies = [
"cranelift-codegen",
"log",
@@ -410,35 +406,12 @@ dependencies = [
]
[[package]]
name = "cranelift-module"
version = "0.68.0"
name = "cranelift-jit"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdaf0b5c93a610ff988fe5e2adbb7f6afa89cf702ca41acc3479dc35638d3a8d"
checksum = "3ffd9b060436974c7e777630ad459f3609ff1b868f43419ad63297be6bbf61ad"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"log",
"thiserror",
]
[[package]]
name = "cranelift-native"
version = "0.68.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5246a1af14b7812ee4d94a3f0c4b295ec02c370c08b0ecc3dec512890fdad175"
dependencies = [
"cranelift-codegen",
"raw-cpuid",
"target-lexicon",
]
[[package]]
name = "cranelift-simplejit"
version = "0.68.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2522ebdff6ba637c0b5e75bc3d40cc990ac1128e13547b740f10fc7b16d3991"
dependencies = [
"cranelift-codegen",
"cranelift-entity",
"cranelift-module",
@@ -451,6 +424,30 @@ dependencies = [
"winapi",
]
[[package]]
name = "cranelift-module"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b17bc01cb9f176156d5cbd47ece19292e04e05a91a837dcf0ef69cc1e0e97a5a"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"log",
"thiserror",
]
[[package]]
name = "cranelift-native"
version = "0.69.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f68035c10b2e80f26cc29c32fa824380877f38483504c2a47b54e7da311caaf3"
dependencies = [
"cranelift-codegen",
"raw-cpuid",
"target-lexicon",
]
[[package]]
name = "crc"
version = "1.8.1"
@@ -551,6 +548,12 @@ dependencies = [
"lazy_static 1.4.0",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-mac"
version = "0.7.0"
@@ -670,18 +673,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "docopt"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f525a586d310c87df72ebcd98009e57f1cc030c8c268305287a476beb653969"
dependencies = [
"lazy_static 1.4.0",
"regex",
"serde",
"strsim 0.9.3",
]
[[package]]
name = "dtoa"
version = "0.4.6"
@@ -755,26 +746,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fehler"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5729fe49ba028cd550747b6e62cd3d841beccab5390aa398538c31a2d983635"
dependencies = [
"fehler-macros",
]
[[package]]
name = "fehler-macros"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccb5acb1045ebbfa222e2c50679e392a71dd77030b78fb0189f2d9c5974400f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
@@ -885,6 +856,18 @@ dependencies = [
"cfg-if 0.1.10",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"wasm-bindgen",
]
@@ -899,6 +882,9 @@ name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
"ahash 0.4.7",
]
[[package]]
name = "hermit-abi"
@@ -1011,34 +997,35 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
[[package]]
name = "lalrpop"
version = "0.19.1"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60fb56191fb8ed5311597e5750debe6779c9fdb487dbaa5ff302592897d7a2c8"
checksum = "4a71d75b267b3299da9ccff4dd80d73325b5d8adcd76fe97cf92725eb7c6f122"
dependencies = [
"ascii-canvas",
"atty",
"bit-set",
"diff",
"docopt",
"ena",
"itertools",
"lalrpop-util",
"petgraph",
"pico-args",
"regex",
"regex-syntax",
"serde",
"serde_derive",
"sha2",
"string_cache",
"term",
"tiny-keccak",
"unicode-xid",
]
[[package]]
name = "lalrpop-util"
version = "0.19.1"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6771161eff561647fad8bb7e745e002c304864fb8f436b52b30acda51fca4408"
checksum = "3ebbd90154472db6267a7d28ca08fea7788e5619fef10f2398155cb74c08f77a"
dependencies = [
"regex",
]
[[package]]
name = "lazy_static"
@@ -1067,9 +1054,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.80"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]]
name = "libffi"
@@ -1129,17 +1116,10 @@ dependencies = [
]
[[package]]
name = "lz-fear"
version = "0.1.1"
name = "lz4_flex"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06aad1ce45e4ccf7a8d7d43e0c3ad38dc5d2255174a5f29a3c39d961fbc6181d"
dependencies = [
"bitflags",
"byteorder",
"fehler",
"thiserror",
"twox-hash",
]
checksum = "a9025814971d70dd729afe3b93b02d653c905dadb9821d5578458e12dea5148f"
[[package]]
name = "mach"
@@ -1206,12 +1186,11 @@ dependencies = [
[[package]]
name = "mt19937"
version = "1.0.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c674293daac706360a8fa633c802ca15d27ee4a52394f12ecec2f6d2aa5508bf"
checksum = "3e6dd1b4462edbfbc0c4ad4c3205d94623bb94b4819aa0888936988d38834158"
dependencies = [
"rand",
"rand_core",
"rand_core 0.6.0",
]
[[package]]
@@ -1443,6 +1422,41 @@ dependencies = [
"indexmap",
]
[[package]]
name = "phf"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
"phf_macros",
"phf_shared",
"proc-macro-hack",
]
[[package]]
name = "phf_generator"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
dependencies = [
"phf_shared",
"rand 0.7.3",
]
[[package]]
name = "phf_macros"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
@@ -1452,6 +1466,12 @@ dependencies = [
"siphasher",
]
[[package]]
name = "pico-args"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b9b4df73455c861d7cbf8be42f01d3b373ed7f02e378d55fa84eafc6f638b1"
[[package]]
name = "pkg-config"
version = "0.3.19"
@@ -1517,6 +1537,12 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "puruspe"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96e65ac785a4b9fe1d1046da0a3b5fad0a2a1606c66e41f5bfb86be8851ea0c3"
[[package]]
name = "python3-sys"
version = "0.5.1"
@@ -1548,11 +1574,24 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"getrandom 0.1.15",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc 0.2.0",
"rand_pcg",
]
[[package]]
name = "rand"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12"
dependencies = [
"libc",
"rand_chacha 0.3.0",
"rand_core 0.6.0",
"rand_hc 0.3.0",
]
[[package]]
@@ -1562,7 +1601,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
"rand_core 0.5.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
"rand_core 0.6.0",
]
[[package]]
@@ -1571,7 +1620,16 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
"getrandom 0.1.15",
]
[[package]]
name = "rand_core"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8b34ba8cfb21243bd8df91854c830ff0d785fff2e82ebd4434c2644cb9ada18"
dependencies = [
"getrandom 0.2.1",
]
[[package]]
@@ -1580,14 +1638,32 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
"rand_core 0.5.1",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core 0.6.0",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "raw-cpuid"
version = "7.0.3"
version = "8.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf"
checksum = "1fdf7d9dbd43f3d81d94a49c1c3df73cc2b3827995147e6cf7f89d4ec5483e73"
dependencies = [
"bitflags",
"cc",
@@ -1631,7 +1707,7 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [
"getrandom",
"getrandom 0.1.15",
"redox_syscall",
"rust-argon2",
]
@@ -1769,7 +1845,7 @@ dependencies = [
"bitflags",
"bstr",
"itertools",
"lz-fear",
"lz4_flex",
"num-bigint",
"num-complex",
"serde",
@@ -1789,7 +1865,7 @@ dependencies = [
"num-traits",
"once_cell",
"parking_lot",
"rand",
"rand 0.8.0",
"siphasher",
"volatile",
]
@@ -1808,15 +1884,17 @@ dependencies = [
name = "rustpython-compiler-core"
version = "0.1.2"
dependencies = [
"arrayvec",
"ahash 0.6.2",
"indexmap",
"insta",
"itertools",
"log",
"num-complex",
"num-traits",
"rustpython-ast",
"rustpython-bytecode",
"rustpython-parser",
"scopeguard",
]
[[package]]
@@ -1841,8 +1919,8 @@ version = "0.1.2"
dependencies = [
"approx",
"cranelift",
"cranelift-jit",
"cranelift-module",
"cranelift-simplejit",
"libffi",
"num-traits",
"rustpython-bytecode",
@@ -1854,11 +1932,14 @@ dependencies = [
name = "rustpython-parser"
version = "0.1.2"
dependencies = [
"ahash 0.6.2",
"hashbrown",
"lalrpop",
"lalrpop-util",
"log",
"num-bigint",
"num-traits",
"phf",
"rustpython-ast",
"unic-emoji-char",
"unic-ucd-ident",
@@ -1878,13 +1959,12 @@ name = "rustpython-vm"
version = "0.1.2"
dependencies = [
"adler32",
"arr_macro",
"ahash 0.6.2",
"atty",
"base64",
"bitflags",
"blake2",
"bstr",
"byteorder",
"caseless",
"cfg-if 0.1.10",
"chrono",
@@ -1900,7 +1980,8 @@ dependencies = [
"flate2",
"foreign-types-shared",
"gethostname",
"getrandom",
"getrandom 0.2.1",
"half",
"hex",
"hexf-parse",
"indexmap",
@@ -1910,7 +1991,6 @@ dependencies = [
"libc",
"libz-sys",
"log",
"maplit",
"md-5",
"mt19937",
"nix",
@@ -1927,8 +2007,9 @@ dependencies = [
"openssl-sys",
"parking_lot",
"paste",
"rand",
"rand_core",
"puruspe",
"rand 0.8.0",
"rand_core 0.6.0",
"regex",
"result-like",
"rustc_version_runtime",
@@ -1948,7 +2029,6 @@ dependencies = [
"sha3",
"socket2",
"static_assertions",
"statrs",
"thiserror",
"thread_local",
"timsort",
@@ -2164,13 +2244,12 @@ checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75"
[[package]]
name = "socket2"
version = "0.3.17"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902"
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"winapi",
]
@@ -2180,15 +2259,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "statrs"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cce16f6de653e88beca7bd13780d08e09d4489dbca1f9210e041bc4852481382"
dependencies = [
"rand",
]
[[package]]
name = "string_cache"
version = "0.8.1"
@@ -2199,7 +2269,6 @@ dependencies = [
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
"serde",
]
[[package]]
@@ -2208,12 +2277,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "subtle"
version = "1.0.0"
@@ -2360,6 +2423,15 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb4fa83bb73adf1c7219f4fe4bf3c0ac5635e4e51e070fad5df745a41bedfb8"
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tinytemplate"
version = "1.1.0"
@@ -2394,16 +2466,6 @@ dependencies = [
"serde",
]
[[package]]
name = "twox-hash"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
dependencies = [
"cfg-if 0.1.10",
"static_assertions",
]
[[package]]
name = "typenum"
version = "1.12.0"
@@ -2602,6 +2664,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "volatile"
version = "0.3.0"

View File

@@ -68,9 +68,5 @@ opt-level = 3
[patch.crates-io]
# REDOX START, Uncommment when you want to compile/check with redoxer
# # following patches are just waiting on a new version to be released to crates.io
# nix = { git = "https://github.com/nix-rust/nix" }
# crossbeam-utils = { git = "https://github.com/crossbeam-rs/crossbeam" }
# socket2 = { git = "https://github.com/alexcrichton/socket2-rs" }
# REDOX END

View File

@@ -0,0 +1,50 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,E74528136B90D2DD
WRHVD2PJXPqjFSHg92HURIsUzvsTE4a9oi0SC5yMBFKNWA5Z933gK3XTifp6jul5
zpNYi8jBXZ2EqJJBxCuVcefmXSxL0q7CMej25TdIC4BVAFJVveeprHPUFkNB0IM1
go5Lg4YofYqTCg3OE3k7WvfR3Zg1cRYxksDKO+WNZgWyKBex5X4vjOiyUqDl3GKt
kQXnkg1VgPV2Vrx93S9XNdELNRTguwf+XG0fkhtYhp/zCto8uKTgy5elK2P/ulGp
7fe6uj7h/uN9L7EOC6CjRkitywfeBUER739mOcGT4imSFJ9G27TCqPzj2ea3uuaf
/v1xhkQ4M6lNY/gcRfgVpCXhW43aAQV8XXQRMJTqLmz5Y5hYTKn+Ugq5vJ/ngyRM
lu1gUJnYYaemBTb4hbm6aBvnYK9mORa891Pmf+vxU9rYuQIdVAhvvXh4KBreSEBI
1AFy6dFKXl8ZKs6Wrq5wPefmFFkRmZ8OBiiq0fp2ApCRGZw6LsjCgwrRM38JiY7d
3OdsJpKvRYufgUyuuzUE0xA+E4yMvD48M9pPq2fC8O5giuGL1uEekQWXJuq+6ZRI
XYKIeSkuQALbX3RAzCPXTUEMtCYXKm/gxrrwJ+Bet4ob2amf3MX0uvWwOuAq++Fk
J0HFSBxrwvIWOhyQXOPuJdAN8PXA7dWOXfOgOMF0hQYqZCl3T4TiVZJbwVQtg1sN
dO7oAD5ZPHiKzvveZuB6k1FlBG8j0TyAC+44ChxkPDD3jF4dd6zGe62sDf85p4/d
W80gxJeD3xnDxG0ePPns+GuKUpUaWS7WvHtDpeFW1JEhvOqf8p1Li9a7RzWVo8ML
mGTdQgBIYIf6/fk69pFKl0nKtBU75KaunZz4nAmd9bNED4naDurMBg44u5TvODbJ
vgYIYXIYjNvONbskJatVrrTS8zch2NwVIjCi8L/hecwBXbIXzo1pECpc6BU7sQT8
+i9sDKBeJcRipzfKZNHvnO19mUZaPCY8+a/f9c21DgKXz+bgLcJbohpSaeGM8Gfc
aZd3Vp9n3OJ3g2zQR1++HO9v1vR/wLELu6MeydkvMduHLmOPCn54gZ9z51ZNPAwa
qfFIsH+mLh9ks0H74ssF59uIlstkgB9zmZHv/Q0dK9ZfG/VEH6rSgdETWhZxhoMQ
Z92jXBEFT0zhI3rrIPNY+XS7eJCQIc1wc84Ea3cRk7SP+S1og3JtAxX56ykUwtkM
LQ/Dwwa6h1aqD0l2d5x1/BSdavtTuSegISRWQ4iOmSvEdlFP7H4g6RZk/okbLzMD
Evq5gNc7vlXhVawoQU8JCanJ5ZbbWnIRZfiXxBQS4lpYPKvJt4ML9z/x+82XxcXv
Z93N2Wep7wWW5OwS2LcQcOgZRDSIPompwo/0pMFGOS+5oort0ZDRHdmmGLjvBcCb
1KQmKQ4+8brI/3rjRzts6uDLjTGNxSCieNsnqhwHUv9Mg9WDSWupcGa+x27L89x3
rObf6+3umcFLSjIzU8wuv1hx/e/y98Kv7BDBNYpAr6kVMrLnzYjAfJbBmqlxkzkQ
IgQzgrk2QZoTdgwR+S374NAMO0AE5IlO+/qa6qp2SORGTDX64I3UNw==
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDWTCCAkGgAwIBAgIJAPm6B21bar2bMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODAx
MTkxOTA5MDZaFw0yODAxMTcxOTA5MDZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAKvvsX2gEti4shve3iYMc+jE4Se7WHs1Bol2f21H8qNboDOFdeb1
RKHjmq3exHpajywOUEgne9nKHJY/3f2phR4Y5klqG6liLgiSpVyRlcBGbeT2qEAj
9oLiLFUXLGfGDds2mTwivQDLJBWi51j7ff5k2Pr58fN5ugYMn24T9FNyn0moT+qj
SFoBNm58l9jrdkJSlgWfqPlbiMa+mqDn/SFtrwLF2Trbfzu42Sd9UdIzMaSSrzbN
sGm53pNhCh8KndWUQ8GPP2IsLPoUU4qAtmZuTxCx2S1cXrN9EkmT69tlOH84YfSn
96Ih9bWRc7M5y5bfVdEVM+fKQl3hBRf05qMCAwEAAaMYMBYwFAYDVR0RBA0wC4IJ
bG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQAtQ8f37cCEk7/rAcbYR53ce3iK
Vpihb0U2ni1QjG9Tg9UIExkIGkwTiCm7kwQL+GEStBu9AG/QVrOjeTriRiddhWkk
ze8kRaI3AC/63t6Vh9Q1x6PESgeE4OtAO9JpJCf4GILglA789Y/b/GF8zJZQxR13
qpB4ZwWw7gCBhdEW59u6CFeBmfDa58hM8lWvuVoRrTi7bjUeC6PAn5HVMzZSykhu
4HaUfBp6bKFjuym2+h/VvM1n8C3chjVSmutsLb6ELdD8IK0vPV/yf5+LN256zSsS
dyUZYd8XwQaioEMKdbhLvnehyzHiWfQIUR3BdhONxoIJhHv/EAo8eCkHHYIF
-----END CERTIFICATE-----

48
Lib/test/keycert.pem Normal file
View File

@@ -0,0 +1,48 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCr77F9oBLYuLIb
3t4mDHPoxOEnu1h7NQaJdn9tR/KjW6AzhXXm9USh45qt3sR6Wo8sDlBIJ3vZyhyW
P939qYUeGOZJahupYi4IkqVckZXARm3k9qhAI/aC4ixVFyxnxg3bNpk8Ir0AyyQV
oudY+33+ZNj6+fHzeboGDJ9uE/RTcp9JqE/qo0haATZufJfY63ZCUpYFn6j5W4jG
vpqg5/0hba8Cxdk62387uNknfVHSMzGkkq82zbBpud6TYQofCp3VlEPBjz9iLCz6
FFOKgLZmbk8QsdktXF6zfRJJk+vbZTh/OGH0p/eiIfW1kXOzOcuW31XRFTPnykJd
4QUX9OajAgMBAAECggEAHppmXDbuw9Z0FVPg9KLIysioTtsgz6VLiZIm8juZK4x2
glUh/D7xvWL2uDXrgN+3lh7iGUW13LkFx5SMncbbo9TIwI57Z/XKvcnkVwquve+L
RfLFVc1Q5lD9lROv2rS86KTaN4LzYz3FKXi6dvMkpPAsUtfEQhMLkmISypQQq/1z
EJaqo7r85OjN7e0wKazlKZpOzJEa5FQLMVRjTRFhLFNbHXX/tAet2jw+umATKbw8
hYgiuZ44TwSEd9JeIV/oSYWfI/3HetuYW0ru3caiztRF2NySNu8lcsWgNC7fIku9
mcHjtSNzs91QN1Qlu7GQvvhpt6OWDirNDCW+49WGaQKBgQDg9SDhfF0jRYslgYbH
cqO4ggaFdHjrAAYpwnAgvanhFZL/zEqm5G1E7l/e2fCkJ9VOSFO0A208chvwMcr+
dCjHE2tVdE81aQ2v/Eo83VdS1RcOV4Y75yPH48rMhxPaHvxWD/FFDbf0/P2mtPB7
SZ3kIeZMkE1wxdaO3AKUbQoozwKBgQDDqYgg7kVtygyICE1mB8Hwp6nUxFTczG7y
4XcsDqMIrKmw+PbQluvkoHoStxeVrsTloDhkTjIrpmYLyAiazg+PUJdkd6xrfLSj
VV6X93W0S/1egEb1F1CGFxtk8v/PWH4K76EPL2vxXdxjywz3GWlrL9yDYaB2szzS
DqgwVMqx7QKBgDCD7UF0Bsoyl13RX3XoPXLvZ+SkR+e2q52Z94C4JskKVBeiwX7Y
yNAS8M4pBoMArDoj0xmBm69rlKbqtjLGbnzwrTdSzDpim7cWnBQgUFLm7gAD1Elb
AhZ8BCK0Bw4FnLoa2hfga4oEfdfUMgEE0W5/+SEOBgWKRUmuHUhRc911AoGAY2EN
YmSDYSM5wDIvVb5k9B3EtevOiqNPSw/XnsoEZtiEC/44JnQxdltIBY93bDBrk5IQ
cmoBM4h91kgQjshQwOMXMhFSwvmBKmCm/hrTbvMVytTutXfVD3ZXFKwT4DW7N0TF
ElhsxBh/YzRz7mG62JVjtFt2zDN3ld2Z8YpvtXUCgYEA4EJ4ObS5YyvcXAKHJFo6
Fxmavyrf8LSm3MFA65uSnFvWukMVqqRMReQc5jvpxHKCis+XvnHzyOfL0gW9ZTi7
tWGGbBi0TRJCa8BkvgngUZxOxUlMfg/7cVxOIB0TPoUSgxFd/+qVz4GZMvr0dPu7
eAF7J/8ECVvb0wSPTUI1N3c=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDWTCCAkGgAwIBAgIJAPm6B21bar2bMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODAx
MTkxOTA5MDZaFw0yODAxMTcxOTA5MDZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
DA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
YXRpb24xEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAKvvsX2gEti4shve3iYMc+jE4Se7WHs1Bol2f21H8qNboDOFdeb1
RKHjmq3exHpajywOUEgne9nKHJY/3f2phR4Y5klqG6liLgiSpVyRlcBGbeT2qEAj
9oLiLFUXLGfGDds2mTwivQDLJBWi51j7ff5k2Pr58fN5ugYMn24T9FNyn0moT+qj
SFoBNm58l9jrdkJSlgWfqPlbiMa+mqDn/SFtrwLF2Trbfzu42Sd9UdIzMaSSrzbN
sGm53pNhCh8KndWUQ8GPP2IsLPoUU4qAtmZuTxCx2S1cXrN9EkmT69tlOH84YfSn
96Ih9bWRc7M5y5bfVdEVM+fKQl3hBRf05qMCAwEAAaMYMBYwFAYDVR0RBA0wC4IJ
bG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQAtQ8f37cCEk7/rAcbYR53ce3iK
Vpihb0U2ni1QjG9Tg9UIExkIGkwTiCm7kwQL+GEStBu9AG/QVrOjeTriRiddhWkk
ze8kRaI3AC/63t6Vh9Q1x6PESgeE4OtAO9JpJCf4GILglA789Y/b/GF8zJZQxR13
qpB4ZwWw7gCBhdEW59u6CFeBmfDa58hM8lWvuVoRrTi7bjUeC6PAn5HVMzZSykhu
4HaUfBp6bKFjuym2+h/VvM1n8C3chjVSmutsLb6ELdD8IK0vPV/yf5+LN256zSsS
dyUZYd8XwQaioEMKdbhLvnehyzHiWfQIUR3BdhONxoIJhHv/EAo8eCkHHYIF
-----END CERTIFICATE-----

49
Lib/test/keycert2.pem Normal file
View File

@@ -0,0 +1,49 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC3ulRNfhbOAey/
B+wIVYx+d5az7EV4riR6yi/qE6G+bxbTvay2pqySHtDweuaYSh2cVmcasBKKIFJm
rCD1zR8UmLb5i2XFIina1t3eePCuBZMrvZZwkzlQUSM1AZtjGOO/W0I3FwO6y645
9xA5PduKI7SMYkH/VL3zE5W1JwMovv6bvNiT+GU5l6mB9ylCTgLpmUqoQhRqz/35
zCzVyoh+ppDvVcpWYfvXywsXsgQwbAF0QJm8SSFi0TZm5ykv4WE16afQp08yuZS0
3U4K3MJCa4rxO58edcxBopWYfQ29K3iINM8enRfr5q+u5mAAbALAEEvyFjgLWl/u
7arxn7bJAgMBAAECggEBAJfMt8KfHzBunrDnVrk8FayYGkfmOzAOkc1yKEx6k/TH
zFB+Mqlm5MaF95P5t3S0J+r36JBAUdEWC38RUNpF9BwMYYGlDxzlsTdCuGYL/q+J
o6NMLXQt7/jQUQqGnWAvPFzqhbcGqOo5R2ZVH25sEWv9PDuRI35XAepIkDTwWsfa
P6UcJJoP+4v9B++fb3sSL4zNwp1BqS4wxR8YTR0t1zQqOxJ5BGPw1J8aBMs1sq5t
qyosAQAT63kLrdqWotHaM26QxjqEQUMlh12XMWb5GdBXUxbvyGtEabsqskGa/f8B
RdHE437J8D8l+jxb2mZLzrlaH3dq2tbFGCe1rT8qLRECgYEA5CWIvoD/YnQydLGA
OlEhCSocqURuqcotg9Ev0nt/C60jkr/NHFLGppz9lhqjIDjixt3sIMGZMFzxRtwM
pSYal3XiR7rZuHau9iM35yDhpuytEiGbYy1ADakJRzY5jq/Qa8RfPP9Atua5xAeP
q6DiSnq9vhHv9G+O4MxzHBmrw9sCgYEAziiJWFthcwvuXn3Jv9xFYKEb/06puZAx
EgQCz/3rPzv5fmGD/sKVo1U/K4z/eA82DNeKG8QRTFJCxT8TCNRxOmGV7HdCYo/B
4BTNNvbKcdi3l0j75kKoADg+nt5CD5lz6gLG0GrUEnVO1y5HVfCTb3BEAfa36C85
9i0sfQGiwysCgYEAuus9k8cgdct5oz3iLuVVSark/JGCkT2B+OOkaLChsDFUWeEm
7TOsaclpwldkmvvAYOplkZjMJ2GelE2pVo1XcAw3LkmaI5WpVyQXoxe/iQGT8qzy
IFlsh0Scw2lb0tmcyw6CcPk4TiHOxRrkzNrtS9QwLM+JZx0XVHptPPKTVc0CgYAu
j/VFYY5G/8Dc0qhIjyWUR48dQNUQtkJ/ASzpcT46z/7vznKTjbtiYpSb74KbyUO5
7sygrM4DYOj3x+Eys1jHiNbly6HQxQtS4x/edCsRP5NntfI+9XsgYZOzKhvdjhki
F3J0DEzNxnUCIM+311hVaRPTJbgv1srOkTFlIoNydQKBgQC6/OHGaC/OewQqRlRK
Mg5KZm01/pk4iKrpA5nG7OTAeoa70NzXNtG8J3WnaJ4mWanNwNUOyRMAMrsUAy9q
EeGqHM5mMFpY4TeVuNLL21lu/x3KYw6mKL3Ctinn+JLAoYoqEy8deZnEA5/tjYlz
YhFBchnUicjoUN1chdpM6SpV2Q==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDYjCCAkqgAwIBAgIJALJXRr8qF6oIMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x
ODAxMTkxOTA5MDZaFw0yODAxMTcxOTA5MDZaMGIxCzAJBgNVBAYTAlhZMRcwFQYD
VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv
dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBALe6VE1+Fs4B7L8H7AhVjH53lrPsRXiuJHrKL+oTob5v
FtO9rLamrJIe0PB65phKHZxWZxqwEoogUmasIPXNHxSYtvmLZcUiKdrW3d548K4F
kyu9lnCTOVBRIzUBm2MY479bQjcXA7rLrjn3EDk924ojtIxiQf9UvfMTlbUnAyi+
/pu82JP4ZTmXqYH3KUJOAumZSqhCFGrP/fnMLNXKiH6mkO9VylZh+9fLCxeyBDBs
AXRAmbxJIWLRNmbnKS/hYTXpp9CnTzK5lLTdTgrcwkJrivE7nx51zEGilZh9Db0r
eIg0zx6dF+vmr67mYABsAsAQS/IWOAtaX+7tqvGftskCAwEAAaMbMBkwFwYDVR0R
BBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBCwUAA4IBAQCZhHhGItpkqhEq
ntMRd6Hv0GoOJixNvgeMwK4NJSRT/no3OirtUTzccn46h+SWibSa2eVssAV+pAVJ
HbzkN/DH27A1mMx1zJL1ekcOKA1AF6MXhUnrUGXMqW36YNtzHfXJLrwvpLJ13OQg
/Kxo4Nw68bGzM+PyRtKU/mpgYyfcvwR+ZSeIDh1fvUZK/IEVCf8ub42GPVs5wPfv
M+k5aHxWTxeif3K1byTRzxHupYNG2yWO4XEdnBGOuOwzzN4/iQyNcsuQKeuKHGrt
YvIlG/ri04CQ7xISZCj74yjTZ+/A2bXre2mQXAHqKPumHL7cl34+erzbUaxYxbTE
u5FcOmLQ
-----END CERTIFICATE-----

132
Lib/test/keycert3.pem Normal file
View File

@@ -0,0 +1,132 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgV4G+Zzf2DT5n
oAisIGFhn/bz7Vn5WiXUqbDsxROJOh/7BtOlduZka0pPhFylGbnxS8l1kEWHRI2T
6hOoWzumB6ItKiN+T5J30lAvSyo7iwdFoAQ/S5nPXQfhNARQe/NEOhRtpcuNdyx4
BWdPdPuJQA1ASNJCLwcLOoRxaLbKLvb2V5T5FCAkeNPtRvPuT4gKQItMmiHfAhoV
C8MZWF/GC0RukHINys5MwqeFexam8CznmQPMYrLdhmKTj3DTivCPoh97EDIFGlgZ
SCaaYDVQA+aqlo/q2pi52PFwC1KzhNEA7EeOqSwC1NQjwjHuhcnf9WbxrgTq2zh3
rv5YEW2ZAgMBAAECggEAPfSMtTumPcJskIumuXp7yk02EyliZrWZqwBuBwVqHsS5
nkbFXnXWrLbgn9MrDsFrE5NdgKUmPnQVMVs8sIr5jyGejSCNCs4I4iRn1pfIgwcj
K/xEEALd6GGF0pDd/CgvB5GOoLVf4KKf2kmLvWrOKJpSzoUN5A8+v8AaYYOMr4sC
czbvfGomzEIewEG+Rw9zOVUDlmwyEKPQZ47E7PQ+EEA7oeFdR+1Zj6eT9ndegf8B
54frySYCLRUCk/sHCpWhaJBtBrcpht7Y8CfY7hiH/7x866fvuLnYPz4YALtUb0wN
7zUCNS9ol3n4LbjFFKfZtiRjKaCBRzMjK0rz6ydFcQKBgQDyLI3oGbnW73vqcDe/
6eR0w++fiCAVhfMs3AO/gOaJi2la2JHlJ5u+cIHQIOFwEhn6Zq0AtdmnFx1TS5IQ
C0MdXI0XoQQw7rEF8EJcvfe85Z0QxENVhzydtdb8QpJfnQGfBfLyQlaaRYzRRHB6
VdYUHF3EIPVIhbjbghal+Qep/QKBgQDtJlRPHkWwTMevu0J0fYbWN1ywtVTFUR//
k7VyORSf8yuuSnaQRop4cbcqONxmDKH6Or1fl3NYBsAxtXkkOK1E2OZNo2sfQdRa
wpA7o7mPHRhztQFpT5vflp+8P6+PEFat8D04eBOhNwrwwfhiPjD4gv5KvN4XutRW
VWv/2pnmzQKBgHPvHGg2mJ7quvm6ixXW1MWJX1eSBToIjCe3lBvDi5nhIaiZ8Q4w
7gA3QA3xD7tlDwauzLeAVxgEmsdbcCs6GQEfY3QiYy1Bt4FOSZa4YrcNfSmfq1Rw
j3Y4rRjKjeQz96i3YlzToT3tecJc7zPBj+DEy6au2H3Fdn+vQURneWHJAoGBANG7
XES8mRVaUh/wlM1BVsaNH8SIGfiHzqzRjV7/bGYpQTBbWpAuUrhCmaMVtpXqBjav
TFwGLVRkZAWSYRjPpy2ERenT5SE3rv61o6mbGrifGsj6A82HQmtzYsGx8SmtYXtj
REF0sKebbmmOooUAS379GrguYJzL9o6D7YfRZNrhAoGAVfb/tiFU4S67DSpYpQey
ULhgfsFpDByICY6Potsg67gVFf9jIaB83NPTx3u/r6sHFgxFw7lQsuZcgSuWMu7t
glzOXVIP11Y5sl5CJ5OsfeK1/0umMZF5MWPyAQCx/qrPlZL86vXjt24Y/VaOxsAi
CZYdyJsjgOrJrWoMbo5ta54=
-----END PRIVATE KEY-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
82:ed:bf:41:c8:80:91:9c
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
Not Before: Jan 19 19:09:06 2018 GMT
Not After : Nov 28 19:09:06 2027 GMT
Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:e0:57:81:be:67:37:f6:0d:3e:67:a0:08:ac:20:
61:61:9f:f6:f3:ed:59:f9:5a:25:d4:a9:b0:ec:c5:
13:89:3a:1f:fb:06:d3:a5:76:e6:64:6b:4a:4f:84:
5c:a5:19:b9:f1:4b:c9:75:90:45:87:44:8d:93:ea:
13:a8:5b:3b:a6:07:a2:2d:2a:23:7e:4f:92:77:d2:
50:2f:4b:2a:3b:8b:07:45:a0:04:3f:4b:99:cf:5d:
07:e1:34:04:50:7b:f3:44:3a:14:6d:a5:cb:8d:77:
2c:78:05:67:4f:74:fb:89:40:0d:40:48:d2:42:2f:
07:0b:3a:84:71:68:b6:ca:2e:f6:f6:57:94:f9:14:
20:24:78:d3:ed:46:f3:ee:4f:88:0a:40:8b:4c:9a:
21:df:02:1a:15:0b:c3:19:58:5f:c6:0b:44:6e:90:
72:0d:ca:ce:4c:c2:a7:85:7b:16:a6:f0:2c:e7:99:
03:cc:62:b2:dd:86:62:93:8f:70:d3:8a:f0:8f:a2:
1f:7b:10:32:05:1a:58:19:48:26:9a:60:35:50:03:
e6:aa:96:8f:ea:da:98:b9:d8:f1:70:0b:52:b3:84:
d1:00:ec:47:8e:a9:2c:02:d4:d4:23:c2:31:ee:85:
c9:df:f5:66:f1:ae:04:ea:db:38:77:ae:fe:58:11:
6d:99
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:localhost
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
85:11:BE:16:47:04:D1:30:EE:86:8A:18:70:BE:A8:28:6F:82:3D:CE
X509v3 Authority Key Identifier:
keyid:9A:CF:CF:6E:EB:71:3D:DB:3C:F1:AE:88:6B:56:72:03:CB:08:A7:48
DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server
serial:82:ED:BF:41:C8:80:91:9B
Authority Information Access:
CA Issuers - URI:http://testca.pythontest.net/testca/pycacert.cer
OCSP - URI:http://testca.pythontest.net/testca/ocsp/
X509v3 CRL Distribution Points:
Full Name:
URI:http://testca.pythontest.net/testca/revocation.crl
Signature Algorithm: sha1WithRSAEncryption
7f:a1:7e:3e:68:01:b0:32:b8:57:b8:03:68:13:13:b3:e3:f4:
70:2f:15:e5:0f:87:b9:fd:e0:12:e3:16:f2:91:53:c7:4e:25:
af:ca:cb:a7:d9:9d:57:4d:bf:a2:80:d4:78:aa:04:31:fd:6d:
cc:6d:82:43:e9:62:16:0d:0e:26:8b:e7:f1:3d:57:5c:68:02:
9c:2b:b6:c9:fd:62:2f:10:85:88:cc:44:a5:e7:a2:3e:89:f2:
1f:02:6a:3f:d0:3c:6c:24:2d:bc:51:62:7a:ec:25:c5:86:87:
77:35:8f:f9:7e:d0:17:3d:77:56:bf:1a:0c:be:09:78:ee:ea:
73:97:65:60:94:91:35:b3:5c:46:8a:5e:6d:94:52:de:48:b7:
1f:6c:28:79:7f:ff:08:8d:e4:7d:d0:b9:0b:7c:ae:c4:1d:2a:
a1:b3:50:11:82:03:5e:6c:e7:26:fa:05:32:39:07:83:49:b9:
a2:fa:04:da:0d:e5:ff:4c:db:97:d0:c3:a7:43:37:4c:16:de:
3c:b5:e9:7e:82:d4:b3:10:df:d1:c1:66:72:9c:15:67:19:3b:
7b:91:0a:82:07:67:c5:06:03:5f:80:54:08:81:8a:b1:5c:7c:
4c:d2:07:38:92:eb:12:f5:71:ae:de:05:15:c8:e1:33:f0:e4:
96:0f:0f:1e
-----BEGIN CERTIFICATE-----
MIIE8TCCA9mgAwIBAgIJAILtv0HIgJGcMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODAxMTkxOTA5MDZaFw0yNzExMjgx
OTA5MDZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj
MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxv
Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOBXgb5nN/YN
PmegCKwgYWGf9vPtWflaJdSpsOzFE4k6H/sG06V25mRrSk+EXKUZufFLyXWQRYdE
jZPqE6hbO6YHoi0qI35PknfSUC9LKjuLB0WgBD9Lmc9dB+E0BFB780Q6FG2ly413
LHgFZ090+4lADUBI0kIvBws6hHFotsou9vZXlPkUICR40+1G8+5PiApAi0yaId8C
GhULwxlYX8YLRG6Qcg3KzkzCp4V7FqbwLOeZA8xist2GYpOPcNOK8I+iH3sQMgUa
WBlIJppgNVAD5qqWj+ramLnY8XALUrOE0QDsR46pLALU1CPCMe6Fyd/1ZvGuBOrb
OHeu/lgRbZkCAwEAAaOCAcAwggG8MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDAOBgNV
HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
EwEB/wQCMAAwHQYDVR0OBBYEFIURvhZHBNEw7oaKGHC+qChvgj3OMH0GA1UdIwR2
MHSAFJrPz27rcT3bPPGuiGtWcgPLCKdIoVGkTzBNMQswCQYDVQQGEwJYWTEmMCQG
A1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91
ci1jYS1zZXJ2ZXKCCQCC7b9ByICRmzCBgwYIKwYBBQUHAQEEdzB1MDwGCCsGAQUF
BzAChjBodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9weWNhY2Vy
dC5jZXIwNQYIKwYBBQUHMAGGKWh0dHA6Ly90ZXN0Y2EucHl0aG9udGVzdC5uZXQv
dGVzdGNhL29jc3AvMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly90ZXN0Y2EucHl0
aG9udGVzdC5uZXQvdGVzdGNhL3Jldm9jYXRpb24uY3JsMA0GCSqGSIb3DQEBBQUA
A4IBAQB/oX4+aAGwMrhXuANoExOz4/RwLxXlD4e5/eAS4xbykVPHTiWvysun2Z1X
Tb+igNR4qgQx/W3MbYJD6WIWDQ4mi+fxPVdcaAKcK7bJ/WIvEIWIzESl56I+ifIf
Amo/0DxsJC28UWJ67CXFhod3NY/5ftAXPXdWvxoMvgl47upzl2VglJE1s1xGil5t
lFLeSLcfbCh5f/8IjeR90LkLfK7EHSqhs1ARggNebOcm+gUyOQeDSbmi+gTaDeX/
TNuX0MOnQzdMFt48tel+gtSzEN/RwWZynBVnGTt7kQqCB2fFBgNfgFQIgYqxXHxM
0gc4kusS9XGu3gUVyOEz8OSWDw8e
-----END CERTIFICATE-----

132
Lib/test/keycert4.pem Normal file
View File

@@ -0,0 +1,132 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDH/76hZAZH4cSV
CmVZa5HEqKCjCKrcPwBECs9BS+3ibwN4x9NnFNP+tCeFGgJXl7WGFoeXgg3oK+1p
FsOWpsRHuF3BdqkCnShSydmT8bLaGHwKeL0cPxJP5T/uW7ezPKW2VWXGMwmwRaRJ
9dj2VCUu20vDZWSGFr9zjnjoJczBtH3RsVUgpK7euEHuQ5pIM9QSOaCo+5FPR7s7
1nU7YqbFWtd+NhC8Og1G497B31DQlHciF6BRm6/cNGAmHaAErKUGBFdkGtFPHBn4
vktoEg9fwxJAZLvGpoTZWrB4HRsRwVTmFdGvK+JXK225xF23AXRXp/snhSuSFeLj
E5cpyJJ7AgMBAAECggEAQOv527X2e/sDr0XSpHZQuT/r9UBpBlnFIlFH+fBF5k0X
GWv0ae/O6U1dzs0kmX57xG0n0ry6+vTXeleTYiH8cTOd66EzN9AAOO+hG29IGZf9
HAEZkkO/FARc/mjzdtFnEYsjIHWM3ZWdwQx3Q28JKu6w51rQiN51g3NqOCGdF/uF
rE5XPKsKndn+nLHvsNuApFgUYZEwdrozgUueEgRaPTUCNhzotcA9eWoBdA24XNhk
x8Cm/bZWabXm7gBO75zl3Cu2F21ay+EuwyOZTsx6lZi6YX9/zo1mkO81Zi3tQk50
NMEI0feLNwsdxTbmOcVJadjOgd+QVghlFyr5HGBWMQKBgQD3AH3rhnAo6tOyNkGN
+IzIU1MhUS452O7IavykUYO9sM24BVChpRtlI9Dpev4yE/q3BAO3+oWT3cJrN7/3
iyo1dzAkpGvI65XWfElXFM4nLjEiZzx4W9fiPN91Oucpr0ED6+BZXTtz4gVm0TP/
TUc2xvTB6EKvIyWmKOYEi0snxQKBgQDPSOjbz9jWOrC9XY7PmtLB6QJDDz7XSGVK
wzD+gDAPpAwhk58BEokdOhBx2Lwl8zMJi0CRHgH2vNvkRyhvUQ4UFzisrqann/Tw
klp5sw3iWC6ERC8z9zL7GfHs7sK3mOVeAdK6ffowPM3JrZ2vPusVBdr0MN3oZwki
CtNXqbY1PwKBgGheQNbAW6wubX0kB9chavtKmhm937Z5v4vYCSC1gOEqUAKt3EAx
L74wwBmn6rjmUE382EVpCgBM99WuHONQXmlxD1qsTw763LlgkuzE0cckcYaD8L06
saHa7uDuHrcyYlpx1L5t8q0ol/e19i6uTKUMtGcq6OJwC3yGU4sgAIWxAoGBAMVq
qiQXm2vFL+jafxYoXUvDMJ1PmskMsTP4HOR2j8+FrOwZnVk3HxGP6HOVOPRn4JbZ
YiAT1Uj6a+7I+rCyINdvmlGUcTK6fFzW9oZryvBkjcD483/pkktmVWwTpa2YV/Ml
h16IdsyUTGYlDUYHhXtbPUJOfDpIT4F1j/0wrFGfAoGAO82BcUsehEUQE0xvQLIn
7QaFtUI5z19WW730jVuEobiYlh9Ka4DPbKMvka8MwyOxEwhk39gZQavmfG6+wZm+
kjERU23LhHziJGWS2Um4yIhC7myKbWaLzjHEq72dszLpQku4BzE5fT60fxI7cURD
WGm/Z3Q2weS3ZGIoMj1RNPI=
-----END PRIVATE KEY-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
82:ed:bf:41:c8:80:91:9d
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
Not Before: Jan 19 19:09:06 2018 GMT
Not After : Nov 28 19:09:06 2027 GMT
Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=fakehostname
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c7:ff:be:a1:64:06:47:e1:c4:95:0a:65:59:6b:
91:c4:a8:a0:a3:08:aa:dc:3f:00:44:0a:cf:41:4b:
ed:e2:6f:03:78:c7:d3:67:14:d3:fe:b4:27:85:1a:
02:57:97:b5:86:16:87:97:82:0d:e8:2b:ed:69:16:
c3:96:a6:c4:47:b8:5d:c1:76:a9:02:9d:28:52:c9:
d9:93:f1:b2:da:18:7c:0a:78:bd:1c:3f:12:4f:e5:
3f:ee:5b:b7:b3:3c:a5:b6:55:65:c6:33:09:b0:45:
a4:49:f5:d8:f6:54:25:2e:db:4b:c3:65:64:86:16:
bf:73:8e:78:e8:25:cc:c1:b4:7d:d1:b1:55:20:a4:
ae:de:b8:41:ee:43:9a:48:33:d4:12:39:a0:a8:fb:
91:4f:47:bb:3b:d6:75:3b:62:a6:c5:5a:d7:7e:36:
10:bc:3a:0d:46:e3:de:c1:df:50:d0:94:77:22:17:
a0:51:9b:af:dc:34:60:26:1d:a0:04:ac:a5:06:04:
57:64:1a:d1:4f:1c:19:f8:be:4b:68:12:0f:5f:c3:
12:40:64:bb:c6:a6:84:d9:5a:b0:78:1d:1b:11:c1:
54:e6:15:d1:af:2b:e2:57:2b:6d:b9:c4:5d:b7:01:
74:57:a7:fb:27:85:2b:92:15:e2:e3:13:97:29:c8:
92:7b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:fakehostname
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
F8:76:79:CB:11:85:F0:46:E5:95:E6:7E:69:CB:12:5E:4E:AA:EC:4D
X509v3 Authority Key Identifier:
keyid:9A:CF:CF:6E:EB:71:3D:DB:3C:F1:AE:88:6B:56:72:03:CB:08:A7:48
DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server
serial:82:ED:BF:41:C8:80:91:9B
Authority Information Access:
CA Issuers - URI:http://testca.pythontest.net/testca/pycacert.cer
OCSP - URI:http://testca.pythontest.net/testca/ocsp/
X509v3 CRL Distribution Points:
Full Name:
URI:http://testca.pythontest.net/testca/revocation.crl
Signature Algorithm: sha1WithRSAEncryption
6d:50:8d:fb:ee:4e:93:8b:eb:47:56:ba:38:cc:80:e1:9d:c7:
e1:9e:1f:9c:22:0c:d2:08:9b:ed:bf:31:d9:00:ee:af:8c:56:
78:92:d1:7c:ba:4e:81:7f:82:1f:f4:68:99:86:91:c6:cb:57:
d3:b9:41:12:fa:75:53:fd:22:32:21:50:af:6b:4c:b1:34:36:
d1:a8:25:0a:d0:f0:f8:81:7d:69:58:6e:af:e3:d2:c4:32:87:
79:d7:cd:ad:0c:56:f3:15:27:10:0c:f9:57:59:53:00:ed:af:
5d:4d:07:86:7a:e5:f3:97:88:bc:86:b4:f1:17:46:33:55:28:
66:7b:70:d3:a5:12:b9:4f:c7:ed:e6:13:20:2d:f0:9e:ec:17:
64:cf:fd:13:14:1b:76:ba:64:ac:c5:51:b6:cd:13:0a:93:b1:
fd:43:09:a0:0b:44:6c:77:45:43:0b:e5:ed:70:b2:76:dc:08:
4a:5b:73:5f:c1:fc:7f:63:70:f8:b9:ca:3c:98:06:5f:fd:98:
d1:e4:e6:61:5f:09:8f:6c:18:86:98:9c:cb:3f:73:7b:3f:38:
f5:a7:09:20:ee:a5:63:1c:ff:8b:a6:d1:8c:e8:f4:84:3d:99:
38:0f:cc:e0:52:03:f9:18:05:23:76:39:de:52:ce:8e:fb:a6:
6e:f5:4f:c3
-----BEGIN CERTIFICATE-----
MIIE9zCCA9+gAwIBAgIJAILtv0HIgJGdMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODAxMTkxOTA5MDZaFw0yNzExMjgx
OTA5MDZaMGIxCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj
MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZh
a2Vob3N0bmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMf/vqFk
BkfhxJUKZVlrkcSooKMIqtw/AEQKz0FL7eJvA3jH02cU0/60J4UaAleXtYYWh5eC
Degr7WkWw5amxEe4XcF2qQKdKFLJ2ZPxstoYfAp4vRw/Ek/lP+5bt7M8pbZVZcYz
CbBFpEn12PZUJS7bS8NlZIYWv3OOeOglzMG0fdGxVSCkrt64Qe5Dmkgz1BI5oKj7
kU9HuzvWdTtipsVa1342ELw6DUbj3sHfUNCUdyIXoFGbr9w0YCYdoASspQYEV2Qa
0U8cGfi+S2gSD1/DEkBku8amhNlasHgdGxHBVOYV0a8r4lcrbbnEXbcBdFen+yeF
K5IV4uMTlynIknsCAwEAAaOCAcMwggG/MBcGA1UdEQQQMA6CDGZha2Vob3N0bmFt
ZTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPh2ecsRhfBG5ZXmfmnLEl5OquxNMH0G
A1UdIwR2MHSAFJrPz27rcT3bPPGuiGtWcgPLCKdIoVGkTzBNMQswCQYDVQQGEwJY
WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV
BAMMDW91ci1jYS1zZXJ2ZXKCCQCC7b9ByICRmzCBgwYIKwYBBQUHAQEEdzB1MDwG
CCsGAQUFBzAChjBodHRwOi8vdGVzdGNhLnB5dGhvbnRlc3QubmV0L3Rlc3RjYS9w
eWNhY2VydC5jZXIwNQYIKwYBBQUHMAGGKWh0dHA6Ly90ZXN0Y2EucHl0aG9udGVz
dC5uZXQvdGVzdGNhL29jc3AvMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly90ZXN0
Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3Jldm9jYXRpb24uY3JsMA0GCSqGSIb3
DQEBBQUAA4IBAQBtUI377k6Ti+tHVro4zIDhncfhnh+cIgzSCJvtvzHZAO6vjFZ4
ktF8uk6Bf4If9GiZhpHGy1fTuUES+nVT/SIyIVCva0yxNDbRqCUK0PD4gX1pWG6v
49LEMod5182tDFbzFScQDPlXWVMA7a9dTQeGeuXzl4i8hrTxF0YzVShme3DTpRK5
T8ft5hMgLfCe7Bdkz/0TFBt2umSsxVG2zRMKk7H9QwmgC0Rsd0VDC+XtcLJ23AhK
W3Nfwfx/Y3D4uco8mAZf/ZjR5OZhXwmPbBiGmJzLP3N7Pzj1pwkg7qVjHP+LptGM
6PSEPZk4D8zgUgP5GAUjdjneUs6O+6Zu9U/D
-----END CERTIFICATE-----

96
Lib/test/keycertecc.pem Normal file
View File

@@ -0,0 +1,96 @@
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDe3QWmhZX07HZbntz4
CFqAOaoYMdYwD7Z3WPNIc2zR7p4D6BMOa7NAWjLV5A7CUw6hZANiAAQ5IVKzLLz4
LCfcpy6fMOp+jk5KwywsU3upPtjA6E3UetxPcfnnv+gghRyDAYLN2OVqZgLMEmUo
F1j1SM1QrbhHIuNcVxI9gPPMdumcNFSz/hqxrBRtA/8Z2gywczdNLjc=
-----END PRIVATE KEY-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
82:ed:bf:41:c8:80:91:9e
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
Validity
Not Before: Jan 19 19:09:06 2018 GMT
Not After : Nov 28 19:09:06 2027 GMT
Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost-ecc
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:39:21:52:b3:2c:bc:f8:2c:27:dc:a7:2e:9f:30:
ea:7e:8e:4e:4a:c3:2c:2c:53:7b:a9:3e:d8:c0:e8:
4d:d4:7a:dc:4f:71:f9:e7:bf:e8:20:85:1c:83:01:
82:cd:d8:e5:6a:66:02:cc:12:65:28:17:58:f5:48:
cd:50:ad:b8:47:22:e3:5c:57:12:3d:80:f3:cc:76:
e9:9c:34:54:b3:fe:1a:b1:ac:14:6d:03:ff:19:da:
0c:b0:73:37:4d:2e:37
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:localhost-ecc
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
33:23:0E:15:04:83:2E:3D:BF:DA:81:6D:10:38:80:C3:C2:B0:A4:74
X509v3 Authority Key Identifier:
keyid:9A:CF:CF:6E:EB:71:3D:DB:3C:F1:AE:88:6B:56:72:03:CB:08:A7:48
DirName:/C=XY/O=Python Software Foundation CA/CN=our-ca-server
serial:82:ED:BF:41:C8:80:91:9B
Authority Information Access:
CA Issuers - URI:http://testca.pythontest.net/testca/pycacert.cer
OCSP - URI:http://testca.pythontest.net/testca/ocsp/
X509v3 CRL Distribution Points:
Full Name:
URI:http://testca.pythontest.net/testca/revocation.crl
Signature Algorithm: sha1WithRSAEncryption
3b:6f:97:af:7e:5f:e0:14:34:ed:57:7e:de:ce:c4:85:1e:aa:
84:52:94:7c:e5:ce:e9:9c:88:8b:ad:b5:4d:16:ac:af:81:ea:
b8:a2:e2:50:2e:cb:e9:11:bd:1b:a6:3f:0c:a2:d7:7b:67:72:
b3:43:16:ad:c6:87:ac:6e:ac:47:78:ef:2f:8c:86:e8:9b:d1:
43:8c:c1:7a:91:30:e9:14:d6:9f:41:8b:9b:0b:24:9b:78:86:
11:8a:fc:2b:cd:c9:13:ee:90:4f:14:33:51:a3:c4:9e:d6:06:
48:f5:41:12:af:f0:f2:71:40:78:f5:96:c2:5d:cf:e1:38:ff:
bf:10:eb:74:2f:c2:23:21:3e:27:f5:f1:f2:af:2c:62:82:31:
00:c8:96:1b:c3:7e:8d:71:89:e7:40:b5:67:1a:33:fb:c0:8b:
96:0c:36:78:25:27:82:d8:27:27:52:0f:f7:69:cd:ff:2b:92:
10:d3:d2:0a:db:65:ed:af:90:eb:db:76:f3:8a:7a:13:9e:c6:
33:57:15:42:06:13:d6:54:49:fa:84:a7:0e:1d:14:72:ca:19:
8e:2b:aa:a4:02:54:3c:f6:1c:23:81:7a:59:54:b0:92:65:72:
c8:e5:ba:9f:03:4e:30:f2:4d:45:85:e3:35:a8:b1:68:58:b9:
3b:20:a3:eb
-----BEGIN CERTIFICATE-----
MIIESzCCAzOgAwIBAgIJAILtv0HIgJGeMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODAxMTkxOTA5MDZaFw0yNzExMjgx
OTA5MDZaMGMxCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj
MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xFjAUBgNVBAMMDWxv
Y2FsaG9zdC1lY2MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ5IVKzLLz4LCfcpy6f
MOp+jk5KwywsU3upPtjA6E3UetxPcfnnv+gghRyDAYLN2OVqZgLMEmUoF1j1SM1Q
rbhHIuNcVxI9gPPMdumcNFSz/hqxrBRtA/8Z2gywczdNLjejggHEMIIBwDAYBgNV
HREEETAPgg1sb2NhbGhvc3QtZWNjMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
BggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUMyMO
FQSDLj2/2oFtEDiAw8KwpHQwfQYDVR0jBHYwdIAUms/PbutxPds88a6Ia1ZyA8sI
p0ihUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcoIJAILtv0HIgJGb
MIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly90ZXN0Y2EucHl0
aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1BggrBgEFBQcwAYYpaHR0
cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2NzcC8wQwYDVR0fBDww
OjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2EvcmV2
b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQEFBQADggEBADtvl69+X+AUNO1Xft7OxIUe
qoRSlHzlzumciIuttU0WrK+B6rii4lAuy+kRvRumPwyi13tncrNDFq3Gh6xurEd4
7y+Mhuib0UOMwXqRMOkU1p9Bi5sLJJt4hhGK/CvNyRPukE8UM1GjxJ7WBkj1QRKv
8PJxQHj1lsJdz+E4/78Q63QvwiMhPif18fKvLGKCMQDIlhvDfo1xiedAtWcaM/vA
i5YMNnglJ4LYJydSD/dpzf8rkhDT0grbZe2vkOvbdvOKehOexjNXFUIGE9ZUSfqE
pw4dFHLKGY4rqqQCVDz2HCOBellUsJJlcsjlup8DTjDyTUWF4zWosWhYuTsgo+s=
-----END CERTIFICATE-----

View File

@@ -41,8 +41,6 @@ class ExceptionTests(unittest.TestCase):
self.assertEqual(buf1, buf2)
self.assertEqual(exc.__name__, excname)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def testRaising(self):
self.raise_catch(AttributeError, "AttributeError")
self.assertRaises(AttributeError, getattr, sys, "undefined_attribute")

1103
Lib/test/test_ftplib.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -599,102 +599,101 @@ class MathTests(unittest.TestCase):
self.assertTrue(math.isnan(math.frexp(NAN)[0]))
# TODO: RUSTPYTHON
# @requires_IEEE_754
# @unittest.skipIf(HAVE_DOUBLE_ROUNDING,
# "fsum is not exact on machines with double rounding")
# def testFsum(self):
# # math.fsum relies on exact rounding for correct operation.
# # There's a known problem with IA32 floating-point that causes
# # inexact rounding in some situations, and will cause the
# # math.fsum tests below to fail; see issue #2937. On non IEEE
# # 754 platforms, and on IEEE 754 platforms that exhibit the
# # problem described in issue #2937, we simply skip the whole
# # test.
@requires_IEEE_754
@unittest.skipIf(HAVE_DOUBLE_ROUNDING,
"fsum is not exact on machines with double rounding")
def testFsum(self):
# math.fsum relies on exact rounding for correct operation.
# There's a known problem with IA32 floating-point that causes
# inexact rounding in some situations, and will cause the
# math.fsum tests below to fail; see issue #2937. On non IEEE
# 754 platforms, and on IEEE 754 platforms that exhibit the
# problem described in issue #2937, we simply skip the whole
# test.
# # Python version of math.fsum, for comparison. Uses a
# # different algorithm based on frexp, ldexp and integer
# # arithmetic.
# from sys import float_info
# mant_dig = float_info.mant_dig
# etiny = float_info.min_exp - mant_dig
# Python version of math.fsum, for comparison. Uses a
# different algorithm based on frexp, ldexp and integer
# arithmetic.
from sys import float_info
mant_dig = float_info.mant_dig
etiny = float_info.min_exp - mant_dig
# def msum(iterable):
# """Full precision summation. Compute sum(iterable) without any
# intermediate accumulation of error. Based on the 'lsum' function
# at http://code.activestate.com/recipes/393090/
# """
# tmant, texp = 0, 0
# for x in iterable:
# mant, exp = math.frexp(x)
# mant, exp = int(math.ldexp(mant, mant_dig)), exp - mant_dig
# if texp > exp:
# tmant <<= texp-exp
# texp = exp
# else:
# mant <<= exp-texp
# tmant += mant
# # Round tmant * 2**texp to a float. The original recipe
# # used float(str(tmant)) * 2.0**texp for this, but that's
# # a little unsafe because str -> float conversion can't be
# # relied upon to do correct rounding on all platforms.
# tail = max(len(bin(abs(tmant)))-2 - mant_dig, etiny - texp)
# if tail > 0:
# h = 1 << (tail-1)
# tmant = tmant // (2*h) + bool(tmant & h and tmant & 3*h-1)
# texp += tail
# return math.ldexp(tmant, texp)
def msum(iterable):
"""Full precision summation. Compute sum(iterable) without any
intermediate accumulation of error. Based on the 'lsum' function
at http://code.activestate.com/recipes/393090/
"""
tmant, texp = 0, 0
for x in iterable:
mant, exp = math.frexp(x)
mant, exp = int(math.ldexp(mant, mant_dig)), exp - mant_dig
if texp > exp:
tmant <<= texp-exp
texp = exp
else:
mant <<= exp-texp
tmant += mant
# Round tmant * 2**texp to a float. The original recipe
# used float(str(tmant)) * 2.0**texp for this, but that's
# a little unsafe because str -> float conversion can't be
# relied upon to do correct rounding on all platforms.
tail = max(len(bin(abs(tmant)))-2 - mant_dig, etiny - texp)
if tail > 0:
h = 1 << (tail-1)
tmant = tmant // (2*h) + bool(tmant & h and tmant & 3*h-1)
texp += tail
return math.ldexp(tmant, texp)
# test_values = [
# ([], 0.0),
# ([0.0], 0.0),
# ([1e100, 1.0, -1e100, 1e-100, 1e50, -1.0, -1e50], 1e-100),
# ([2.0**53, -0.5, -2.0**-54], 2.0**53-1.0),
# ([2.0**53, 1.0, 2.0**-100], 2.0**53+2.0),
# ([2.0**53+10.0, 1.0, 2.0**-100], 2.0**53+12.0),
# ([2.0**53-4.0, 0.5, 2.0**-54], 2.0**53-3.0),
# ([1./n for n in range(1, 1001)],
# float.fromhex('0x1.df11f45f4e61ap+2')),
# ([(-1.)**n/n for n in range(1, 1001)],
# float.fromhex('-0x1.62a2af1bd3624p-1')),
# ([1e16, 1., 1e-16], 10000000000000002.0),
# ([1e16-2., 1.-2.**-53, -(1e16-2.), -(1.-2.**-53)], 0.0),
# # exercise code for resizing partials array
# ([2.**n - 2.**(n+50) + 2.**(n+52) for n in range(-1074, 972, 2)] +
# [-2.**1022],
# float.fromhex('0x1.5555555555555p+970')),
# ]
test_values = [
([], 0.0),
([0.0], 0.0),
([1e100, 1.0, -1e100, 1e-100, 1e50, -1.0, -1e50], 1e-100),
([2.0**53, -0.5, -2.0**-54], 2.0**53-1.0),
([2.0**53, 1.0, 2.0**-100], 2.0**53+2.0),
([2.0**53+10.0, 1.0, 2.0**-100], 2.0**53+12.0),
([2.0**53-4.0, 0.5, 2.0**-54], 2.0**53-3.0),
([1./n for n in range(1, 1001)],
float.fromhex('0x1.df11f45f4e61ap+2')),
([(-1.)**n/n for n in range(1, 1001)],
float.fromhex('-0x1.62a2af1bd3624p-1')),
([1e16, 1., 1e-16], 10000000000000002.0),
([1e16-2., 1.-2.**-53, -(1e16-2.), -(1.-2.**-53)], 0.0),
# exercise code for resizing partials array
([2.**n - 2.**(n+50) + 2.**(n+52) for n in range(-1074, 972, 2)] +
[-2.**1022],
float.fromhex('0x1.5555555555555p+970')),
]
# # Telescoping sum, with exact differences (due to Sterbenz)
# terms = [1.7**i for i in range(1001)]
# test_values.append((
# [terms[i+1] - terms[i] for i in range(1000)] + [-terms[1000]],
# -terms[0]
# ))
# Telescoping sum, with exact differences (due to Sterbenz)
terms = [1.7**i for i in range(1001)]
test_values.append((
[terms[i+1] - terms[i] for i in range(1000)] + [-terms[1000]],
-terms[0]
))
# for i, (vals, expected) in enumerate(test_values):
# try:
# actual = math.fsum(vals)
# except OverflowError:
# self.fail("test %d failed: got OverflowError, expected %r "
# "for math.fsum(%.100r)" % (i, expected, vals))
# except ValueError:
# self.fail("test %d failed: got ValueError, expected %r "
# "for math.fsum(%.100r)" % (i, expected, vals))
# self.assertEqual(actual, expected)
for i, (vals, expected) in enumerate(test_values):
try:
actual = math.fsum(vals)
except OverflowError:
self.fail("test %d failed: got OverflowError, expected %r "
"for math.fsum(%.100r)" % (i, expected, vals))
except ValueError:
self.fail("test %d failed: got ValueError, expected %r "
"for math.fsum(%.100r)" % (i, expected, vals))
self.assertEqual(actual, expected)
# from random import random, gauss, shuffle
# for j in range(1000):
# vals = [7, 1e100, -7, -1e100, -9e-20, 8e-20] * 10
# s = 0
# for i in range(200):
# v = gauss(0, random()) ** 7 - s
# s += v
# vals.append(v)
# shuffle(vals)
from random import random, gauss, shuffle
for j in range(1000):
vals = [7, 1e100, -7, -1e100, -9e-20, 8e-20] * 10
s = 0
for i in range(200):
v = gauss(0, random()) ** 7 - s
s += v
vals.append(v)
shuffle(vals)
# s = msum(vals)
# self.assertEqual(msum(vals), math.fsum(vals))
s = msum(vals)
self.assertEqual(msum(vals), math.fsum(vals))
# Python 3.9
@@ -1558,13 +1557,12 @@ class MathTests(unittest.TestCase):
# def test_nan_constant(self):
# self.assertTrue(math.isnan(math.nan))
# TODO: RUSTPYTHON
# @requires_IEEE_754
# def test_inf_constant(self):
# self.assertTrue(math.isinf(math.inf))
# self.assertGreater(math.inf, 0.0)
# self.assertEqual(math.inf, float("inf"))
# self.assertEqual(-math.inf, float("-inf"))
@requires_IEEE_754
def test_inf_constant(self):
self.assertTrue(math.isinf(math.inf))
self.assertGreater(math.inf, 0.0)
self.assertEqual(math.inf, float("inf"))
self.assertEqual(-math.inf, float("-inf"))
# RED_FLAG 16-Oct-2000 Tim
# While 2.0 is more consistent about exceptions than previous releases, it

View File

@@ -384,8 +384,6 @@ class AbstractMemoryTests:
mm.release()
m.tolist()
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_issue22668(self):
a = array.array('H', [256, 256, 256, 256])
x = memoryview(a)

View File

@@ -723,8 +723,6 @@ class UnpackIteratorTest(unittest.TestCase):
self.assertRaises(StopIteration, next, it)
self.assertRaises(StopIteration, next, it)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_half_float(self):
# Little-endian examples from:
# http://en.wikipedia.org/wiki/Half_precision_floating-point_format

View File

@@ -5,4 +5,4 @@ authors = ["RustPython Team"]
edition = "2018"
[dependencies]
num-bigint = "0.3"
num-bigint = { version = "0.3", default-features = false }

View File

@@ -5,20 +5,21 @@
//! location of the node.
pub use crate::location::Location;
use alloc::{boxed::Box, string::String, vec::Vec};
use num_bigint::BigInt;
#[allow(clippy::large_enum_variant)]
#[derive(Debug, PartialEq)]
pub enum Top {
Program(Program),
Statement(Vec<Statement>),
Expression(Expression),
pub enum Top<U = ()> {
Program(Program<U>),
Statement(Vec<Statement<U>>),
Expression(Expression<U>),
}
#[derive(Debug, PartialEq)]
/// A full python program, it's a sequence of statements.
pub struct Program {
pub statements: Suite,
pub struct Program<U = ()> {
pub statements: Suite<U>,
}
#[derive(Debug, PartialEq)]
@@ -28,17 +29,18 @@ pub struct ImportSymbol {
}
#[derive(Debug, PartialEq)]
pub struct Located<T> {
pub struct Located<T, U = ()> {
pub location: Location,
pub node: T,
pub custom: U,
}
pub type Statement = Located<StatementType>;
pub type Suite = Vec<Statement>;
pub type Statement<U = ()> = Located<StatementType<U>, U>;
pub type Suite<U = ()> = Vec<Statement<U>>;
/// Abstract syntax tree nodes for python statements.
#[derive(Debug, PartialEq)]
pub enum StatementType {
pub enum StatementType<U = ()> {
/// A [`break`](https://docs.python.org/3/reference/simple_stmts.html#the-break-statement) statement.
Break,
@@ -47,7 +49,7 @@ pub enum StatementType {
/// A [`return`](https://docs.python.org/3/reference/simple_stmts.html#the-return-statement) statement.
/// This is used to return from a function.
Return { value: Option<Expression> },
Return { value: Option<Expression<U>> },
/// An [`import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) statement.
Import { names: Vec<ImportSymbol> },
@@ -64,35 +66,35 @@ pub enum StatementType {
/// An [`assert`](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement) statement.
Assert {
test: Expression,
msg: Option<Expression>,
test: Expression<U>,
msg: Option<Expression<U>>,
},
/// A `del` statement, to delete some variables.
Delete { targets: Vec<Expression> },
Delete { targets: Vec<Expression<U>> },
/// Variable assignment. Note that we can assign to multiple targets.
Assign {
targets: Vec<Expression>,
value: Expression,
targets: Vec<Expression<U>>,
value: Expression<U>,
},
/// Augmented assignment.
AugAssign {
target: Box<Expression>,
target: Box<Expression<U>>,
op: Operator,
value: Box<Expression>,
value: Box<Expression<U>>,
},
/// A type annotated assignment.
AnnAssign {
target: Box<Expression>,
annotation: Box<Expression>,
value: Option<Expression>,
target: Box<Expression<U>>,
annotation: Box<Expression<U>>,
value: Option<Expression<U>>,
},
/// An expression used as a statement.
Expression { expression: Expression },
Expression { expression: Expression<U> },
/// The [`global`](https://docs.python.org/3/reference/simple_stmts.html#the-global-statement) statement,
/// to declare names as global variables.
@@ -104,56 +106,56 @@ pub enum StatementType {
/// An [`if`](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement) statement.
If {
test: Expression,
body: Suite,
orelse: Option<Suite>,
test: Expression<U>,
body: Suite<U>,
orelse: Option<Suite<U>>,
},
/// A [`while`](https://docs.python.org/3/reference/compound_stmts.html#the-while-statement) statement.
While {
test: Expression,
body: Suite,
orelse: Option<Suite>,
test: Expression<U>,
body: Suite<U>,
orelse: Option<Suite<U>>,
},
/// The [`with`](https://docs.python.org/3/reference/compound_stmts.html#the-with-statement) statement.
With {
is_async: bool,
items: Vec<WithItem>,
body: Suite,
items: Vec<WithItem<U>>,
body: Suite<U>,
},
/// A [`for`](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement) statement.
/// Contains the body of the loop, and the `else` clause.
For {
is_async: bool,
target: Box<Expression>,
iter: Box<Expression>,
body: Suite,
orelse: Option<Suite>,
target: Box<Expression<U>>,
iter: Box<Expression<U>>,
body: Suite<U>,
orelse: Option<Suite<U>>,
},
/// A `raise` statement.
Raise {
exception: Option<Expression>,
cause: Option<Expression>,
exception: Option<Expression<U>>,
cause: Option<Expression<U>>,
},
/// A [`try`](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement) statement.
Try {
body: Suite,
handlers: Vec<ExceptHandler>,
orelse: Option<Suite>,
finalbody: Option<Suite>,
body: Suite<U>,
handlers: Vec<ExceptHandler<U>>,
orelse: Option<Suite<U>>,
finalbody: Option<Suite<U>>,
},
/// A [class definition](https://docs.python.org/3/reference/compound_stmts.html#class-definitions).
ClassDef {
name: String,
body: Suite,
bases: Vec<Expression>,
keywords: Vec<Keyword>,
decorator_list: Vec<Expression>,
body: Suite<U>,
bases: Vec<Expression<U>>,
keywords: Vec<Keyword<U>>,
decorator_list: Vec<Expression<U>>,
},
/// A [function definition](https://docs.python.org/3/reference/compound_stmts.html#function-definitions).
@@ -162,82 +164,82 @@ pub enum StatementType {
FunctionDef {
is_async: bool,
name: String,
args: Box<Parameters>,
body: Suite,
decorator_list: Vec<Expression>,
returns: Option<Expression>,
args: Box<Parameters<U>>,
body: Suite<U>,
decorator_list: Vec<Expression<U>>,
returns: Option<Expression<U>>,
},
}
#[derive(Debug, PartialEq)]
pub struct WithItem {
pub context_expr: Expression,
pub optional_vars: Option<Expression>,
pub struct WithItem<U = ()> {
pub context_expr: Expression<U>,
pub optional_vars: Option<Expression<U>>,
}
/// An expression at a given location in the sourcecode.
pub type Expression = Located<ExpressionType>;
pub type Expression<U = ()> = Located<ExpressionType<U>, U>;
/// A certain type of expression.
#[derive(Debug, PartialEq)]
pub enum ExpressionType {
pub enum ExpressionType<U = ()> {
BoolOp {
op: BooleanOperator,
values: Vec<Expression>,
values: Vec<Expression<U>>,
},
/// A binary operation on two operands.
Binop {
a: Box<Expression>,
a: Box<Expression<U>>,
op: Operator,
b: Box<Expression>,
b: Box<Expression<U>>,
},
/// Subscript operation.
Subscript {
a: Box<Expression>,
b: Box<Expression>,
a: Box<Expression<U>>,
b: Box<Expression<U>>,
},
/// An unary operation.
Unop {
op: UnaryOperator,
a: Box<Expression>,
a: Box<Expression<U>>,
},
/// An await expression.
Await {
value: Box<Expression>,
value: Box<Expression<U>>,
},
/// A yield expression.
Yield {
value: Option<Box<Expression>>,
value: Option<Box<Expression<U>>>,
},
// A yield from expression.
YieldFrom {
value: Box<Expression>,
value: Box<Expression<U>>,
},
/// A chained comparison. Note that in python you can use
/// `1 < a < 10` for example.
Compare {
vals: Vec<Expression>,
vals: Vec<Expression<U>>,
ops: Vec<Comparison>,
},
/// Attribute access in the form of `value.name`.
Attribute {
value: Box<Expression>,
value: Box<Expression<U>>,
name: String,
},
/// A call expression.
Call {
function: Box<Expression>,
args: Vec<Expression>,
keywords: Vec<Keyword>,
function: Box<Expression<U>>,
args: Vec<Expression<U>>,
keywords: Vec<Keyword<U>>,
},
/// A numeric literal.
@@ -247,43 +249,43 @@ pub enum ExpressionType {
/// A `list` literal value.
List {
elements: Vec<Expression>,
elements: Vec<Expression<U>>,
},
/// A `tuple` literal value.
Tuple {
elements: Vec<Expression>,
elements: Vec<Expression<U>>,
},
/// A `dict` literal value.
/// For example: `{2: 'two', 3: 'three'}`
Dict {
elements: Vec<(Option<Expression>, Expression)>,
elements: Vec<(Option<Expression<U>>, Expression<U>)>,
},
/// A `set` literal.
Set {
elements: Vec<Expression>,
elements: Vec<Expression<U>>,
},
Comprehension {
kind: Box<ComprehensionKind>,
generators: Vec<Comprehension>,
kind: Box<ComprehensionKind<U>>,
generators: Vec<Comprehension<U>>,
},
/// A starred expression.
Starred {
value: Box<Expression>,
value: Box<Expression<U>>,
},
/// A slice expression.
Slice {
elements: Vec<Expression>,
elements: Vec<Expression<U>>,
},
/// A string literal.
String {
value: StringGroup,
value: StringGroup<U>,
},
/// A bytes literal.
@@ -298,21 +300,21 @@ pub enum ExpressionType {
/// A `lambda` function expression.
Lambda {
args: Box<Parameters>,
body: Box<Expression>,
args: Box<Parameters<U>>,
body: Box<Expression<U>>,
},
/// An if-expression.
IfExpression {
test: Box<Expression>,
body: Box<Expression>,
orelse: Box<Expression>,
test: Box<Expression<U>>,
body: Box<Expression<U>>,
orelse: Box<Expression<U>>,
},
// A named expression
NamedExpression {
left: Box<Expression>,
right: Box<Expression>,
left: Box<Expression<U>>,
right: Box<Expression<U>>,
},
/// The literal 'True'.
@@ -328,7 +330,7 @@ pub enum ExpressionType {
Ellipsis,
}
impl Expression {
impl<U> Expression<U> {
/// Returns a short name for the node suitable for use in error messages.
pub fn name(&self) -> &'static str {
use self::ExpressionType::*;
@@ -380,61 +382,70 @@ impl Expression {
/// In cpython this is called arguments, but we choose parameters to
/// distinguish between function parameters and actual call arguments.
#[derive(Debug, PartialEq, Default)]
pub struct Parameters {
pub struct Parameters<U = ()> {
pub posonlyargs_count: usize,
pub args: Vec<Parameter>,
pub kwonlyargs: Vec<Parameter>,
pub vararg: Varargs, // Optionally we handle optionally named '*args' or '*'
pub kwarg: Varargs,
pub defaults: Vec<Expression>,
pub kw_defaults: Vec<Option<Expression>>,
pub args: Vec<Parameter<U>>,
pub kwonlyargs: Vec<Parameter<U>>,
pub vararg: Varargs<U>, // Optionally we handle optionally named '*args' or '*'
pub kwarg: Varargs<U>,
pub defaults: Vec<Expression<U>>,
pub kw_defaults: Vec<Option<Expression<U>>>,
}
/// A single formal parameter to a function.
#[derive(Debug, PartialEq, Default)]
pub struct Parameter {
pub struct Parameter<U = ()> {
pub location: Location,
pub arg: String,
pub annotation: Option<Box<Expression>>,
pub annotation: Option<Box<Expression<U>>>,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, PartialEq)]
pub enum ComprehensionKind {
GeneratorExpression { element: Expression },
List { element: Expression },
Set { element: Expression },
Dict { key: Expression, value: Expression },
pub enum ComprehensionKind<U = ()> {
GeneratorExpression {
element: Expression<U>,
},
List {
element: Expression<U>,
},
Set {
element: Expression<U>,
},
Dict {
key: Expression<U>,
value: Expression<U>,
},
}
/// A list/set/dict/generator compression.
#[derive(Debug, PartialEq)]
pub struct Comprehension {
pub struct Comprehension<U = ()> {
pub location: Location,
pub target: Expression,
pub iter: Expression,
pub ifs: Vec<Expression>,
pub target: Expression<U>,
pub iter: Expression<U>,
pub ifs: Vec<Expression<U>>,
pub is_async: bool,
}
#[derive(Debug, PartialEq)]
pub struct ArgumentList {
pub args: Vec<Expression>,
pub keywords: Vec<Keyword>,
pub struct ArgumentList<U = ()> {
pub args: Vec<Expression<U>>,
pub keywords: Vec<Keyword<U>>,
}
#[derive(Debug, PartialEq)]
pub struct Keyword {
pub struct Keyword<U = ()> {
pub name: Option<String>,
pub value: Expression,
pub value: Expression<U>,
}
#[derive(Debug, PartialEq)]
pub struct ExceptHandler {
pub struct ExceptHandler<U = ()> {
pub location: Location,
pub typ: Option<Expression>,
pub typ: Option<Expression<U>>,
pub name: Option<String>,
pub body: Suite,
pub body: Suite<U>,
}
/// An operator for a binary operation (an operation with two operands).
@@ -506,35 +517,35 @@ pub enum ConversionFlag {
}
#[derive(Debug, PartialEq)]
pub enum StringGroup {
pub enum StringGroup<U = ()> {
Constant {
value: String,
},
FormattedValue {
value: Box<Expression>,
value: Box<Expression<U>>,
conversion: Option<ConversionFlag>,
spec: Option<Box<StringGroup>>,
spec: Option<Box<StringGroup<U>>>,
},
Joined {
values: Vec<StringGroup>,
values: Vec<StringGroup<U>>,
},
}
#[derive(Debug, PartialEq)]
pub enum Varargs {
pub enum Varargs<U = ()> {
None,
Unnamed,
Named(Parameter),
Named(Parameter<U>),
}
impl Default for Varargs {
fn default() -> Varargs {
impl<U> Default for Varargs<U> {
fn default() -> Varargs<U> {
Varargs::None
}
}
impl From<Option<Option<Parameter>>> for Varargs {
fn from(opt: Option<Option<Parameter>>) -> Varargs {
impl<U> From<Option<Option<Parameter<U>>>> for Varargs<U> {
fn from(opt: Option<Option<Parameter<U>>>) -> Varargs<U> {
match opt {
Some(inner_opt) => match inner_opt {
Some(param) => Varargs::Named(param),

View File

@@ -1,3 +1,7 @@
#![no_std]
extern crate alloc;
mod ast;
mod location;

View File

@@ -1,6 +1,6 @@
//! Datatypes to support source location information.
use std::fmt;
use core::fmt;
/// A location somewhere in the sourcecode.
#[derive(Clone, Copy, Debug, Default, PartialEq)]

View File

@@ -7,13 +7,16 @@ edition = "2018"
repository = "https://github.com/RustPython/RustPython"
license = "MIT"
[features]
std = ["bstr/std", "itertools/use_std", "lz4_flex/std"]
default = ["std"]
[dependencies]
bincode = "1.1"
bitflags = "1.1"
lz-fear = "0.1"
num-bigint = { version = "0.3", features = ["serde"] }
num-complex = { version = "0.3", features = ["serde"] }
lz4_flex = { version = "0.7", default-features = false, features = ["safe-decode", "safe-encode"] }
num-bigint = { version = "0.3", default-features = false, features = ["serde"] }
num-complex = { version = "0.3", default-features = false, features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
itertools = "0.9"
bstr = "0.2"
itertools = { version = "0.9", default-features = false }
bstr = { version = "0.2", default-features = false }

View File

@@ -1,948 +0,0 @@
//! Implement python as a virtual machine with bytecodes. This module
//! implements bytecode structure.
use bitflags::bitflags;
use bstr::ByteSlice;
use itertools::Itertools;
use num_bigint::BigInt;
use num_complex::Complex64;
use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
use std::fmt;
/// Sourcecode location.
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Location {
row: usize,
column: usize,
}
impl Location {
pub fn new(row: usize, column: usize) -> Self {
Location { row, column }
}
pub fn row(&self) -> usize {
self.row
}
pub fn column(&self) -> usize {
self.column
}
}
pub trait Constant: Sized {
type Name: AsRef<str>;
fn borrow_constant(&self) -> BorrowedConstant<Self>;
fn into_data(self) -> ConstantData {
self.borrow_constant().into_data()
}
fn map_constant<Bag: ConstantBag>(self, bag: &Bag) -> Bag::Constant {
bag.make_constant(self.into_data())
}
}
impl Constant for ConstantData {
type Name = String;
fn borrow_constant(&self) -> BorrowedConstant<Self> {
use BorrowedConstant::*;
match self {
ConstantData::Integer { value } => Integer { value },
ConstantData::Float { value } => Float { value: *value },
ConstantData::Complex { value } => Complex { value: *value },
ConstantData::Boolean { value } => Boolean { value: *value },
ConstantData::Str { value } => Str { value },
ConstantData::Bytes { value } => Bytes { value },
ConstantData::Code { code } => Code { code },
ConstantData::Tuple { elements } => Tuple {
elements: Box::new(elements.iter().map(|e| e.borrow_constant())),
},
ConstantData::None => None,
ConstantData::Ellipsis => Ellipsis,
}
}
fn into_data(self) -> ConstantData {
self
}
}
pub trait ConstantBag: Sized {
type Constant: Constant;
fn make_constant(&self, constant: ConstantData) -> Self::Constant;
fn make_constant_borrowed<C: Constant>(&self, constant: BorrowedConstant<C>) -> Self::Constant {
self.make_constant(constant.into_data())
}
fn make_name(&self, name: String) -> <Self::Constant as Constant>::Name;
fn make_name_ref(&self, name: &str) -> <Self::Constant as Constant>::Name {
self.make_name(name.to_owned())
}
}
#[derive(Clone)]
pub struct BasicBag;
impl ConstantBag for BasicBag {
type Constant = ConstantData;
fn make_constant(&self, constant: ConstantData) -> Self::Constant {
constant
}
fn make_name(&self, name: String) -> <Self::Constant as Constant>::Name {
name
}
}
/// Primary container of a single code object. Each python function has
/// a codeobject. Also a module has a codeobject.
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct CodeObject<C: Constant = ConstantData> {
pub instructions: Box<[Instruction]>,
pub locations: Box<[Location]>,
pub flags: CodeFlags,
pub posonlyarg_count: usize, // Number of positional-only arguments
pub arg_count: usize,
pub kwonlyarg_count: usize,
pub source_path: String,
pub first_line_number: usize,
pub obj_name: String, // Name of the object that created this code object
pub cell2arg: Option<Box<[isize]>>,
pub constants: Box<[C]>,
#[serde(bound(
deserialize = "C::Name: serde::Deserialize<'de>",
serialize = "C::Name: serde::Serialize"
))]
pub names: Box<[C::Name]>,
pub varnames: Box<[C::Name]>,
pub cellvars: Box<[C::Name]>,
pub freevars: Box<[C::Name]>,
}
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct CodeFlags: u16 {
const HAS_DEFAULTS = 0x01;
const HAS_KW_ONLY_DEFAULTS = 0x02;
const HAS_ANNOTATIONS = 0x04;
const NEW_LOCALS = 0x08;
const IS_GENERATOR = 0x10;
const IS_COROUTINE = 0x20;
const HAS_VARARGS = 0x40;
const HAS_VARKEYWORDS = 0x80;
const IS_OPTIMIZED = 0x0100;
}
}
impl CodeFlags {
pub const NAME_MAPPING: &'static [(&'static str, CodeFlags)] = &[
("GENERATOR", CodeFlags::IS_GENERATOR),
("COROUTINE", CodeFlags::IS_COROUTINE),
(
"ASYNC_GENERATOR",
Self::from_bits_truncate(Self::IS_GENERATOR.bits | Self::IS_COROUTINE.bits),
),
("VARARGS", CodeFlags::HAS_VARARGS),
("VARKEYWORDS", CodeFlags::HAS_VARKEYWORDS),
];
}
#[derive(Serialize, Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[repr(transparent)]
// XXX: if you add a new instruction that stores a Label, make sure to add it in
// compile::CodeInfo::finalize_code and CodeObject::label_targets
pub struct Label(pub usize);
impl fmt::Display for Label {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
/// Transforms a value prior to formatting it.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ConversionFlag {
/// Converts by calling `str(<value>)`.
Str,
/// Converts by calling `ascii(<value>)`.
Ascii,
/// Converts by calling `repr(<value>)`.
Repr,
}
pub type NameIdx = usize;
/// A Single bytecode instruction.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Instruction {
Import {
name_idx: Option<NameIdx>,
symbols_idx: Vec<NameIdx>,
level: usize,
},
ImportStar,
ImportFrom {
idx: NameIdx,
},
LoadFast(NameIdx),
LoadNameAny(NameIdx),
LoadGlobal(NameIdx),
LoadDeref(NameIdx),
LoadClassDeref(NameIdx),
StoreFast(NameIdx),
StoreLocal(NameIdx),
StoreGlobal(NameIdx),
StoreDeref(NameIdx),
DeleteFast(NameIdx),
DeleteLocal(NameIdx),
DeleteGlobal(NameIdx),
DeleteDeref(NameIdx),
LoadClosure(NameIdx),
Subscript,
StoreSubscript,
DeleteSubscript,
StoreAttr {
idx: NameIdx,
},
DeleteAttr {
idx: NameIdx,
},
LoadConst {
/// index into constants vec
idx: usize,
},
UnaryOperation {
op: UnaryOperator,
},
BinaryOperation {
op: BinaryOperator,
inplace: bool,
},
LoadAttr {
idx: NameIdx,
},
CompareOperation {
op: ComparisonOperator,
},
Pop,
Rotate {
amount: usize,
},
Duplicate,
GetIter,
Continue,
Break,
Jump {
target: Label,
},
/// Pop the top of the stack, and jump if this value is true.
JumpIfTrue {
target: Label,
},
/// Pop the top of the stack, and jump if this value is false.
JumpIfFalse {
target: Label,
},
/// Peek at the top of the stack, and jump if this value is true.
/// Otherwise, pop top of stack.
JumpIfTrueOrPop {
target: Label,
},
/// Peek at the top of the stack, and jump if this value is false.
/// Otherwise, pop top of stack.
JumpIfFalseOrPop {
target: Label,
},
MakeFunction,
CallFunction {
typ: CallType,
},
ForIter {
target: Label,
},
ReturnValue,
YieldValue,
YieldFrom,
SetupAnnotation,
SetupLoop {
start: Label,
end: Label,
},
/// Setup a finally handler, which will be called whenever one of this events occurs:
/// - the block is popped
/// - the function returns
/// - an exception is returned
SetupFinally {
handler: Label,
},
/// Enter a finally block, without returning, excepting, just because we are there.
EnterFinally,
/// Marker bytecode for the end of a finally sequence.
/// When this bytecode is executed, the eval loop does one of those things:
/// - Continue at a certain bytecode position
/// - Propagate the exception
/// - Return from a function
/// - Do nothing at all, just continue
EndFinally,
SetupExcept {
handler: Label,
},
SetupWith {
end: Label,
},
WithCleanupStart,
WithCleanupFinish,
PopBlock,
Raise {
argc: usize,
},
BuildString {
size: usize,
},
BuildTuple {
size: usize,
unpack: bool,
},
BuildList {
size: usize,
unpack: bool,
},
BuildSet {
size: usize,
unpack: bool,
},
BuildMap {
size: usize,
unpack: bool,
for_call: bool,
},
BuildSlice {
size: usize,
},
ListAppend {
i: usize,
},
SetAdd {
i: usize,
},
MapAdd {
i: usize,
},
PrintExpr,
LoadBuildClass,
UnpackSequence {
size: usize,
},
UnpackEx {
before: usize,
after: usize,
},
FormatValue {
conversion: Option<ConversionFlag>,
},
PopException,
Reverse {
amount: usize,
},
GetAwaitable,
BeforeAsyncWith,
SetupAsyncWith {
end: Label,
},
GetAIter,
GetANext,
/// Reverse order evaluation in MapAdd
/// required to support named expressions of Python 3.8 in dict comprehension
/// today (including Py3.9) only required in dict comprehension.
MapAddRev {
i: usize,
},
}
use self::Instruction::*;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CallType {
Positional(usize),
Keyword(usize),
Ex(bool),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ConstantData {
Integer { value: BigInt },
Float { value: f64 },
Complex { value: Complex64 },
Boolean { value: bool },
Str { value: String },
Bytes { value: Vec<u8> },
Code { code: Box<CodeObject> },
Tuple { elements: Vec<ConstantData> },
None,
Ellipsis,
}
pub enum BorrowedConstant<'a, C: Constant> {
Integer { value: &'a BigInt },
Float { value: f64 },
Complex { value: Complex64 },
Boolean { value: bool },
Str { value: &'a str },
Bytes { value: &'a [u8] },
Code { code: &'a CodeObject<C> },
Tuple { elements: BorrowedTupleIter<'a, C> },
None,
Ellipsis,
}
type BorrowedTupleIter<'a, C> = Box<dyn Iterator<Item = BorrowedConstant<'a, C>> + 'a>;
impl<C: Constant> BorrowedConstant<'_, C> {
// takes `self` because we need to consume the iterator
pub fn fmt_display(self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BorrowedConstant::Integer { value } => write!(f, "{}", value),
BorrowedConstant::Float { value } => write!(f, "{}", value),
BorrowedConstant::Complex { value } => write!(f, "{}", value),
BorrowedConstant::Boolean { value } => {
write!(f, "{}", if value { "True" } else { "False" })
}
BorrowedConstant::Str { value } => write!(f, "{:?}", value),
BorrowedConstant::Bytes { value } => write!(f, "b{:?}", value.as_bstr()),
BorrowedConstant::Code { code } => write!(f, "{:?}", code),
BorrowedConstant::Tuple { elements } => {
write!(f, "(")?;
let mut first = true;
for c in elements {
if first {
first = false
} else {
write!(f, ", ")?;
}
c.fmt_display(f)?;
}
write!(f, ")")
}
BorrowedConstant::None => write!(f, "None"),
BorrowedConstant::Ellipsis => write!(f, "..."),
}
}
pub fn into_data(self) -> ConstantData {
use ConstantData::*;
match self {
BorrowedConstant::Integer { value } => Integer {
value: value.clone(),
},
BorrowedConstant::Float { value } => Float { value },
BorrowedConstant::Complex { value } => Complex { value },
BorrowedConstant::Boolean { value } => Boolean { value },
BorrowedConstant::Str { value } => Str {
value: value.to_owned(),
},
BorrowedConstant::Bytes { value } => Bytes {
value: value.to_owned(),
},
BorrowedConstant::Code { code } => Code {
code: Box::new(code.map_clone_bag(&BasicBag)),
},
BorrowedConstant::Tuple { elements } => Tuple {
elements: elements.map(BorrowedConstant::into_data).collect(),
},
BorrowedConstant::None => None,
BorrowedConstant::Ellipsis => Ellipsis,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ComparisonOperator {
Greater,
GreaterOrEqual,
Less,
LessOrEqual,
Equal,
NotEqual,
In,
NotIn,
Is,
IsNot,
ExceptionMatch,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum BinaryOperator {
Power,
Multiply,
MatrixMultiply,
Divide,
FloorDivide,
Modulo,
Add,
Subtract,
Lshift,
Rshift,
And,
Xor,
Or,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum UnaryOperator {
Not,
Invert,
Minus,
Plus,
}
/*
Maintain a stack of blocks on the VM.
pub enum BlockType {
Loop,
Except,
}
*/
pub struct Arguments<'a, N: AsRef<str>> {
pub posonlyargs: &'a [N],
pub args: &'a [N],
pub vararg: Option<&'a N>,
pub kwonlyargs: &'a [N],
pub varkwarg: Option<&'a N>,
}
impl<N: AsRef<str>> fmt::Debug for Arguments<'_, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
macro_rules! fmt_slice {
($x:expr) => {
format_args!("[{}]", $x.iter().map(AsRef::as_ref).format(", "))
};
}
f.debug_struct("Arguments")
.field("posonlyargs", &fmt_slice!(self.posonlyargs))
.field("args", &fmt_slice!(self.posonlyargs))
.field("vararg", &self.vararg.map(N::as_ref))
.field("kwonlyargs", &fmt_slice!(self.kwonlyargs))
.field("varkwarg", &self.varkwarg.map(N::as_ref))
.finish()
}
}
impl<C: Constant> CodeObject<C> {
pub fn new(
flags: CodeFlags,
posonlyarg_count: usize,
arg_count: usize,
kwonlyarg_count: usize,
source_path: String,
first_line_number: usize,
obj_name: String,
) -> Self {
CodeObject {
instructions: Box::new([]),
locations: Box::new([]),
flags,
posonlyarg_count,
arg_count,
kwonlyarg_count,
source_path,
first_line_number,
obj_name,
cell2arg: None,
constants: Box::new([]),
names: Box::new([]),
varnames: Box::new([]),
cellvars: Box::new([]),
freevars: Box::new([]),
}
}
// like inspect.getargs
pub fn arg_names(&self) -> Arguments<C::Name> {
let nargs = self.arg_count;
let nkwargs = self.kwonlyarg_count;
let mut varargspos = nargs + nkwargs;
let posonlyargs = &self.varnames[..self.posonlyarg_count];
let args = &self.varnames[..nargs];
let kwonlyargs = &self.varnames[nargs..varargspos];
let vararg = if self.flags.contains(CodeFlags::HAS_VARARGS) {
let vararg = &self.varnames[varargspos];
varargspos += 1;
Some(vararg)
} else {
None
};
let varkwarg = if self.flags.contains(CodeFlags::HAS_VARKEYWORDS) {
Some(&self.varnames[varargspos])
} else {
None
};
Arguments {
posonlyargs,
args,
vararg,
kwonlyargs,
varkwarg,
}
}
pub fn label_targets(&self) -> BTreeSet<Label> {
let mut label_targets = BTreeSet::new();
for instruction in &*self.instructions {
match instruction {
Jump { target: l }
| JumpIfTrue { target: l }
| JumpIfFalse { target: l }
| JumpIfTrueOrPop { target: l }
| JumpIfFalseOrPop { target: l }
| ForIter { target: l }
| SetupFinally { handler: l }
| SetupExcept { handler: l }
| SetupWith { end: l }
| SetupAsyncWith { end: l } => {
label_targets.insert(*l);
}
SetupLoop { start, end } => {
label_targets.insert(*start);
label_targets.insert(*end);
}
#[rustfmt::skip]
Import { .. } | ImportStar | ImportFrom { .. } | LoadFast(_) | LoadNameAny(_)
| LoadGlobal(_) | LoadDeref(_) | LoadClassDeref(_) | StoreFast(_) | StoreLocal(_)
| StoreGlobal(_) | StoreDeref(_) | DeleteFast(_) | DeleteLocal(_) | DeleteGlobal(_)
| DeleteDeref(_) | LoadClosure(_) | Subscript | StoreSubscript | DeleteSubscript
| StoreAttr { .. } | DeleteAttr { .. } | LoadConst { .. } | UnaryOperation { .. }
| BinaryOperation { .. } | LoadAttr { .. } | CompareOperation { .. } | Pop
| Rotate { .. } | Duplicate | GetIter | Continue | Break | MakeFunction
| CallFunction { .. } | ReturnValue | YieldValue | YieldFrom | SetupAnnotation
| EnterFinally | EndFinally | WithCleanupStart | WithCleanupFinish | PopBlock
| Raise { .. } | BuildString { .. } | BuildTuple { .. } | BuildList { .. }
| BuildSet { .. } | BuildMap { .. } | BuildSlice { .. } | ListAppend { .. }
| SetAdd { .. } | MapAdd { .. } | PrintExpr | LoadBuildClass | UnpackSequence { .. }
| UnpackEx { .. } | FormatValue { .. } | PopException | Reverse { .. }
| GetAwaitable | BeforeAsyncWith | GetAIter | GetANext | MapAddRev { .. } => {}
}
}
label_targets
}
fn display_inner(
&self,
f: &mut fmt::Formatter,
expand_codeobjects: bool,
level: usize,
) -> fmt::Result {
let label_targets = self.label_targets();
for (offset, instruction) in self.instructions.iter().enumerate() {
let arrow = if label_targets.contains(&Label(offset)) {
">>"
} else {
" "
};
for _ in 0..level {
write!(f, " ")?;
}
write!(f, "{} {:5} ", arrow, offset)?;
instruction.fmt_dis(
f,
&self.constants,
&self.names,
&self.varnames,
&self.cellvars,
&self.freevars,
expand_codeobjects,
level,
)?;
}
Ok(())
}
pub fn display_expand_codeobjects<'a>(&'a self) -> impl fmt::Display + 'a {
struct Display<'a, C: Constant>(&'a CodeObject<C>);
impl<C: Constant> fmt::Display for Display<'_, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.display_inner(f, true, 1)
}
}
Display(self)
}
pub fn map_bag<Bag: ConstantBag>(self, bag: &Bag) -> CodeObject<Bag::Constant> {
let map_names = |names: Box<[C::Name]>| {
names
.into_vec()
.into_iter()
.map(|x| bag.make_name_ref(x.as_ref()))
.collect::<Box<[_]>>()
};
CodeObject {
constants: self
.constants
.into_vec()
.into_iter()
.map(|x| x.map_constant(bag))
.collect(),
names: map_names(self.names),
varnames: map_names(self.varnames),
cellvars: map_names(self.cellvars),
freevars: map_names(self.freevars),
instructions: self.instructions,
locations: self.locations,
flags: self.flags,
posonlyarg_count: self.posonlyarg_count,
arg_count: self.arg_count,
kwonlyarg_count: self.kwonlyarg_count,
source_path: self.source_path,
first_line_number: self.first_line_number,
obj_name: self.obj_name,
cell2arg: self.cell2arg,
}
}
pub fn map_clone_bag<Bag: ConstantBag>(&self, bag: &Bag) -> CodeObject<Bag::Constant> {
let map_names = |names: &[C::Name]| {
names
.iter()
.map(|x| bag.make_name_ref(x.as_ref()))
.collect()
};
CodeObject {
constants: self
.constants
.iter()
.map(|x| bag.make_constant_borrowed(x.borrow_constant()))
.collect(),
names: map_names(&self.names),
varnames: map_names(&self.varnames),
cellvars: map_names(&self.cellvars),
freevars: map_names(&self.freevars),
instructions: self.instructions.clone(),
locations: self.locations.clone(),
flags: self.flags,
posonlyarg_count: self.posonlyarg_count,
arg_count: self.arg_count,
kwonlyarg_count: self.kwonlyarg_count,
source_path: self.source_path.clone(),
first_line_number: self.first_line_number,
obj_name: self.obj_name.clone(),
cell2arg: self.cell2arg.clone(),
}
}
}
impl CodeObject<ConstantData> {
/// Load a code object from bytes
pub fn from_bytes(data: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
let reader = lz_fear::framed::LZ4FrameReader::new(data)?;
Ok(bincode::deserialize_from(reader.into_read())?)
}
/// Serialize this bytecode to bytes.
pub fn to_bytes(&self) -> Vec<u8> {
let data = bincode::serialize(&self).expect("CodeObject is not serializable");
let mut out = Vec::new();
lz_fear::framed::CompressionSettings::default()
.compress_with_size_unchecked(data.as_slice(), &mut out, data.len() as u64)
.unwrap();
out
}
}
impl<C: Constant> fmt::Display for CodeObject<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.display_inner(f, false, 1)?;
for constant in &*self.constants {
if let BorrowedConstant::Code { code } = constant.borrow_constant() {
write!(f, "\nDisassembly of {:?}\n", code)?;
code.fmt(f)?;
}
}
Ok(())
}
}
impl Instruction {
#[allow(clippy::too_many_arguments)]
fn fmt_dis<C: Constant>(
&self,
f: &mut fmt::Formatter,
constants: &[C],
names: &[C::Name],
varnames: &[C::Name],
cellvars: &[C::Name],
freevars: &[C::Name],
expand_codeobjects: bool,
level: usize,
) -> fmt::Result {
macro_rules! w {
($variant:ident) => {
writeln!(f, stringify!($variant))
};
($variant:ident, $var:expr) => {
writeln!(f, "{:20} ({})", stringify!($variant), $var)
};
($variant:ident, $var1:expr, $var2:expr) => {
writeln!(f, "{:20} ({}, {})", stringify!($variant), $var1, $var2)
};
($variant:ident, $var1:expr, $var2:expr, $var3:expr) => {
writeln!(
f,
"{:20} ({}, {}, {})",
stringify!($variant),
$var1,
$var2,
$var3
)
};
}
let cellname = |i: usize| {
cellvars
.get(i)
.unwrap_or_else(|| &freevars[i - cellvars.len()])
.as_ref()
};
match self {
Import {
name_idx,
symbols_idx,
level,
} => w!(
Import,
format!("{:?}", name_idx.map(|idx| names[idx].as_ref())),
format!(
"({:?})",
symbols_idx
.iter()
.map(|&idx| names[idx].as_ref())
.format(", ")
),
level
),
ImportStar => w!(ImportStar),
ImportFrom { idx } => w!(ImportFrom, names[*idx].as_ref()),
LoadFast(idx) => w!(LoadFast, *idx, varnames[*idx].as_ref()),
LoadNameAny(idx) => w!(LoadNameAny, *idx, names[*idx].as_ref()),
LoadGlobal(idx) => w!(LoadGlobal, *idx, names[*idx].as_ref()),
LoadDeref(idx) => w!(LoadDeref, *idx, cellname(*idx)),
LoadClassDeref(idx) => w!(LoadClassDeref, *idx, cellname(*idx)),
StoreFast(idx) => w!(StoreFast, *idx, varnames[*idx].as_ref()),
StoreLocal(idx) => w!(StoreLocal, *idx, names[*idx].as_ref()),
StoreGlobal(idx) => w!(StoreGlobal, *idx, names[*idx].as_ref()),
StoreDeref(idx) => w!(StoreDeref, *idx, cellname(*idx)),
DeleteFast(idx) => w!(DeleteFast, *idx, varnames[*idx].as_ref()),
DeleteLocal(idx) => w!(DeleteLocal, *idx, names[*idx].as_ref()),
DeleteGlobal(idx) => w!(DeleteGlobal, *idx, names[*idx].as_ref()),
DeleteDeref(idx) => w!(DeleteDeref, *idx, cellname(*idx)),
LoadClosure(i) => w!(LoadClosure, *i, cellname(*i)),
Subscript => w!(Subscript),
StoreSubscript => w!(StoreSubscript),
DeleteSubscript => w!(DeleteSubscript),
StoreAttr { idx } => w!(StoreAttr, names[*idx].as_ref()),
DeleteAttr { idx } => w!(DeleteAttr, names[*idx].as_ref()),
LoadConst { idx } => {
let value = &constants[*idx];
match value.borrow_constant() {
BorrowedConstant::Code { code } if expand_codeobjects => {
writeln!(f, "{:20} ({:?}):", "LoadConst", code)?;
code.display_inner(f, true, level + 1)?;
Ok(())
}
c => {
write!(f, "{:20} (", "LoadConst")?;
c.fmt_display(f)?;
writeln!(f, ")")
}
}
}
UnaryOperation { op } => w!(UnaryOperation, format!("{:?}", op)),
BinaryOperation { op, inplace } => w!(BinaryOperation, format!("{:?}", op), inplace),
LoadAttr { idx } => w!(LoadAttr, names[*idx].as_ref()),
CompareOperation { op } => w!(CompareOperation, format!("{:?}", op)),
Pop => w!(Pop),
Rotate { amount } => w!(Rotate, amount),
Duplicate => w!(Duplicate),
GetIter => w!(GetIter),
Continue => w!(Continue),
Break => w!(Break),
Jump { target } => w!(Jump, target),
JumpIfTrue { target } => w!(JumpIfTrue, target),
JumpIfFalse { target } => w!(JumpIfFalse, target),
JumpIfTrueOrPop { target } => w!(JumpIfTrueOrPop, target),
JumpIfFalseOrPop { target } => w!(JumpIfFalseOrPop, target),
MakeFunction => w!(MakeFunction),
CallFunction { typ } => w!(CallFunction, format!("{:?}", typ)),
ForIter { target } => w!(ForIter, target),
ReturnValue => w!(ReturnValue),
YieldValue => w!(YieldValue),
YieldFrom => w!(YieldFrom),
SetupAnnotation => w!(SetupAnnotation),
SetupLoop { start, end } => w!(SetupLoop, start, end),
SetupExcept { handler } => w!(SetupExcept, handler),
SetupFinally { handler } => w!(SetupFinally, handler),
EnterFinally => w!(EnterFinally),
EndFinally => w!(EndFinally),
SetupWith { end } => w!(SetupWith, end),
WithCleanupStart => w!(WithCleanupStart),
WithCleanupFinish => w!(WithCleanupFinish),
BeforeAsyncWith => w!(BeforeAsyncWith),
SetupAsyncWith { end } => w!(SetupAsyncWith, end),
PopBlock => w!(PopBlock),
Raise { argc } => w!(Raise, argc),
BuildString { size } => w!(BuildString, size),
BuildTuple { size, unpack } => w!(BuildTuple, size, unpack),
BuildList { size, unpack } => w!(BuildList, size, unpack),
BuildSet { size, unpack } => w!(BuildSet, size, unpack),
BuildMap {
size,
unpack,
for_call,
} => w!(BuildMap, size, unpack, for_call),
BuildSlice { size } => w!(BuildSlice, size),
ListAppend { i } => w!(ListAppend, i),
SetAdd { i } => w!(SetAdd, i),
MapAddRev { i } => w!(MapAddRev, i),
PrintExpr => w!(PrintExpr),
LoadBuildClass => w!(LoadBuildClass),
UnpackSequence { size } => w!(UnpackSequence, size),
UnpackEx { before, after } => w!(UnpackEx, before, after),
FormatValue { .. } => w!(FormatValue), // TODO: write conversion
PopException => w!(PopException),
Reverse { amount } => w!(Reverse, amount),
GetAwaitable => w!(GetAwaitable),
GetAIter => w!(GetAIter),
GetANext => w!(GetANext),
MapAdd { i } => w!(MapAdd, i),
}
}
}
impl fmt::Display for ConstantData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.borrow_constant().fmt_display(f)
}
}
impl<C: Constant> fmt::Debug for CodeObject<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"<code object {} at ??? file {:?}, line {}>",
self.obj_name, self.source_path, self.first_line_number
)
}
}
#[derive(Serialize, Deserialize)]
pub struct FrozenModule<C: Constant = ConstantData> {
#[serde(bound(
deserialize = "C: serde::Deserialize<'de>, C::Name: serde::Deserialize<'de>",
serialize = "C: serde::Serialize, C::Name: serde::Serialize"
))]
pub code: CodeObject<C>,
pub package: bool,
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,6 @@ hexf-parse = "0.1.0"
cfg-if = "0.1"
once_cell = "1.4.1"
siphasher = "0.3"
rand = "0.7.3"
rand = "0.8"
derive_more = "0.99.9"
volatile = "0.3"

714
common/src/boxvec.rs Normal file
View File

@@ -0,0 +1,714 @@
//! An unresizable vector backed by a `Box<[T]>`
use std::borrow::{Borrow, BorrowMut};
use std::mem::{self, MaybeUninit};
use std::ops::{Bound, Deref, DerefMut, RangeBounds};
use std::{alloc, cmp, fmt, ptr, slice};
pub struct BoxVec<T> {
xs: Box<[MaybeUninit<T>]>,
len: usize,
}
impl<T> Drop for BoxVec<T> {
fn drop(&mut self) {
self.clear();
// MaybeUninit inhibits array's drop
}
}
macro_rules! panic_oob {
($method_name:expr, $index:expr, $len:expr) => {
panic!(
concat!(
"BoxVec::",
$method_name,
": index {} is out of bounds in vector of length {}"
),
$index, $len
)
};
}
fn capacity_overflow() -> ! {
panic!("capacity overflow")
}
impl<T> BoxVec<T> {
pub fn new(n: usize) -> BoxVec<T> {
unsafe {
let layout = match alloc::Layout::array::<T>(n) {
Ok(l) => l,
Err(_) => capacity_overflow(),
};
let ptr = if mem::size_of::<T>() == 0 {
ptr::NonNull::<MaybeUninit<T>>::dangling().as_ptr()
} else {
let ptr = alloc::alloc(layout);
if ptr.is_null() {
alloc::handle_alloc_error(layout)
}
ptr as *mut MaybeUninit<T>
};
let ptr = ptr::slice_from_raw_parts_mut(ptr, n);
let xs = Box::from_raw(ptr);
BoxVec { xs, len: 0 }
}
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn capacity(&self) -> usize {
self.xs.len()
}
pub fn is_full(&self) -> bool {
self.len() == self.capacity()
}
pub fn remaining_capacity(&self) -> usize {
self.capacity() - self.len()
}
pub fn push(&mut self, element: T) {
self.try_push(element).unwrap()
}
pub fn try_push(&mut self, element: T) -> Result<(), CapacityError<T>> {
if self.len() < self.capacity() {
unsafe {
self.push_unchecked(element);
}
Ok(())
} else {
Err(CapacityError::new(element))
}
}
/// # Safety
/// Must ensure that self.len() < self.capacity()
pub unsafe fn push_unchecked(&mut self, element: T) {
let len = self.len();
debug_assert!(len < self.capacity());
ptr::write(self.get_unchecked_ptr(len), element);
self.set_len(len + 1);
}
/// Get pointer to where element at `index` would be
unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut T {
self.xs.as_mut_ptr().add(index).cast()
}
pub fn insert(&mut self, index: usize, element: T) {
self.try_insert(index, element).unwrap()
}
pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), CapacityError<T>> {
if index > self.len() {
panic_oob!("try_insert", index, self.len())
}
if self.len() == self.capacity() {
return Err(CapacityError::new(element));
}
let len = self.len();
// follows is just like Vec<T>
unsafe {
// infallible
// The spot to put the new value
{
let p: *mut _ = self.get_unchecked_ptr(index);
// Shift everything over to make space. (Duplicating the
// `index`th element into two consecutive places.)
ptr::copy(p, p.offset(1), len - index);
// Write it in, overwriting the first copy of the `index`th
// element.
ptr::write(p, element);
}
self.set_len(len + 1);
}
Ok(())
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
unsafe {
let new_len = self.len() - 1;
self.set_len(new_len);
Some(ptr::read(self.get_unchecked_ptr(new_len)))
}
}
pub fn swap_remove(&mut self, index: usize) -> T {
self.swap_pop(index)
.unwrap_or_else(|| panic_oob!("swap_remove", index, self.len()))
}
pub fn swap_pop(&mut self, index: usize) -> Option<T> {
let len = self.len();
if index >= len {
return None;
}
self.swap(index, len - 1);
self.pop()
}
pub fn remove(&mut self, index: usize) -> T {
self.pop_at(index)
.unwrap_or_else(|| panic_oob!("remove", index, self.len()))
}
pub fn pop_at(&mut self, index: usize) -> Option<T> {
if index >= self.len() {
None
} else {
self.drain(index..index + 1).next()
}
}
pub fn truncate(&mut self, new_len: usize) {
unsafe {
if new_len < self.len() {
let tail: *mut [_] = &mut self[new_len..];
self.len = new_len;
ptr::drop_in_place(tail);
}
}
}
/// Remove all elements in the vector.
pub fn clear(&mut self) {
self.truncate(0)
}
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&mut e)` returns false.
/// This method operates in place and preserves the order of the retained
/// elements.
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&mut T) -> bool,
{
let len = self.len();
let mut del = 0;
{
let v = &mut **self;
for i in 0..len {
if !f(&mut v[i]) {
del += 1;
} else if del > 0 {
v.swap(i - del, i);
}
}
}
if del > 0 {
self.drain(len - del..);
}
}
/// Set the vector’s length without dropping or moving out elements
///
/// This method is `unsafe` because it changes the notion of the
/// number of “valid” elements in the vector. Use with care.
///
/// This method uses *debug assertions* to check that `length` is
/// not greater than the capacity.
///
/// # Safety
/// Must ensure that length <= self.capacity()
pub unsafe fn set_len(&mut self, length: usize) {
debug_assert!(length <= self.capacity());
self.len = length;
}
/// Copy and appends all elements in a slice to the `BoxVec`.
///
/// # Errors
///
/// This method will return an error if the capacity left (see
/// [`remaining_capacity`]) is smaller then the length of the provided
/// slice.
///
/// [`remaining_capacity`]: #method.remaining_capacity
pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), CapacityError>
where
T: Copy,
{
if self.remaining_capacity() < other.len() {
return Err(CapacityError::new(()));
}
let self_len = self.len();
let other_len = other.len();
unsafe {
let dst = self.as_mut_ptr().add(self_len);
ptr::copy_nonoverlapping(other.as_ptr(), dst, other_len);
self.set_len(self_len + other_len);
}
Ok(())
}
/// Create a draining iterator that removes the specified range in the vector
/// and yields the removed items from start to end. The element range is
/// removed even if the iterator is not consumed until the end.
///
/// Note: It is unspecified how many elements are removed from the vector,
/// if the `Drain` value is leaked.
///
/// **Panics** if the starting point is greater than the end point or if
/// the end point is greater than the length of the vector.
pub fn drain<R>(&mut self, range: R) -> Drain<T>
where
R: RangeBounds<usize>,
{
// Memory safety
//
// When the Drain is first created, it shortens the length of
// the source vector to make sure no uninitialized or moved-from elements
// are accessible at all if the Drain's destructor never gets to run.
//
// Drain will ptr::read out the values to remove.
// When finished, remaining tail of the vec is copied back to cover
// the hole, and the vector length is restored to the new length.
//
let len = self.len();
let start = match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(&i) => i,
Bound::Excluded(&i) => i.saturating_add(1),
};
let end = match range.end_bound() {
Bound::Excluded(&j) => j,
Bound::Included(&j) => j.saturating_add(1),
Bound::Unbounded => len,
};
self.drain_range(start, end)
}
fn drain_range(&mut self, start: usize, end: usize) -> Drain<T> {
let len = self.len();
// bounds check happens here (before length is changed!)
let range_slice: *const _ = &self[start..end];
// Calling `set_len` creates a fresh and thus unique mutable references, making all
// older aliases we created invalid. So we cannot call that function.
self.len = start;
unsafe {
Drain {
tail_start: end,
tail_len: len - end,
iter: (*range_slice).iter(),
vec: ptr::NonNull::from(self),
}
}
}
/// Return a slice containing all elements of the vector.
pub fn as_slice(&self) -> &[T] {
self
}
/// Return a mutable slice containing all elements of the vector.
pub fn as_mut_slice(&mut self) -> &mut [T] {
self
}
/// Return a raw pointer to the vector's buffer.
#[inline]
pub fn as_ptr(&self) -> *const T {
self.xs.as_ptr().cast()
}
/// Return a raw mutable pointer to the vector's buffer.
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.xs.as_mut_ptr().cast()
}
}
impl<T> Deref for BoxVec<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
}
}
impl<T> DerefMut for BoxVec<T> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
let len = self.len();
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), len) }
}
}
/// Iterate the `BoxVec` with references to each element.
impl<'a, T> IntoIterator for &'a BoxVec<T> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// Iterate the `BoxVec` with mutable references to each element.
impl<'a, T> IntoIterator for &'a mut BoxVec<T> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
/// Iterate the `BoxVec` with each element by value.
///
/// The vector is consumed by this operation.
impl<T> IntoIterator for BoxVec<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
IntoIter { index: 0, v: self }
}
}
/// By-value iterator for `BoxVec`.
pub struct IntoIter<T> {
index: usize,
v: BoxVec<T>,
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.index == self.v.len {
None
} else {
unsafe {
let index = self.index;
self.index += 1;
Some(ptr::read(self.v.get_unchecked_ptr(index)))
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.v.len() - self.index;
(len, Some(len))
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<T> {
if self.index == self.v.len {
None
} else {
unsafe {
let new_len = self.v.len() - 1;
self.v.set_len(new_len);
Some(ptr::read(self.v.get_unchecked_ptr(new_len)))
}
}
}
}
impl<T> ExactSizeIterator for IntoIter<T> {}
impl<T> Drop for IntoIter<T> {
fn drop(&mut self) {
// panic safety: Set length to 0 before dropping elements.
let index = self.index;
let len = self.v.len();
unsafe {
self.v.set_len(0);
let elements = slice::from_raw_parts_mut(self.v.get_unchecked_ptr(index), len - index);
ptr::drop_in_place(elements);
}
}
}
impl<T> fmt::Debug for IntoIter<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(&self.v[self.index..]).finish()
}
}
/// A draining iterator for `BoxVec`.
pub struct Drain<'a, T> {
/// Index of tail to preserve
tail_start: usize,
/// Length of tail
tail_len: usize,
/// Current remaining range to remove
iter: slice::Iter<'a, T>,
vec: ptr::NonNull<BoxVec<T>>,
}
unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
impl<T> Iterator for Drain<'_, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|elt| unsafe { ptr::read(elt as *const _) })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for Drain<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter
.next_back()
.map(|elt| unsafe { ptr::read(elt as *const _) })
}
}
impl<T> ExactSizeIterator for Drain<'_, T> {}
impl<'a, T> Drain<'a, T> {
pub fn as_slice(&self) -> &'a [T] {
self.iter.as_slice()
}
}
impl<T> Drop for Drain<'_, T> {
fn drop(&mut self) {
// len is currently 0 so panicking while dropping will not cause a double drop.
// exhaust self first
while let Some(_) = self.next() {}
if self.tail_len > 0 {
unsafe {
let source_vec = self.vec.as_mut();
// memmove back untouched tail, update to new length
let start = source_vec.len();
let tail = self.tail_start;
let src = source_vec.as_ptr().add(tail);
let dst = source_vec.as_mut_ptr().add(start);
ptr::copy(src, dst, self.tail_len);
source_vec.set_len(start + self.tail_len);
}
}
}
}
struct ScopeExitGuard<T, Data, F>
where
F: FnMut(&Data, &mut T),
{
value: T,
data: Data,
f: F,
}
impl<T, Data, F> Drop for ScopeExitGuard<T, Data, F>
where
F: FnMut(&Data, &mut T),
{
fn drop(&mut self) {
(self.f)(&self.data, &mut self.value)
}
}
/// Extend the `BoxVec` with an iterator.
///
/// Does not extract more items than there is space for. No error
/// occurs if there are more iterator elements.
impl<T> Extend<T> for BoxVec<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let take = self.capacity() - self.len();
unsafe {
let len = self.len();
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
let end_ptr = raw_ptr_add(ptr, take);
// Keep the length in a separate variable, write it back on scope
// exit. To help the compiler with alias analysis and stuff.
// We update the length to handle panic in the iteration of the
// user's iterator, without dropping any elements on the floor.
let mut guard = ScopeExitGuard {
value: &mut self.len,
data: len,
f: move |&len, self_len| {
**self_len = len;
},
};
let mut iter = iter.into_iter();
loop {
if ptr == end_ptr {
break;
}
if let Some(elt) = iter.next() {
raw_ptr_write(ptr, elt);
ptr = raw_ptr_add(ptr, 1);
guard.data += 1;
} else {
break;
}
}
}
}
}
/// Rawptr add but uses arithmetic distance for ZST
unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
if mem::size_of::<T>() == 0 {
// Special case for ZST
(ptr as usize).wrapping_add(offset) as _
} else {
ptr.add(offset)
}
}
unsafe fn raw_ptr_write<T>(ptr: *mut T, value: T) {
if mem::size_of::<T>() == 0 {
/* nothing */
} else {
ptr::write(ptr, value)
}
}
impl<T> Clone for BoxVec<T>
where
T: Clone,
{
fn clone(&self) -> Self {
let mut new = BoxVec::new(self.capacity());
new.extend(self.iter().cloned());
new
}
fn clone_from(&mut self, rhs: &Self) {
// recursive case for the common prefix
let prefix = cmp::min(self.len(), rhs.len());
self[..prefix].clone_from_slice(&rhs[..prefix]);
if prefix < self.len() {
// rhs was shorter
for _ in 0..self.len() - prefix {
self.pop();
}
} else {
let rhs_elems = rhs[self.len()..].iter().cloned();
self.extend(rhs_elems);
}
}
}
impl<T> PartialEq for BoxVec<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl<T> PartialEq<[T]> for BoxVec<T>
where
T: PartialEq,
{
fn eq(&self, other: &[T]) -> bool {
**self == *other
}
}
impl<T> Eq for BoxVec<T> where T: Eq {}
impl<T> Borrow<[T]> for BoxVec<T> {
fn borrow(&self) -> &[T] {
self
}
}
impl<T> BorrowMut<[T]> for BoxVec<T> {
fn borrow_mut(&mut self) -> &mut [T] {
self
}
}
impl<T> AsRef<[T]> for BoxVec<T> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<T> AsMut<[T]> for BoxVec<T> {
fn as_mut(&mut self) -> &mut [T] {
self
}
}
impl<T> fmt::Debug for BoxVec<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
}
}
/// Error value indicating insufficient capacity
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub struct CapacityError<T = ()> {
element: T,
}
impl<T> CapacityError<T> {
/// Create a new `CapacityError` from `element`.
pub fn new(element: T) -> CapacityError<T> {
CapacityError { element }
}
/// Extract the overflowing element
pub fn element(self) -> T {
self.element
}
/// Convert into a `CapacityError` that does not carry an element.
pub fn simplify(self) -> CapacityError {
CapacityError { element: () }
}
}
const CAPERROR: &str = "insufficient capacity";
impl<T> std::error::Error for CapacityError<T> {}
impl<T> fmt::Display for CapacityError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", CAPERROR)
}
}
impl<T> fmt::Debug for CapacityError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "capacity error: {}", CAPERROR)
}
}

View File

@@ -252,7 +252,7 @@ pub fn to_hex(value: f64) -> String {
const BITS: i16 = 52;
const FRACT_MASK: u64 = 0xf_ffff_ffff_ffff;
format!(
"{}0x{:x}.{:013x}p{:+}",
"{}{:#x}.{:013x}p{:+}",
sign_fmt,
mantissa >> BITS,
mantissa & FRACT_MASK,

View File

@@ -1,6 +1,7 @@
//! A crate to hold types and functions common to all rustpython components.
pub mod borrow;
pub mod boxvec;
pub mod cmp;
pub mod float_ops;
pub mod hash;

View File

@@ -7,14 +7,20 @@ repository = "https://github.com/RustPython/RustPython"
license = "MIT"
edition = "2018"
[features]
std = ["rustpython-bytecode/std", "itertools/use_std"]
default = ["std"]
[dependencies]
indexmap = "1.0"
itertools = "0.9"
rustpython-bytecode = { path = "../bytecode", version = "0.1.1" }
itertools = { version = "0.9", default-features = false }
rustpython-bytecode = { path = "../bytecode", version = "0.1.1", default-features = false }
rustpython-ast = { path = "../ast" }
num-complex = { version = "0.3", features = ["serde"] }
num-traits = "0.2"
log = "0.4"
arrayvec = "0.5"
ahash = "0.6"
scopeguard = "1.1"
[dev-dependencies]
rustpython-parser = { path = "../parser" }

View File

@@ -5,6 +5,10 @@ description = "A usability wrapper around rustpython-parser and rustpython-compi
authors = ["RustPython Team"]
edition = "2018"
[features]
std = ["rustpython-compiler-core/std", "rustpython-bytecode/std", "rustpython-parser/std"]
default = ["std"]
[dependencies]
thiserror = "1.0"
rustpython-compiler-core = { path = ".." }

View File

@@ -1,4 +1,4 @@
use rustpython_bytecode::bytecode::CodeObject;
use rustpython_bytecode::CodeObject;
use rustpython_compiler_core::{compile, symboltable};
use rustpython_parser::{ast::Location, parser};
use std::fmt;

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,9 @@
use rustpython_ast::Location;
use alloc::string::String;
use core::fmt;
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub struct CompileError {
@@ -37,6 +39,7 @@ pub enum CompileErrorType {
InvalidFuturePlacement,
InvalidFutureFeature(String),
FunctionImportStar,
TooManyStarUnpack,
}
impl fmt::Display for CompileErrorType {
@@ -70,10 +73,14 @@ impl fmt::Display for CompileErrorType {
CompileErrorType::FunctionImportStar => {
write!(f, "import * only allowed at module level")
}
CompileErrorType::TooManyStarUnpack => {
write!(f, "too many expressions in star-unpacking assignment")
}
}
}
}
#[cfg(feature = "std")]
impl Error for CompileErrorType {}
impl fmt::Display for CompileError {
@@ -82,8 +89,5 @@ impl fmt::Display for CompileError {
}
}
impl Error for CompileError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
#[cfg(feature = "std")]
impl Error for CompileError {}

224
compiler/src/ir.rs Normal file
View File

@@ -0,0 +1,224 @@
use crate::IndexSet;
use rustpython_bytecode::{CodeFlags, CodeObject, ConstantData, Instruction, Label, Location};
pub type BlockIdx = Label;
#[derive(Debug)]
pub struct InstructionInfo {
/// If the instruction has a Label argument, it's actually a BlockIdx, not a code offset
pub instr: Instruction,
pub location: Location,
}
// TODO: look into using petgraph for handling blocks and stuff? it's heavier than this, but it
// might enable more analysis/optimizations
#[derive(Debug)]
pub struct Block {
pub instructions: Vec<InstructionInfo>,
pub next: BlockIdx,
}
impl Default for Block {
fn default() -> Self {
Block {
instructions: Vec::new(),
next: Label(u32::MAX),
}
}
}
pub struct CodeInfo {
pub flags: CodeFlags,
pub posonlyarg_count: usize, // Number of positional-only arguments
pub arg_count: usize,
pub kwonlyarg_count: usize,
pub source_path: String,
pub first_line_number: usize,
pub obj_name: String, // Name of the object that created this code object
pub blocks: Vec<Block>,
pub current_block: BlockIdx,
pub constants: Vec<ConstantData>,
pub name_cache: IndexSet<String>,
pub varname_cache: IndexSet<String>,
pub cellvar_cache: IndexSet<String>,
pub freevar_cache: IndexSet<String>,
}
impl CodeInfo {
pub fn finalize_code(mut self, optimize: u8) -> CodeObject {
let max_stacksize = self.max_stacksize();
let cell2arg = self.cell2arg();
if optimize > 0 {
self.dce();
}
let CodeInfo {
flags,
posonlyarg_count,
arg_count,
kwonlyarg_count,
source_path,
first_line_number,
obj_name,
blocks,
current_block: _,
constants,
name_cache,
varname_cache,
cellvar_cache,
freevar_cache,
} = self;
let mut num_instructions = 0;
let mut block_to_offset = vec![Label(0); blocks.len()];
for (idx, block) in iter_blocks(&blocks) {
block_to_offset[idx.0 as usize] = Label(num_instructions as u32);
num_instructions += block.instructions.len();
}
let mut instructions = Vec::with_capacity(num_instructions);
let mut locations = Vec::with_capacity(num_instructions);
for (_, block) in iter_blocks(&blocks) {
for info in &block.instructions {
let mut instr = info.instr.clone();
if let Some(l) = instr.label_arg_mut() {
*l = block_to_offset[l.0 as usize];
}
instructions.push(instr);
locations.push(info.location);
}
}
CodeObject {
flags,
posonlyarg_count,
arg_count,
kwonlyarg_count,
source_path,
first_line_number,
obj_name,
max_stacksize,
instructions: instructions.into_boxed_slice(),
locations: locations.into_boxed_slice(),
constants: constants.into(),
names: name_cache.into_iter().collect(),
varnames: varname_cache.into_iter().collect(),
cellvars: cellvar_cache.into_iter().collect(),
freevars: freevar_cache.into_iter().collect(),
cell2arg,
}
}
fn cell2arg(&self) -> Option<Box<[isize]>> {
if self.cellvar_cache.is_empty() {
return None;
}
let total_args = self.arg_count
+ self.kwonlyarg_count
+ self.flags.contains(CodeFlags::HAS_VARARGS) as usize
+ self.flags.contains(CodeFlags::HAS_VARKEYWORDS) as usize;
let mut found_cellarg = false;
let cell2arg = self
.cellvar_cache
.iter()
.map(|var| {
self.varname_cache
.get_index_of(var)
// check that it's actually an arg
.filter(|i| *i < total_args)
.map_or(-1, |i| {
found_cellarg = true;
i as isize
})
})
.collect::<Box<[_]>>();
if found_cellarg {
Some(cell2arg)
} else {
None
}
}
fn dce(&mut self) {
for block in &mut self.blocks {
let mut last_instr = None;
for (i, ins) in block.instructions.iter().enumerate() {
if ins.instr.unconditional_branch() {
last_instr = Some(i);
break;
}
}
if let Some(i) = last_instr {
block.instructions.truncate(i + 1);
}
}
}
fn max_stacksize(&self) -> u32 {
let mut maxdepth = 0u32;
let mut stack = Vec::with_capacity(self.blocks.len());
let mut startdepths = vec![u32::MAX; self.blocks.len()];
startdepths[0] = 0;
stack.push(Label(0));
'process_blocks: while let Some(block) = stack.pop() {
let mut depth = startdepths[block.0 as usize];
let block = &self.blocks[block.0 as usize];
for i in &block.instructions {
let instr = &i.instr;
let effect = instr.stack_effect(false);
let new_depth = add_ui(depth, effect);
if new_depth > maxdepth {
maxdepth = new_depth
}
// we don't want to worry about Continue or Break, they use unwinding to jump to
// their targets and as such the stack size is taken care of in frame.rs by setting
// it back to the level it was at when SetupLoop was run
let jump_label = instr.label_arg().filter(
|_| !matches!(instr, Instruction::Continue { .. } | Instruction::Break { .. }),
);
if let Some(&target_block) = jump_label {
let effect = instr.stack_effect(true);
let target_depth = add_ui(depth, effect);
if target_depth > maxdepth {
maxdepth = target_depth
}
stackdepth_push(&mut stack, &mut startdepths, target_block, target_depth);
}
depth = new_depth;
if instr.unconditional_branch() {
continue 'process_blocks;
}
}
stackdepth_push(&mut stack, &mut startdepths, block.next, depth);
}
maxdepth
}
}
fn stackdepth_push(stack: &mut Vec<Label>, startdepths: &mut [u32], target: Label, depth: u32) {
let block_depth = &mut startdepths[target.0 as usize];
if *block_depth == u32::MAX || depth > *block_depth {
*block_depth = depth;
stack.push(target);
}
}
fn add_ui(a: u32, b: i32) -> u32 {
if b < 0 {
a - b.abs() as u32
} else {
a + b as u32
}
}
fn iter_blocks(blocks: &[Block]) -> impl Iterator<Item = (BlockIdx, &Block)> + '_ {
let get_idx = move |i: BlockIdx| blocks.get(i.0 as usize).map(|b| (i, b));
std::iter::successors(get_idx(Label(0)), move |(_, b)| get_idx(b.next)) // if b.next is u32::MAX that's the end
}

View File

@@ -1,12 +1,18 @@
//! Compile a Python AST or source code into bytecode consumable by RustPython or
//! (eventually) CPython.
//! Compile a Python AST or source code into bytecode consumable by RustPython.
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/master/logo.png")]
#![doc(html_root_url = "https://docs.rs/rustpython-compiler/")]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
#[macro_use]
extern crate log;
type IndexMap<K, V> = indexmap::IndexMap<K, V, ahash::RandomState>;
type IndexSet<T> = indexmap::IndexSet<T, ahash::RandomState>;
pub mod compile;
pub mod error;
pub mod ir;
pub mod mode;
pub mod symboltable;

View File

@@ -1,3 +1,5 @@
use core::fmt;
#[derive(Clone, Copy)]
pub enum Mode {
Exec,
@@ -5,7 +7,7 @@ pub enum Mode {
Single,
}
impl std::str::FromStr for Mode {
impl core::str::FromStr for Mode {
type Err = ModeParseError;
fn from_str(s: &str) -> Result<Self, ModeParseError> {
match s {
@@ -22,8 +24,8 @@ pub struct ModeParseError {
_priv: (),
}
impl std::fmt::Display for ModeParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl fmt::Display for ModeParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, r#"mode should be "exec", "eval", or "single""#)
}
}

View File

@@ -8,9 +8,10 @@ Inspirational file: https://github.com/python/cpython/blob/master/Python/symtabl
*/
use crate::error::{CompileError, CompileErrorType};
use indexmap::map::IndexMap;
use crate::IndexMap;
use alloc::{borrow::ToOwned, format, string::String, vec, vec::Vec};
use core::fmt;
use rustpython_ast::{self as ast, Location};
use std::fmt;
pub fn make_symbol_table(program: &ast::Program) -> Result<SymbolTable, SymbolTableError> {
let mut builder = SymbolTableBuilder::default();
@@ -58,7 +59,7 @@ impl SymbolTable {
typ,
line_number,
is_nested,
symbols: IndexMap::new(),
symbols: IndexMap::default(),
sub_tables: vec![],
}
}
@@ -187,8 +188,8 @@ impl SymbolTable {
}
}
impl std::fmt::Debug for SymbolTable {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl fmt::Debug for SymbolTable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"SymbolTable({:?} symbols, {:?} sub scopes)",
@@ -209,8 +210,9 @@ fn analyze_symbol_table(symbol_table: &mut SymbolTable) -> SymbolTableResult {
type SymbolMap = IndexMap<String, Symbol>;
mod stack {
use std::panic;
use std::ptr::NonNull;
use alloc::vec::Vec;
use core::ptr::NonNull;
pub struct StackStack<T> {
v: Vec<NonNull<T>>,
}
@@ -227,9 +229,10 @@ mod stack {
F: FnOnce(&mut Self) -> R,
{
self.v.push(x.into());
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| f(self)));
self.v.pop();
res.unwrap_or_else(|x| panic::resume_unwind(x))
let mut this = scopeguard::guard(self, |this| {
this.v.pop();
});
f(&mut this)
}
pub fn iter(&self) -> impl Iterator<Item = &T> + DoubleEndedIterator + '_ {
@@ -273,7 +276,7 @@ struct SymbolTableAnalyzer {
impl SymbolTableAnalyzer {
fn analyze_symbol_table(&mut self, symbol_table: &mut SymbolTable) -> SymbolTableResult {
let symbols = std::mem::take(&mut symbol_table.symbols);
let symbols = core::mem::take(&mut symbol_table.symbols);
let sub_tables = &mut *symbol_table.sub_tables;
let mut info = (symbols, symbol_table.typ);
@@ -469,7 +472,7 @@ impl SymbolTableAnalyzer {
SymbolTableType::Class => {
// named expressions are forbidden in comprehensions on class scope
return Err(SymbolTableError {
error: "assignment expression within a comprehension cannot be used in a class body".to_string(),
error: "assignment expression within a comprehension cannot be used in a class body".to_owned(),
// TODO: accurate location info, somehow
location: Location::default(),
});
@@ -999,7 +1002,7 @@ impl SymbolTableBuilder {
// comprehension iterator definitions
if let ExpressionContext::IterDefinitionExp = context {
return Err(SymbolTableError {
error: "assignment expression cannot be used in a comprehension iterable expression".to_string(),
error: "assignment expression cannot be used in a comprehension iterable expression".to_owned(),
// TODO: accurate location info, somehow
location: Location::default(),
});
@@ -1218,7 +1221,7 @@ impl SymbolTableBuilder {
return Err(SymbolTableError {
error:
"assignment expression cannot be used in a comprehension iterable expression"
.to_string(),
.to_owned(),
location,
});
}

View File

@@ -17,7 +17,7 @@ use crate::{extract_spans, Diagnostic};
use once_cell::sync::Lazy;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
use rustpython_bytecode::bytecode::{CodeObject, FrozenModule};
use rustpython_bytecode::{CodeObject, FrozenModule};
use rustpython_compiler as compile;
use std::collections::HashMap;
use std::env;
@@ -242,7 +242,7 @@ impl PyCompileInput {
});
} else if ident == "crate_name" {
let name = match &name_value.lit {
Lit::Str(s) => syn::Ident::new(&s.value(), s.span()),
Lit::Str(s) => s.parse()?,
_ => bail_span!(name_value.lit, "source must be a string"),
};
crate_name = Some(name);
@@ -261,7 +261,7 @@ impl PyCompileInput {
source,
mode: mode.unwrap_or(compile::Mode::Exec),
module_name: module_name.unwrap_or_else(|| "frozen".to_owned()),
crate_name: crate_name.unwrap_or_else(|| syn::parse_quote!(rustpython_vm)),
crate_name: crate_name.unwrap_or_else(|| syn::parse_quote!(::rustpython_vm::bytecode)),
})
}
}
@@ -302,7 +302,7 @@ struct PyCompileArgs {
source: CompilationSource,
mode: compile::Mode,
module_name: String,
crate_name: syn::Ident,
crate_name: syn::Path,
}
pub fn impl_py_compile(input: TokenStream2) -> Result<TokenStream2, Diagnostic> {
@@ -316,7 +316,7 @@ pub fn impl_py_compile(input: TokenStream2) -> Result<TokenStream2, Diagnostic>
let bytes = LitByteStr::new(&bytes, Span::call_site());
let output = quote! {
::#crate_name::bytecode::CodeObject::from_bytes(#bytes)
#crate_name::CodeObject::from_bytes(#bytes)
.expect("Deserializing CodeObject failed")
};
@@ -339,8 +339,8 @@ pub fn impl_py_freeze(input: TokenStream2) -> Result<TokenStream2, Diagnostic> {
let bytes = code.to_bytes();
let bytes = LitByteStr::new(&bytes, Span::call_site());
quote! {
m.insert(#module_name.into(), ::#crate_name::bytecode::FrozenModule {
code: ::#crate_name::bytecode::CodeObject::from_bytes(
m.insert(#module_name.into(), #crate_name::FrozenModule {
code: #crate_name::CodeObject::from_bytes(
#bytes
).expect("Deserializing CodeObject failed"),
package: #package,

View File

@@ -326,7 +326,7 @@ where
quote! {
class.set_str_attr(
#py_name,
ctx.new_function_named(Self::#ident, #py_name.to_owned())
ctx.make_funcdef(#py_name, Self::#ident)
#doc
.#build_func(ctx),
);

View File

@@ -263,7 +263,7 @@ impl ModuleItem for FunctionItem {
);
let module = args.module_name();
let new_func = quote_spanned!(ident.span()=>
vm.ctx.new_function_named(#ident, #py_name.to_owned())
vm.ctx.make_funcdef(#py_name, #ident)
#doc
.into_function()
.with_module(vm.ctx.new_str(#module.to_owned()))

View File

@@ -41,7 +41,9 @@ fn run(vm: &vm::VirtualMachine) -> vm::pyobject::PyResult<()> {
let scope: vm::scope::Scope = vm.new_scope_with_builtins();
// typing `quit()` is too long, let's make `on(False)` work instead.
scope.globals.set_item("on", vm.ctx.new_function(on), vm)?;
scope
.globals
.set_item("on", vm.ctx.new_function("on", on), vm)?;
// let's include a fibonacci function, but let's be lazy and write it in Python
add_python_function!(

View File

@@ -1,5 +1,6 @@
from testutils import assert_raises
import pickle
import sys
# new
assert bytearray([1, 2, 3])
@@ -753,4 +754,8 @@ b = pickle.loads(pickle.dumps(a, 4))
assert type(a) == type(b)
assert a.x == b.x
assert a.y == b.y
assert a == b
assert a == b
a = bytearray()
for i in range(-1, 2, 1):
assert_raises(IndexError, lambda: a[-sys.maxsize - i], _msg='bytearray index out of range')

View File

@@ -10,9 +10,9 @@ edition = "2018"
autotests = false
[dependencies]
cranelift = "0.68.0"
cranelift-module = "0.68.0"
cranelift-simplejit = "0.68.0"
cranelift = "0.69.0"
cranelift-module = "0.69.0"
cranelift-jit = "0.69.0"
num-traits = "0.2"
libffi = "1.0"
rustpython-bytecode = { path = "../bytecode", version = "0.1.2" }

View File

@@ -1,8 +1,8 @@
use cranelift::prelude::*;
use num_traits::cast::ToPrimitive;
use rustpython_bytecode::bytecode::{
self, BinaryOperator, BorrowedConstant, CodeObject, ComparisonOperator, Instruction, Label,
UnaryOperator,
use rustpython_bytecode::{
self as bytecode, BinaryOperator, BorrowedConstant, CodeObject, ComparisonOperator,
Instruction, Label, UnaryOperator,
};
use std::collections::HashMap;
@@ -54,7 +54,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
let params = compiler.builder.func.dfg.block_params(entry_block).to_vec();
for (i, (ty, val)) in arg_types.iter().zip(params).enumerate() {
compiler
.store_variable(i, JitValue::new(val, ty.clone()))
.store_variable(i as u32, JitValue::new(val, ty.clone()))
.unwrap();
}
compiler
@@ -66,8 +66,8 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
val: JitValue,
) -> Result<(), JitCompileError> {
let builder = &mut self.builder;
let local = self.variables[idx].get_or_insert_with(|| {
let var = Variable::new(idx);
let local = self.variables[idx as usize].get_or_insert_with(|| {
let var = Variable::new(idx as usize);
let local = Local {
var,
ty: val.ty.clone(),
@@ -119,7 +119,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
let label_targets = bytecode.label_targets();
for (offset, instruction) in bytecode.instructions.iter().enumerate() {
let label = Label(offset);
let label = Label(offset as u32);
if label_targets.contains(&label) {
let block = self.get_or_create_block(label);
@@ -219,7 +219,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
Ok(())
}
Instruction::LoadFast(idx) => {
let local = self.variables[*idx]
let local = self.variables[*idx as usize]
.as_ref()
.ok_or(JitCompileError::BadBytecode)?;
self.stack.push(JitValue {
@@ -232,7 +232,9 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
let val = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
self.store_variable(*idx, val)
}
Instruction::LoadConst { idx } => self.load_const(constants[*idx].borrow_constant()),
Instruction::LoadConst { idx } => {
self.load_const(constants[*idx as usize].borrow_constant())
}
Instruction::ReturnValue => {
let val = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
if let Some(ref ty) = self.sig.ret {
@@ -320,7 +322,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
_ => Err(JitCompileError::NotSupported),
}
}
Instruction::BinaryOperation { op, .. } => {
Instruction::BinaryOperation { op } | Instruction::BinaryOperationInplace { op } => {
// the rhs is popped off first
let b = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;
let a = self.stack.pop().ok_or(JitCompileError::BadBytecode)?;

View File

@@ -1,10 +1,10 @@
use std::fmt;
use cranelift::prelude::*;
use cranelift_jit::{JITBuilder, JITModule};
use cranelift_module::{FuncId, Linkage, Module, ModuleError};
use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule, SimpleJITProduct};
use rustpython_bytecode::bytecode;
use rustpython_bytecode as bytecode;
mod instructions;
@@ -32,13 +32,13 @@ pub enum JitArgumentError {
struct Jit {
builder_context: FunctionBuilderContext,
ctx: codegen::Context,
module: SimpleJITModule,
module: JITModule,
}
impl Jit {
fn new() -> Self {
let builder = SimpleJITBuilder::new(cranelift_module::default_libcall_names());
let module = SimpleJITModule::new(builder);
let builder = JITBuilder::new(cranelift_module::default_libcall_names());
let module = JITModule::new(builder);
Self {
builder_context: FunctionBuilderContext::new(),
ctx: module.make_context(),
@@ -77,7 +77,7 @@ impl Jit {
builder.finalize();
let id = self.module.declare_function(
&format!("jit_{}", bytecode.obj_name),
&format!("jit_{}", bytecode.obj_name.as_ref()),
Linkage::Export,
&self.ctx.func.signature,
)?;
@@ -105,14 +105,14 @@ pub fn compile<C: bytecode::Constant>(
Ok(CompiledCode {
sig,
code,
memory: jit.module.finish(),
module: jit.module,
})
}
pub struct CompiledCode {
sig: JitSig,
code: *const u8,
memory: SimpleJITProduct,
module: JITModule,
}
impl CompiledCode {
@@ -287,7 +287,7 @@ unsafe impl Sync for CompiledCode {}
impl Drop for CompiledCode {
fn drop(&mut self) {
// SAFETY: The only pointer that this memory will also be dropped now
unsafe { self.memory.free_memory() }
unsafe { self.module.free_memory() }
}
}

View File

@@ -1,6 +1,6 @@
use std::collections::HashMap;
use rustpython_bytecode::bytecode::{CodeObject, ConstantData, Instruction};
use rustpython_bytecode::{CodeObject, ConstantData, Instruction};
use rustpython_jit::{CompiledCode, JitType};
#[derive(Debug, Clone)]
@@ -78,13 +78,15 @@ impl StackMachine {
names: &[String],
) -> bool {
match instruction {
Instruction::LoadConst { idx } => self.stack.push(constants[idx].clone().into()),
Instruction::LoadNameAny(idx) => {
self.stack.push(StackValue::String(names[idx].clone()))
Instruction::LoadConst { idx } => {
self.stack.push(constants[idx as usize].clone().into())
}
Instruction::LoadNameAny(idx) => self
.stack
.push(StackValue::String(names[idx as usize].clone())),
Instruction::StoreLocal(idx) => {
self.locals
.insert(names[idx].clone(), self.stack.pop().unwrap());
.insert(names[idx as usize].clone(), self.stack.pop().unwrap());
}
Instruction::StoreAttr { .. } => {
// Do nothing except throw away the stack values
@@ -104,7 +106,7 @@ impl StackMachine {
}
self.stack.push(StackValue::Map(map));
}
Instruction::MakeFunction => {
Instruction::MakeFunction(_flags) => {
let name = if let Some(StackValue::String(name)) = self.stack.pop() {
name
} else {
@@ -134,7 +136,7 @@ impl StackMachine {
let mut values = Vec::new();
// Pop all values from stack:
values.extend(self.stack.drain(self.stack.len() - amount..));
values.extend(self.stack.drain(self.stack.len() - amount as usize..));
// Push top of stack back first:
self.stack.push(values.pop().unwrap());

View File

@@ -8,15 +8,22 @@ repository = "https://github.com/RustPython/RustPython"
license = "MIT"
edition = "2018"
[features]
std = []
default = ["std", "lalrpop-util/std", "num-bigint/std"]
[build-dependencies]
lalrpop = "0.19"
lalrpop = "0.19.4"
[dependencies]
rustpython-ast = { path = "../ast" }
lalrpop-util = "0.19.1"
lalrpop-util = { version = "0.19.4", default-features = false }
log = "0.4.1"
num-bigint = "0.3"
num-traits = "0.2"
num-bigint = { version = "0.3", default-features = false }
num-traits = { version = "0.2", default-features = false }
unic-emoji-char = "0.9"
unic-ucd-ident = "0.9"
unicode_names2 = "0.4"
phf = { version = "0.8", features = ["macros"] }
ahash = "0.6"
hashbrown = "0.9"

View File

@@ -5,8 +5,10 @@ use lalrpop_util::ParseError as LalrpopError;
use crate::ast::Location;
use crate::token::Tok;
use alloc::{boxed::Box, string::String};
use core::fmt;
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt;
/// Represents an error during lexical scanning.
#[derive(Debug, PartialEq)]
@@ -22,6 +24,7 @@ pub enum LexicalErrorType {
NestingError,
IndentationError,
TabError,
TabsAfterSpaces,
DefaultArgumentError,
PositionalArgumentError,
DuplicateKeywordArgumentError,
@@ -45,6 +48,9 @@ impl fmt::Display for LexicalErrorType {
LexicalErrorType::TabError => {
write!(f, "inconsistent use of tabs and spaces in indentation")
}
LexicalErrorType::TabsAfterSpaces => {
write!(f, "Tabs not allowed as part of indentation after spaces")
}
LexicalErrorType::DefaultArgumentError => {
write!(f, "non-default argument follows default argument")
}
@@ -66,6 +72,16 @@ impl fmt::Display for LexicalErrorType {
}
}
#[cfg(feature = "std")]
impl Error for LexicalErrorType {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
LexicalErrorType::FStringError(e) => Some(e),
_ => None,
}
}
}
// TODO: consolidate these with ParseError
#[derive(Debug, PartialEq)]
pub struct FStringError {
@@ -115,6 +131,16 @@ impl From<FStringError> for LalrpopError<Location, Tok, LexicalError> {
}
}
#[cfg(feature = "std")]
impl Error for FStringErrorType {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
FStringErrorType::InvalidExpression(e) => Some(e.as_ref()),
_ => None,
}
}
}
/// Represents an error during parsing
#[derive(Debug, PartialEq)]
pub struct ParseError {
@@ -200,32 +226,45 @@ impl fmt::Display for ParseErrorType {
}
}
impl Error for ParseErrorType {}
#[cfg(feature = "std")]
impl Error for ParseErrorType {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ParseErrorType::Lexical(e) => Some(e),
_ => None,
}
}
}
impl ParseErrorType {
pub fn is_indentation_error(&self) -> bool {
match self {
ParseErrorType::Lexical(LexicalErrorType::IndentationError) => true,
ParseErrorType::UnrecognizedToken(token, expected) => {
*token == Tok::Indent || expected.clone() == Some("Indent".to_owned())
*token == Tok::Indent || expected.as_ref().map_or(false, |s| s == "Indent")
}
_ => false,
}
}
pub fn is_tab_error(&self) -> bool {
matches!(self, ParseErrorType::Lexical(LexicalErrorType::TabError))
matches!(
self,
ParseErrorType::Lexical(LexicalErrorType::TabError)
| ParseErrorType::Lexical(LexicalErrorType::TabsAfterSpaces)
)
}
}
impl std::ops::Deref for ParseError {
impl core::ops::Deref for ParseError {
type Target = ParseErrorType;
fn deref(&self) -> &Self::Target {
&self.error
}
}
#[cfg(feature = "std")]
impl Error for ParseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
self.error.source()
}
}

View File

@@ -1,6 +1,5 @@
use std::iter;
use std::mem;
use std::str;
use alloc::{borrow::ToOwned, boxed::Box, format, string::String, vec, vec::Vec};
use core::{iter, mem, str};
use crate::ast::{ConversionFlag, Expression, Location, StringGroup};
use crate::error::{FStringError, FStringErrorType, ParseError};
@@ -81,7 +80,7 @@ impl<'a> FStringParser<'a> {
// match a python 3.8 self documenting expression
// format '{' PYTHON_EXPRESSION '=' FORMAT_SPECIFIER? '}'
'=' if self.chars.peek() != Some(&'=') && delims.is_empty() => {
pred_expression_text = expression.to_string(); // safe expression before = to print it
pred_expression_text = expression.to_owned(); // safe expression before = to print it
}
':' if delims.is_empty() => {
@@ -283,6 +282,7 @@ mod tests {
fn mk_ident(name: &str, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::Identifier {
name: name.to_owned(),
},

View File

@@ -1,4 +1,5 @@
use std::collections::HashSet;
use alloc::{string::String, vec, vec::Vec};
use hashbrown::HashSet;
use crate::ast;
use crate::error::{LexicalError, LexicalErrorType};
@@ -45,7 +46,8 @@ pub fn parse_args(func_args: Vec<FunctionArgument>) -> Result<ast::ArgumentList,
let mut args = vec![];
let mut keywords = vec![];
let mut keyword_names = HashSet::with_capacity(func_args.len());
let mut keyword_names =
HashSet::with_capacity_and_hasher(func_args.len(), ahash::RandomState::default());
for (name, value) in func_args {
match name {
Some(n) => {

View File

@@ -5,13 +5,19 @@
pub use super::token::Tok;
use crate::ast::Location;
use crate::error::{LexicalError, LexicalErrorType};
use alloc::{
borrow::ToOwned,
format,
string::{String, ToString},
vec,
vec::Vec,
};
use core::char;
use core::cmp::Ordering;
use core::str::FromStr;
use num_bigint::BigInt;
use num_traits::identities::Zero;
use num_traits::Num;
use std::char;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::str::FromStr;
use unic_emoji_char::is_emoji_presentation;
use unic_ucd_ident::{is_xid_continue, is_xid_start};
@@ -66,57 +72,53 @@ pub struct Lexer<T: Iterator<Item = char>> {
chr1: Option<char>,
chr2: Option<char>,
location: Location,
keywords: HashMap<String, Tok>,
}
pub fn get_keywords() -> HashMap<String, Tok> {
let mut keywords: HashMap<String, Tok> = HashMap::new();
pub static KEYWORDS: phf::Map<&'static str, Tok> = phf::phf_map! {
// Alphabetical keywords:
keywords.insert(String::from("..."), Tok::Ellipsis);
keywords.insert(String::from("False"), Tok::False);
keywords.insert(String::from("None"), Tok::None);
keywords.insert(String::from("True"), Tok::True);
"..." => Tok::Ellipsis,
"False" => Tok::False,
"None" => Tok::None,
"True" => Tok::True,
keywords.insert(String::from("and"), Tok::And);
keywords.insert(String::from("as"), Tok::As);
keywords.insert(String::from("assert"), Tok::Assert);
keywords.insert(String::from("async"), Tok::Async);
keywords.insert(String::from("await"), Tok::Await);
keywords.insert(String::from("break"), Tok::Break);
keywords.insert(String::from("class"), Tok::Class);
keywords.insert(String::from("continue"), Tok::Continue);
keywords.insert(String::from("def"), Tok::Def);
keywords.insert(String::from("del"), Tok::Del);
keywords.insert(String::from("elif"), Tok::Elif);
keywords.insert(String::from("else"), Tok::Else);
keywords.insert(String::from("except"), Tok::Except);
keywords.insert(String::from("finally"), Tok::Finally);
keywords.insert(String::from("for"), Tok::For);
keywords.insert(String::from("from"), Tok::From);
keywords.insert(String::from("global"), Tok::Global);
keywords.insert(String::from("if"), Tok::If);
keywords.insert(String::from("import"), Tok::Import);
keywords.insert(String::from("in"), Tok::In);
keywords.insert(String::from("is"), Tok::Is);
keywords.insert(String::from("lambda"), Tok::Lambda);
keywords.insert(String::from("nonlocal"), Tok::Nonlocal);
keywords.insert(String::from("not"), Tok::Not);
keywords.insert(String::from("or"), Tok::Or);
keywords.insert(String::from("pass"), Tok::Pass);
keywords.insert(String::from("raise"), Tok::Raise);
keywords.insert(String::from("return"), Tok::Return);
keywords.insert(String::from("try"), Tok::Try);
keywords.insert(String::from("while"), Tok::While);
keywords.insert(String::from("with"), Tok::With);
keywords.insert(String::from("yield"), Tok::Yield);
keywords
}
"and" => Tok::And,
"as" => Tok::As,
"assert" => Tok::Assert,
"async" => Tok::Async,
"await" => Tok::Await,
"break" => Tok::Break,
"class" => Tok::Class,
"continue" => Tok::Continue,
"def" => Tok::Def,
"del" => Tok::Del,
"elif" => Tok::Elif,
"else" => Tok::Else,
"except" => Tok::Except,
"finally" => Tok::Finally,
"for" => Tok::For,
"from" => Tok::From,
"global" => Tok::Global,
"if" => Tok::If,
"import" => Tok::Import,
"in" => Tok::In,
"is" => Tok::Is,
"lambda" => Tok::Lambda,
"nonlocal" => Tok::Nonlocal,
"not" => Tok::Not,
"or" => Tok::Or,
"pass" => Tok::Pass,
"raise" => Tok::Raise,
"return" => Tok::Return,
"try" => Tok::Try,
"while" => Tok::While,
"with" => Tok::With,
"yield" => Tok::Yield,
};
pub type Spanned = (Location, Tok, Location);
pub type LexResult = Result<Spanned, LexicalError>;
pub fn make_tokenizer<'a>(source: &'a str) -> impl Iterator<Item = LexResult> + 'a {
pub fn make_tokenizer(source: &str) -> impl Iterator<Item = LexResult> + '_ {
let nlh = NewlineHandler::new(source.chars());
Lexer::new(nlh)
}
@@ -193,7 +195,6 @@ where
location: Location::new(0, 0),
chr1: None,
chr2: None,
keywords: get_keywords(),
};
lxr.next_char();
lxr.next_char();
@@ -245,8 +246,8 @@ where
}
let end_pos = self.get_pos();
if self.keywords.contains_key(&name) {
Ok((start_pos, self.keywords[&name].clone(), end_pos))
if let Some(tok) = KEYWORDS.get(name.as_str()) {
Ok((start_pos, tok.clone(), end_pos))
} else {
Ok((start_pos, Tok::Name { name }, end_pos))
}
@@ -442,8 +443,8 @@ where
}
}
match p {
0xD800..=0xDFFF => Ok(std::char::REPLACEMENT_CHARACTER),
_ => std::char::from_u32(p).ok_or(unicode_error),
0xD800..=0xDFFF => Ok(char::REPLACEMENT_CHARACTER),
_ => char::from_u32(p).ok_or(unicode_error),
}
}
@@ -678,9 +679,7 @@ where
// This is technically stricter than python3 but spaces before
// tabs is even more insane than mixing spaces and tabs.
return Err(LexicalError {
error: LexicalErrorType::OtherError(
"Tabs not allowed as part of indentation after spaces".to_owned(),
),
error: LexicalErrorType::TabsAfterSpaces,
location: self.get_pos(),
});
}

View File

@@ -17,6 +17,13 @@
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/master/logo.png")]
#![doc(html_root_url = "https://docs.rs/rustpython-parser/")]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
// hack to get around lalrpop hardcoding ::std::* paths
#[cfg(not(feature = "std"))]
extern crate self as std;
#[macro_use]
extern crate log;

View File

@@ -1,10 +1,12 @@
use core::fmt;
#[derive(Clone, Copy)]
pub enum Mode {
Program,
Statement,
}
impl std::str::FromStr for Mode {
impl core::str::FromStr for Mode {
type Err = ModeParseError;
fn from_str(s: &str) -> Result<Self, ModeParseError> {
match s {
@@ -20,8 +22,8 @@ pub struct ModeParseError {
_priv: (),
}
impl std::fmt::Display for ModeParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl fmt::Display for ModeParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, r#"mode should be "exec", "eval", or "single""#)
}
}

View File

@@ -5,7 +5,8 @@
//! parse a whole program, a single statement, or a single
//! expression.
use std::iter;
use alloc::vec::Vec;
use core::iter;
use crate::ast;
use crate::error::ParseError;
@@ -60,9 +61,11 @@ pub fn parse_statement(source: &str) -> Result<Vec<ast::Statement>, ParseError>
///
/// assert_eq!(ast::Expression {
/// location: ast::Location::new(1, 3),
/// custom: (),
/// node: ast::ExpressionType::Binop {
/// a: Box::new(ast::Expression {
/// location: ast::Location::new(1, 1),
/// custom: (),
/// node: ast::ExpressionType::Number {
/// value: ast::Number::Integer { value: BigInt::from(1) }
/// }
@@ -70,6 +73,7 @@ pub fn parse_statement(source: &str) -> Result<Vec<ast::Statement>, ParseError>
/// op: ast::Operator::Add,
/// b: Box::new(ast::Expression {
/// location: ast::Location::new(1, 5),
/// custom: (),
/// node: ast::ExpressionType::Number {
/// value: ast::Number::Integer { value: BigInt::from(2) }
/// }
@@ -103,11 +107,13 @@ mod tests {
use super::parse_expression;
use super::parse_program;
use super::parse_statement;
use alloc::borrow::ToOwned;
use num_bigint::BigInt;
fn mk_ident(name: &str, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::Identifier {
name: name.to_owned(),
},
@@ -117,6 +123,7 @@ mod tests {
fn make_int(value: i32, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::Number {
value: ast::Number::Integer {
value: BigInt::from(value),
@@ -128,9 +135,10 @@ mod tests {
fn make_string(value: &str, row: usize, col: usize) -> ast::Expression {
ast::Expression {
location: ast::Location::new(row, col),
custom: (),
node: ast::ExpressionType::String {
value: ast::StringGroup::Constant {
value: String::from(value),
value: value.to_owned(),
},
},
}
@@ -139,6 +147,7 @@ mod tests {
fn as_statement(expr: ast::Expression) -> ast::Statement {
ast::Statement {
location: expr.location,
custom: (),
node: ast::StatementType::Expression { expression: expr },
}
}
@@ -151,15 +160,17 @@ mod tests {
#[test]
fn test_parse_print_hello() {
let source = String::from("print('Hello world')");
let parse_ast = parse_program(&source).unwrap();
let source = "print('Hello world')";
let parse_ast = parse_program(source).unwrap();
assert_eq!(
parse_ast,
ast::Program {
statements: vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Expression {
expression: ast::Expression {
custom: (),
location: ast::Location::new(1, 6),
node: ast::ExpressionType::Call {
function: Box::new(mk_ident("print", 1, 1)),
@@ -175,16 +186,18 @@ mod tests {
#[test]
fn test_parse_print_2() {
let source = String::from("print('Hello world', 2)");
let parse_ast = parse_program(&source).unwrap();
let source = "print('Hello world', 2)";
let parse_ast = parse_program(source).unwrap();
assert_eq!(
parse_ast,
ast::Program {
statements: vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Expression {
expression: ast::Expression {
location: ast::Location::new(1, 6),
custom: (),
node: ast::ExpressionType::Call {
function: Box::new(mk_ident("print", 1, 1)),
args: vec![make_string("Hello world", 1, 8), make_int(2, 1, 22),],
@@ -199,16 +212,18 @@ mod tests {
#[test]
fn test_parse_kwargs() {
let source = String::from("my_func('positional', keyword=2)");
let parse_ast = parse_program(&source).unwrap();
let source = "my_func('positional', keyword=2)";
let parse_ast = parse_program(source).unwrap();
assert_eq!(
parse_ast,
ast::Program {
statements: vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Expression {
expression: ast::Expression {
location: ast::Location::new(1, 8),
custom: (),
node: ast::ExpressionType::Call {
function: Box::new(mk_ident("my_func", 1, 1)),
args: vec![make_string("positional", 1, 10)],
@@ -226,17 +241,19 @@ mod tests {
#[test]
fn test_parse_if_elif_else() {
let source = String::from("if 1: 10\nelif 2: 20\nelse: 30");
let parse_ast = parse_statement(&source).unwrap();
let source = "if 1: 10\nelif 2: 20\nelse: 30";
let parse_ast = parse_statement(source).unwrap();
assert_eq!(
parse_ast,
vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::If {
test: make_int(1, 1, 4),
body: vec![as_statement(make_int(10, 1, 7))],
orelse: Some(vec![ast::Statement {
location: ast::Location::new(2, 1),
custom: (),
node: ast::StatementType::If {
test: make_int(2, 2, 6),
body: vec![as_statement(make_int(20, 2, 9))],
@@ -250,24 +267,25 @@ mod tests {
#[test]
fn test_parse_lambda() {
let source = String::from("lambda x, y: x * y"); // lambda(x, y): x * y");
let parse_ast = parse_statement(&source);
let source = "lambda x, y: x * y"; // lambda(x, y): x * y");
let parse_ast = parse_statement(source);
assert_eq!(
parse_ast,
Ok(vec![as_statement(ast::Expression {
location: ast::Location::new(1, 1),
custom: (),
node: ast::ExpressionType::Lambda {
args: Box::new(ast::Parameters {
posonlyargs_count: 0,
args: vec![
ast::Parameter {
location: ast::Location::new(1, 8),
arg: String::from("x"),
arg: "x".to_owned(),
annotation: None,
},
ast::Parameter {
location: ast::Location::new(1, 11),
arg: String::from("y"),
arg: "y".to_owned(),
annotation: None,
}
],
@@ -279,6 +297,7 @@ mod tests {
}),
body: Box::new(ast::Expression {
location: ast::Location::new(1, 16),
custom: (),
node: ast::ExpressionType::Binop {
a: Box::new(mk_ident("x", 1, 14)),
op: ast::Operator::Mult,
@@ -292,14 +311,16 @@ mod tests {
#[test]
fn test_parse_tuples() {
let source = String::from("a, b = 4, 5");
let source = "a, b = 4, 5";
assert_eq!(
parse_statement(&source),
parse_statement(source),
Ok(vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::Assign {
targets: vec![ast::Expression {
custom: (),
location: ast::Location::new(1, 1),
node: ast::ExpressionType::Tuple {
elements: vec![mk_ident("a", 1, 1), mk_ident("b", 1, 4),]
@@ -307,6 +328,7 @@ mod tests {
}],
value: ast::Expression {
location: ast::Location::new(1, 8),
custom: (),
node: ast::ExpressionType::Tuple {
elements: vec![make_int(4, 1, 8), make_int(5, 1, 11),]
}
@@ -318,28 +340,33 @@ mod tests {
#[test]
fn test_parse_class() {
let source = String::from(
"class Foo(A, B):\n def __init__(self):\n pass\n def method_with_default(self, arg='default'):\n pass",
);
let source = "\
class Foo(A, B):
def __init__(self):
pass
def method_with_default(self, arg='default'):
pass";
assert_eq!(
parse_statement(&source),
parse_statement(source),
Ok(vec![ast::Statement {
location: ast::Location::new(1, 1),
custom: (),
node: ast::StatementType::ClassDef {
name: String::from("Foo"),
name: "Foo".to_owned(),
bases: vec![mk_ident("A", 1, 11), mk_ident("B", 1, 14)],
keywords: vec![],
body: vec![
ast::Statement {
location: ast::Location::new(2, 2),
custom: (),
node: ast::StatementType::FunctionDef {
is_async: false,
name: String::from("__init__"),
name: "__init__".to_owned(),
args: Box::new(ast::Parameters {
posonlyargs_count: 0,
args: vec![ast::Parameter {
location: ast::Location::new(2, 15),
arg: String::from("self"),
arg: "self".to_owned(),
annotation: None,
}],
kwonlyargs: vec![],
@@ -350,6 +377,7 @@ mod tests {
}),
body: vec![ast::Statement {
location: ast::Location::new(3, 3),
custom: (),
node: ast::StatementType::Pass,
}],
decorator_list: vec![],
@@ -358,20 +386,21 @@ mod tests {
},
ast::Statement {
location: ast::Location::new(4, 2),
custom: (),
node: ast::StatementType::FunctionDef {
is_async: false,
name: String::from("method_with_default"),
name: "method_with_default".to_owned(),
args: Box::new(ast::Parameters {
posonlyargs_count: 0,
args: vec![
ast::Parameter {
location: ast::Location::new(4, 26),
arg: String::from("self"),
arg: "self".to_owned(),
annotation: None,
},
ast::Parameter {
location: ast::Location::new(4, 32),
arg: String::from("arg"),
arg: "arg".to_owned(),
annotation: None,
}
],
@@ -383,6 +412,7 @@ mod tests {
}),
body: vec![ast::Statement {
location: ast::Location::new(5, 3),
custom: (),
node: ast::StatementType::Pass,
}],
decorator_list: vec![],
@@ -398,12 +428,13 @@ mod tests {
#[test]
fn test_parse_dict_comprehension() {
let source = String::from("{x1: x2 for y in z}");
let parse_ast = parse_expression(&source).unwrap();
let source = "{x1: x2 for y in z}";
let parse_ast = parse_expression(source).unwrap();
assert_eq!(
parse_ast,
ast::Expression {
location: ast::Location::new(1, 1),
custom: (),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::Dict {
key: mk_ident("x1", 1, 2),
@@ -423,11 +454,12 @@ mod tests {
#[test]
fn test_parse_list_comprehension() {
let source = String::from("[x for y in z]");
let parse_ast = parse_expression(&source).unwrap();
let source = "[x for y in z]";
let parse_ast = parse_expression(source).unwrap();
assert_eq!(
parse_ast,
ast::Expression {
custom: (),
location: ast::Location::new(1, 1),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::List {
@@ -447,11 +479,12 @@ mod tests {
#[test]
fn test_parse_double_list_comprehension() {
let source = String::from("[x for y, y2 in z for a in b if a < 5 if a > 10]");
let parse_ast = parse_expression(&source).unwrap();
let source = "[x for y, y2 in z for a in b if a < 5 if a > 10]";
let parse_ast = parse_expression(source).unwrap();
assert_eq!(
parse_ast,
ast::Expression {
custom: (),
location: ast::Location::new(1, 1),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::List {
@@ -461,6 +494,7 @@ mod tests {
ast::Comprehension {
location: ast::Location::new(1, 4),
target: ast::Expression {
custom: (),
location: ast::Location::new(1, 8),
node: ast::ExpressionType::Tuple {
elements: vec![mk_ident("y", 1, 8), mk_ident("y2", 1, 11),],
@@ -476,6 +510,7 @@ mod tests {
iter: mk_ident("b", 1, 28),
ifs: vec![
ast::Expression {
custom: (),
location: ast::Location::new(1, 35),
node: ast::ExpressionType::Compare {
vals: vec![mk_ident("a", 1, 33), make_int(5, 1, 37),],
@@ -483,6 +518,7 @@ mod tests {
}
},
ast::Expression {
custom: (),
location: ast::Location::new(1, 44),
node: ast::ExpressionType::Compare {
vals: vec![mk_ident("a", 1, 42), make_int(10, 1, 46),],

View File

@@ -3,13 +3,12 @@
// See also: file:///usr/share/doc/python/html/reference/compound_stmts.html#function-definitions
// See also: https://greentreesnakes.readthedocs.io/en/latest/nodes.html#keyword
use std::iter::FromIterator;
use crate::ast;
use crate::fstring::parse_located_fstring;
use crate::function::{parse_args, parse_params};
use crate::error::LexicalError;
use crate::lexer;
use alloc::{boxed::Box, string::{String, ToString}, vec, vec::Vec};
use num_bigint::BigInt;
@@ -26,7 +25,7 @@ pub Top: ast::Top = {
Program: ast::Program = {
<lines:FileLine*> => ast::Program {
statements: Vec::from_iter(lines.into_iter().flatten())
statements: lines.into_iter().flatten().collect(),
},
};
@@ -69,6 +68,7 @@ PassStatement: ast::Statement = {
<location:@L> "pass" => {
ast::Statement {
location,
custom: (),
node: ast::StatementType::Pass,
}
},
@@ -78,6 +78,7 @@ DelStatement: ast::Statement = {
<location:@L> "del" <targets:ExpressionList2> => {
ast::Statement {
location,
custom: (),
node: ast::StatementType::Delete { targets },
}
},
@@ -88,6 +89,7 @@ ExpressionStatement: ast::Statement = {
// Just an expression, no assignment:
if suffix.is_empty() {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Expression { expression }
}
@@ -102,6 +104,7 @@ ExpressionStatement: ast::Statement = {
let value = values.into_iter().next().unwrap();
ast::Statement {
custom: (),
location,
node: ast::StatementType::Assign { targets, value },
}
@@ -109,6 +112,7 @@ ExpressionStatement: ast::Statement = {
},
<location:@L> <target:TestOrStarExprList> <op:AugAssign> <rhs:TestListOrYieldExpr> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::AugAssign {
target: Box::new(target),
@@ -119,6 +123,7 @@ ExpressionStatement: ast::Statement = {
},
<location:@L> <target:Test> ":" <annotation:Test> <rhs:AssignSuffix?> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::AnnAssign {
target: Box::new(target),
@@ -145,6 +150,7 @@ TestOrStarExprList: ast::Expression = {
} else {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Tuple { elements }
}
}
@@ -158,6 +164,7 @@ TestOrStarNamedExprList: ast::Expression = {
} else {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Tuple { elements }
}
}
@@ -193,24 +200,28 @@ AugAssign: ast::Operator = {
FlowStatement: ast::Statement = {
<location:@L> "break" => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Break,
}
},
<location:@L> "continue" => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Continue,
}
},
<location:@L> "return" <value:TestList?> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Return { value },
}
},
<location:@L> <expression:YieldExpr> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Expression { expression },
}
@@ -221,12 +232,14 @@ FlowStatement: ast::Statement = {
RaiseStatement: ast::Statement = {
<location:@L> "raise" => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Raise { exception: None, cause: None },
}
},
<location:@L> "raise" <t:Test> <c:("from" Test)?> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Raise { exception: Some(t), cause: c.map(|x| x.1) },
}
@@ -236,6 +249,7 @@ RaiseStatement: ast::Statement = {
ImportStatement: ast::Statement = {
<location:@L> "import" <names: OneOrMore<ImportAsAlias<DottedName>>> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Import { names },
}
@@ -243,6 +257,7 @@ ImportStatement: ast::Statement = {
<location:@L> "from" <source:ImportFromLocation> "import" <names: ImportAsNames> => {
let (level, module) = source;
ast::Statement {
custom: (),
location,
node: ast::StatementType::ImportFrom {
level,
@@ -298,6 +313,7 @@ DottedName: String = {
GlobalStatement: ast::Statement = {
<location:@L> "global" <names:OneOrMore<Identifier>> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Global { names }
}
@@ -307,6 +323,7 @@ GlobalStatement: ast::Statement = {
NonlocalStatement: ast::Statement = {
<location:@L> "nonlocal" <names:OneOrMore<Identifier>> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Nonlocal { names }
}
@@ -316,6 +333,7 @@ NonlocalStatement: ast::Statement = {
AssertStatement: ast::Statement = {
<location:@L> "assert" <test:Test> <msg: ("," Test)?> => {
ast::Statement {
custom: (),
location,
node: ast::StatementType::Assert {
test, msg: msg.map(|e| e.1)
@@ -342,6 +360,7 @@ IfStatement: ast::Statement = {
// handle elif:
for i in s2.into_iter().rev() {
let x = ast::Statement {
custom: (),
location: i.0,
node: ast::StatementType::If { test: i.2, body: i.4, orelse: last },
};
@@ -349,6 +368,7 @@ IfStatement: ast::Statement = {
}
ast::Statement {
custom: (),
location,
node: ast::StatementType::If { test, body, orelse: last }
}
@@ -359,6 +379,7 @@ WhileStatement: ast::Statement = {
<location:@L> "while" <test:NamedExpressionTest> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
let orelse = s2.map(|s| s.2);
ast::Statement {
custom: (),
location,
node: ast::StatementType::While {
test,
@@ -374,6 +395,7 @@ ForStatement: ast::Statement = {
let is_async = is_async.is_some();
let orelse = s2.map(|s| s.2);
ast::Statement {
custom: (),
location,
node: ast::StatementType::For {
is_async,
@@ -391,6 +413,7 @@ TryStatement: ast::Statement = {
let orelse = else_suite.map(|s| s.2);
let finalbody = finally.map(|s| s.2);
ast::Statement {
custom: (),
location,
node: ast::StatementType::Try {
body,
@@ -405,6 +428,7 @@ TryStatement: ast::Statement = {
let orelse = None;
let finalbody = Some(finally.2);
ast::Statement {
custom: (),
location,
node: ast::StatementType::Try {
body,
@@ -439,6 +463,7 @@ WithStatement: ast::Statement = {
<location:@L> <is_async:"async"?> "with" <items:OneOrMore<WithItem>> ":" <body:Suite> => {
let is_async = is_async.is_some();
ast::Statement {
custom: (),
location,
node: ast::StatementType::With { is_async, items, body },
}
@@ -456,6 +481,7 @@ FuncDef: ast::Statement = {
<decorator_list:Decorator*> <location:@L> <is_async:"async"?> "def" <name:Identifier> <args:Parameters> <r:("->" Test)?> ":" <body:Suite> => {
let is_async = is_async.is_some();
ast::Statement {
custom: (),
location,
node: ast::StatementType::FunctionDef {
is_async,
@@ -597,6 +623,7 @@ ClassDef: ast::Statement = {
None => (vec![], vec![]),
};
ast::Statement {
custom: (),
location,
node: ast::StatementType::ClassDef {
name,
@@ -612,11 +639,13 @@ ClassDef: ast::Statement = {
Path: ast::Expression = {
<location:@L> <n:Identifier> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Identifier { name: n }
},
<p:Path> <location:@L> "." <n:name> => {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Attribute {
value: Box::new(p),
name: n,
@@ -635,10 +664,12 @@ Decorator: ast::Expression = {
YieldExpr: ast::Expression = {
<location:@L> "yield" <value:TestList?> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Yield { value: value.map(Box::new) }
},
<location:@L> "yield" "from" <e:Test> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::YieldFrom { value: Box::new(e) }
},
};
@@ -648,6 +679,7 @@ Test: ast::Expression = {
if let Some(c) = condition {
ast::Expression {
location: c.0,
custom: (),
node: ast::ExpressionType::IfExpression {
test: Box::new(c.2),
body: Box::new(expr),
@@ -666,10 +698,12 @@ NamedExpressionTest: ast::Expression = {
if let Some(l) = left {
ast::Expression {
location: location,
custom: (),
node: ast::ExpressionType::NamedExpression {
left: Box::new(
ast::Expression {
location: location,
custom: (),
node: ast::ExpressionType::Identifier { name: l.0, },
}),
right: Box::new(right),
@@ -685,6 +719,7 @@ LambdaDef: ast::Expression = {
<location:@L> "lambda" <p:ParameterList<UntypedParameter>?> ":" <body:Test> =>
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Lambda {
args: Box::new(p.unwrap_or_default()),
body: Box::new(body)
@@ -701,6 +736,7 @@ OrTest: ast::Expression = {
values.extend(e2.into_iter().map(|e| e.1));
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::BoolOp { op: ast::BooleanOperator::Or, values }
}
}
@@ -716,6 +752,7 @@ AndTest: ast::Expression = {
values.extend(e2.into_iter().map(|e| e.1));
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::BoolOp { op: ast::BooleanOperator::And, values }
}
}
@@ -725,6 +762,7 @@ AndTest: ast::Expression = {
NotTest: ast::Expression = {
<location:@L> "not" <e:NotTest> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Unop { a: Box::new(e), op: ast::UnaryOperator::Not }
},
Comparison,
@@ -740,6 +778,7 @@ Comparison: ast::Expression = {
}
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Compare { vals, ops }
}
},
@@ -762,6 +801,7 @@ CompOp: ast::Comparison = {
Expression: ast::Expression = {
<e1:Expression> <location:@L> "|" <e2:XorExpression> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Binop { a: Box::new(e1), op: ast::Operator::BitOr, b: Box::new(e2) }
},
XorExpression,
@@ -770,6 +810,7 @@ Expression: ast::Expression = {
XorExpression: ast::Expression = {
<e1:XorExpression> <location:@L> "^" <e2:AndExpression> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Binop { a: Box::new(e1), op: ast::Operator::BitXor, b: Box::new(e2) }
},
AndExpression,
@@ -778,6 +819,7 @@ XorExpression: ast::Expression = {
AndExpression: ast::Expression = {
<e1:AndExpression> <location:@L> "&" <e2:ShiftExpression> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Binop { a: Box::new(e1), op: ast::Operator::BitAnd, b: Box::new(e2) }
},
ShiftExpression,
@@ -786,6 +828,7 @@ AndExpression: ast::Expression = {
ShiftExpression: ast::Expression = {
<e1:ShiftExpression> <location:@L> <op:ShiftOp> <e2:ArithmaticExpression> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Binop { a: Box::new(e1), op, b: Box::new(e2) }
},
ArithmaticExpression,
@@ -799,6 +842,7 @@ ShiftOp: ast::Operator = {
ArithmaticExpression: ast::Expression = {
<a:ArithmaticExpression> <location:@L> <op:AddOp> <b:Term> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Binop { a: Box::new(a), op, b: Box::new(b) }
},
Term,
@@ -812,6 +856,7 @@ AddOp: ast::Operator = {
Term: ast::Expression = {
<a:Term> <location:@L> <op:MulOp> <b:Factor> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Binop { a: Box::new(a), op, b: Box::new(b) }
},
Factor,
@@ -828,6 +873,7 @@ MulOp: ast::Operator = {
Factor: ast::Expression = {
<location:@L> <op:UnOp> <e:Factor> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Unop { a: Box::new(e), op }
},
Power,
@@ -845,6 +891,7 @@ Power: ast::Expression = {
None => e,
Some((location, _, b)) => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Binop { a: Box::new(e), op: ast::Operator::Pow, b: Box::new(b) }
},
}
@@ -856,6 +903,7 @@ AtomExpr: ast::Expression = {
if is_await.is_some() {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Await { value: Box::new(atom) }
}
} else {
@@ -869,15 +917,18 @@ AtomExpr2: ast::Expression = {
<f:AtomExpr2> <location:@L> "(" <a:ArgumentList> ")" => {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Call { function: Box::new(f), args: a.args, keywords: a.keywords }
}
},
<e:AtomExpr2> <location:@L> "[" <s:SubscriptList> "]" => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Subscript { a: Box::new(e), b: Box::new(s) }
},
<e:AtomExpr2> <location:@L> "." <name:Identifier> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Attribute { value: Box::new(e), name }
},
};
@@ -894,6 +945,7 @@ SubscriptList: ast::Expression = {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Tuple { elements: dims },
}
}
@@ -903,47 +955,54 @@ SubscriptList: ast::Expression = {
Subscript: ast::Expression = {
Test,
<e1:Test?> <location:@L> ":" <e2:Test?> <e3:SliceOp?> => {
let s1 = e1.unwrap_or(ast::Expression { location, node: ast::ExpressionType::None });
let s2 = e2.unwrap_or(ast::Expression { location, node: ast::ExpressionType::None });
let s3 = e3.unwrap_or(ast::Expression { location, node: ast::ExpressionType::None });
let s1 = e1.unwrap_or(ast::Expression { location, custom: (), node: ast::ExpressionType::None });
let s2 = e2.unwrap_or(ast::Expression { location, custom: (), node: ast::ExpressionType::None });
let s3 = e3.unwrap_or(ast::Expression { location, custom: (), node: ast::ExpressionType::None });
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Slice { elements: vec![s1, s2, s3] }
}
}
};
SliceOp: ast::Expression = {
<location:@L> ":" <e:Test?> => e.unwrap_or(ast::Expression {location, node: ast::ExpressionType::None})
<location:@L> ":" <e:Test?> => e.unwrap_or(ast::Expression {location, custom: (), node: ast::ExpressionType::None})
}
Atom: ast::Expression = {
<location:@L> <value:StringGroup> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::String { value }
},
<location:@L> <value:Bytes> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Bytes { value }
},
<location:@L> <value:Number> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Number { value }
},
<location:@L> <name:Identifier> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Identifier { name }
},
<location:@L> "[" <e:ListLiteralValues?> "]" => {
let elements = e.unwrap_or_default();
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::List { elements }
}
},
<location:@L> "[" <element:TestOrStarNamedExpr> <generators:CompFor> "]" => {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::List { element }),
generators,
@@ -953,6 +1012,7 @@ Atom: ast::Expression = {
<location:@L> "(" <elements:TestOrStarNamedExprList?> ")" => {
elements.unwrap_or(ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Tuple { elements: Vec::new() }
})
},
@@ -960,6 +1020,7 @@ Atom: ast::Expression = {
<location:@L> "(" <element:Test> <generators:CompFor> ")" => {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::GeneratorExpression { element }),
generators,
@@ -968,11 +1029,13 @@ Atom: ast::Expression = {
},
<location:@L> "{" <e:DictLiteralValues?> "}" => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Dict { elements: e.unwrap_or_default() }
},
<location:@L> "{" <e1:DictEntry> <generators:CompFor> "}" => {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::Dict { key: e1.0, value: e1.1 }),
generators,
@@ -981,21 +1044,23 @@ Atom: ast::Expression = {
},
<location:@L> "{" <elements:SetLiteralValues> "}" => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Set { elements }
},
<location:@L> "{" <element:Test> <generators:CompFor> "}" => {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::Set { element }),
generators,
}
}
},
<location:@L> "True" => ast::Expression { location, node: ast::ExpressionType::True },
<location:@L> "False" => ast::Expression { location, node: ast::ExpressionType::False },
<location:@L> "None" => ast::Expression { location, node: ast::ExpressionType::None },
<location:@L> "..." => ast::Expression { location, node: ast::ExpressionType::Ellipsis },
<location:@L> "True" => ast::Expression { location, custom: (), node: ast::ExpressionType::True },
<location:@L> "False" => ast::Expression { location, custom: (), node: ast::ExpressionType::False },
<location:@L> "None" => ast::Expression { location, custom: (), node: ast::ExpressionType::None },
<location:@L> "..." => ast::Expression { location, custom: (), node: ast::ExpressionType::Ellipsis },
};
ListLiteralValues: Vec<ast::Expression> = {
@@ -1031,6 +1096,7 @@ ExpressionList: ast::Expression = {
} else {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Tuple { elements },
}
}
@@ -1052,6 +1118,7 @@ TestList: ast::Expression = {
} else {
ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Tuple { elements },
}
}
@@ -1062,6 +1129,7 @@ TestList: ast::Expression = {
StarExpr: ast::Expression = {
<location:@L> "*" <e:Expression> => ast::Expression {
location,
custom: (),
node: ast::ExpressionType::Starred { value: Box::new(e) },
}
};
@@ -1091,6 +1159,7 @@ FunctionArgument: (Option<Option<String>>, ast::Expression) = {
let expr = match c {
Some(c) => ast::Expression {
location: e.location,
custom: (),
node: ast::ExpressionType::Comprehension {
kind: Box::new(ast::ComprehensionKind::GeneratorExpression { element: e }),
generators: c,
@@ -1101,7 +1170,7 @@ FunctionArgument: (Option<Option<String>>, ast::Expression) = {
(None, expr)
},
<i:Identifier> "=" <e:Test> => (Some(Some(i)), e),
<location:@L> "*" <e:Test> => (None, ast::Expression { location, node: ast::ExpressionType::Starred { value: Box::new(e) } }),
<location:@L> "*" <e:Test> => (None, ast::Expression { location, custom: (), node: ast::ExpressionType::Starred { value: Box::new(e) } }),
"**" <e:Test> => (Some(None), e),
};

View File

@@ -1,7 +1,8 @@
//! Different token definitions.
//! Loosely based on token.h from CPython source:
use alloc::{string::String, vec::Vec};
use core::fmt::{self, Write};
use num_bigint::BigInt;
use std::fmt::{self, Write};
/// Python source code can be tokenized in a sequence of these tokens.
#[derive(Clone, Debug, PartialEq)]
@@ -124,13 +125,11 @@ impl fmt::Display for Tok {
write!(f, "b\"")?;
for i in value {
match i {
0..=8 => write!(f, "\\x0{}", i)?,
9 => f.write_str("\\t")?,
10 => f.write_str("\\n")?,
11 => write!(f, "\\x0{:x}", i)?,
13 => f.write_str("\\r")?,
32..=126 => f.write_char(*i as char)?,
_ => write!(f, "\\x{:x}", i)?,
_ => write!(f, "\\x{:02x}", i)?,
}
}
f.write_str("\"")

View File

@@ -297,15 +297,18 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
/// Create settings by examining command line arguments and environment
/// variables.
fn create_settings(matches: &ArgMatches) -> PySettings {
let mut settings = PySettings::default();
settings.isolated = matches.is_present("isolate");
settings.ignore_environment = matches.is_present("ignore-environment");
let mut settings = PySettings {
isolated: matches.is_present("isolate"),
ignore_environment: matches.is_present("ignore-environment"),
interactive: !matches.is_present("c")
&& !matches.is_present("m")
&& (!matches.is_present("script") || matches.is_present("inspect")),
bytes_warning: matches.occurrences_of("bytes-warning"),
no_site: matches.is_present("no-site"),
..Default::default()
};
let ignore_environment = settings.ignore_environment || settings.isolated;
settings.interactive = !matches.is_present("c")
&& !matches.is_present("m")
&& (!matches.is_present("script") || matches.is_present("inspect"));
// add the current directory to sys.path
settings.path_list.push("".to_owned());
@@ -352,10 +355,6 @@ fn create_settings(matches: &ArgMatches) -> PySettings {
}
}
settings.bytes_warning = matches.occurrences_of("bytes-warning");
settings.no_site = matches.is_present("no-site");
if matches.is_present("no-user-site")
|| matches.is_present("isolate")
|| (!ignore_environment && env::var_os("PYTHONNOUSERSITE").is_some())
@@ -510,7 +509,7 @@ fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> {
vm.get_attribute(vm.sys_module.clone(), "modules")?
.set_item("__main__", main_module, vm)?;
let site_result = vm.import("site", &[], 0);
let site_result = vm.import("site", None, 0);
if site_result.is_err() {
warn!(
@@ -559,7 +558,7 @@ fn run_command(vm: &VirtualMachine, scope: Scope, source: String) -> PyResult<()
fn run_module(vm: &VirtualMachine, module: &str) -> PyResult<()> {
debug!("Running module {}", module);
let runpy = vm.import("runpy", &[], 0)?;
let runpy = vm.import("runpy", None, 0)?;
let run_module_as_main = vm.get_attribute(runpy, "_run_module_as_main")?;
vm.invoke(&run_module_as_main, (module,))?;
Ok(())

View File

@@ -9,13 +9,14 @@ edition = "2018"
include = ["src/**/*.rs", "Cargo.toml", "build.rs", "Lib/**/*.py"]
[features]
default = ["compile-parse", "threading"]
default = ["compile-parse", "threading", "std"]
vm-tracing-logging = []
flame-it = ["flame", "flamer"]
freeze-stdlib = ["rustpython-pylib"]
jit = ["rustpython-jit"]
threading = ["rustpython-common/threading"]
compile-parse = ["rustpython-parser", "rustpython-compiler"]
std = ["rustpython-compiler/std"] # enables compiler-core/std, parser/std, etc
ssl = ["openssl", "openssl-sys", "openssl-probe"]
@@ -34,10 +35,10 @@ num-traits = "0.2.8"
num-integer = "0.1.41"
num-rational = "0.3"
num-iter = "0.1.39"
rand = { version = "0.7", features = ["wasm-bindgen"] }
rand_core = "0.5"
getrandom = { version = "0.1", features = ["wasm-bindgen"] }
mt19937 = "1.0"
rand = "0.8"
rand_core = "0.6"
getrandom = { version = "0.2", features = ["js"] }
mt19937 = "2.0"
log = "0.4"
rustpython-derive = { path = "../derive", version = "0.1.2" }
rustpython-parser = { path = "../parser", optional = true, version = "0.1.2" }
@@ -47,10 +48,9 @@ rustpython-jit = { path = "../jit", optional = true, version = "0.1.2" }
rustpython-pylib = { path = "pylib-crate", optional = true, version = "0.1.0" }
serde = { version = "1.0.66", features = ["derive"] }
serde_json = "1.0"
byteorder = "1.2.6"
regex = "1"
rustc_version_runtime = "0.1.*"
statrs = "0.12.0"
puruspe = "0.1"
caseless = "0.2.1"
chrono = { version = "0.4", features = ["wasmbind"] }
lexical-core = "0.7"
@@ -58,12 +58,11 @@ itertools = "0.9"
hex = "0.4.0"
hexf-parse = "0.1.0"
indexmap = "1.0.2"
ahash = "0.6"
crc = "^1.0.0"
maplit = "1.0"
bitflags = "1.2.1"
libc = "0.2"
nix = "0.18"
arr_macro = "0.1.2"
csv = "1.1.1"
paste = "0.1"
base64 = "0.13"
@@ -80,6 +79,7 @@ timsort = "0.1"
thiserror = "1.0"
atty = "0.2"
static_assertions = "1.1"
half = "1.6"
## unicode stuff
unicode_names2 = "0.4"
@@ -107,7 +107,7 @@ uname = "0.1.1"
crc32fast = "1.2.0"
adler32 = "1.0.3"
gethostname = "0.2.0"
socket2 = "0.3"
socket2 = "0.3.19"
rustyline = "6.0"
openssl = { version = "0.10", features = ["vendored"], optional = true }
openssl-sys = { version = "0.9", optional = true }

View File

@@ -2,16 +2,11 @@
//! common way to use this crate is to just add the `"freeze-stdlib"` feature to `rustpython-vm`,
//! in order to automatically include the python part of the standard library into the binary.
extern crate self as rustpython_pylib;
pub const LIB_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/Lib");
#[cfg(feature = "compiled-bytecode")]
use {
rustpython_bytecode::bytecode::{self, FrozenModule},
std::collections::HashMap,
};
use {rustpython_bytecode::FrozenModule, std::collections::HashMap};
#[cfg(feature = "compiled-bytecode")]
pub fn frozen_stdlib() -> HashMap<String, FrozenModule> {
rustpython_derive::py_freeze!(dir = "Lib", crate_name = "rustpython_pylib")
rustpython_derive::py_freeze!(dir = "Lib", crate_name = "rustpython_bytecode")
}

View File

@@ -9,26 +9,15 @@ use num_traits::{cast::ToPrimitive, sign::Signed};
use std::str::FromStr;
#[derive(FromArgs)]
pub struct SplitArgs<'a, T, S, E>
where
T: TryFromObject + AnyStrWrapper<S>,
S: ?Sized + AnyStr<'a, E>,
E: Copy,
{
pub struct SplitArgs<'s, T: TryFromObject + AnyStrWrapper<'s>> {
#[pyarg(any, default)]
sep: Option<T>,
#[pyarg(any, default = "-1")]
maxsplit: isize,
_phantom1: std::marker::PhantomData<&'a S>,
_phantom2: std::marker::PhantomData<E>,
_phantom: std::marker::PhantomData<&'s ()>,
}
impl<'a, T, S, E> SplitArgs<'a, T, S, E>
where
T: TryFromObject + AnyStrWrapper<S>,
S: ?Sized + AnyStr<'a, E>,
E: Copy,
{
impl<'s, T: TryFromObject + AnyStrWrapper<'s>> SplitArgs<'s, T> {
pub fn get_value(self, vm: &VirtualMachine) -> PyResult<(Option<T>, isize)> {
let sep = if let Some(s) = self.sep {
let sep = s.as_ref();
@@ -124,11 +113,9 @@ impl StringRange for std::ops::Range<usize> {
}
}
pub trait AnyStrWrapper<S>
where
S: ?Sized,
{
fn as_ref(&self) -> &S;
pub trait AnyStrWrapper<'s> {
type Str: ?Sized + AnyStr<'s>;
fn as_ref(&self) -> &Self::Str;
}
pub trait AnyStrContainer<S>
@@ -140,28 +127,23 @@ where
fn push_str(&mut self, s: &S);
}
pub trait AnyStr<'s, E>
where
E: Copy,
Self: 's,
Self::Container: AnyStrContainer<Self> + std::iter::Extend<E>,
Self::CharIter: 's + std::iter::Iterator<Item = char>,
Self::ElementIter: 's + std::iter::Iterator<Item = E>,
{
type Container;
type CharIter;
type ElementIter;
// TODO: GATs for `'s` once stabilized
pub trait AnyStr<'s>: 's {
type Char: Copy;
type Container: AnyStrContainer<Self> + Extend<Self::Char>;
type CharIter: Iterator<Item = char> + 's;
type ElementIter: Iterator<Item = Self::Char> + 's;
fn element_bytes_len(c: E) -> usize;
fn element_bytes_len(c: Self::Char) -> usize;
fn to_container(&self) -> Self::Container;
fn as_bytes(&self) -> &[u8];
fn as_utf8_str(&self) -> Result<&str, std::str::Utf8Error>;
fn chars(&'s self) -> Self::CharIter;
fn elements(&'s self) -> Self::ElementIter;
fn get_bytes<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self;
fn get_bytes(&self, range: std::ops::Range<usize>) -> &Self;
// FIXME: get_chars is expensive for str
fn get_chars<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self;
fn get_chars(&self, range: std::ops::Range<usize>) -> &Self;
fn bytes_len(&self) -> usize;
// fn chars_len(&self) -> usize; // cannot access to cache here
fn is_empty(&self) -> bool;
@@ -175,14 +157,14 @@ where
fn py_split<T, SP, SN, SW, R>(
&self,
args: SplitArgs<'s, T, Self, E>,
args: SplitArgs<'s, T>,
vm: &VirtualMachine,
split: SP,
splitn: SN,
splitw: SW,
) -> PyResult<Vec<R>>
where
T: TryFromObject + AnyStrWrapper<Self>,
T: TryFromObject + AnyStrWrapper<'s, Str = Self>,
SP: Fn(&Self, &Self, &VirtualMachine) -> Vec<R>,
SN: Fn(&Self, &Self, usize, &VirtualMachine) -> Vec<R>,
SW: Fn(&Self, isize, &VirtualMachine) -> Vec<R>,
@@ -249,7 +231,7 @@ where
func_default: FD,
) -> &'a Self
where
S: AnyStrWrapper<Self>,
S: AnyStrWrapper<'s, Str = Self>,
FC: Fn(&'a Self, &Self) -> &'a Self,
FD: Fn(&'a Self) -> &'a Self,
{
@@ -286,7 +268,7 @@ where
}
}
fn py_pad(&self, left: usize, right: usize, fillchar: E) -> Self::Container {
fn py_pad(&self, left: usize, right: usize, fillchar: Self::Char) -> Self::Container {
let mut u = Self::Container::with_capacity(
(left + right) * Self::element_bytes_len(fillchar) + self.bytes_len(),
);
@@ -296,23 +278,23 @@ where
u
}
fn py_center(&self, width: usize, fillchar: E, len: usize) -> Self::Container {
fn py_center(&self, width: usize, fillchar: Self::Char, len: usize) -> Self::Container {
let marg = width - len;
let left = marg / 2 + (marg & width & 1);
self.py_pad(left, marg - left, fillchar)
}
fn py_ljust(&self, width: usize, fillchar: E, len: usize) -> Self::Container {
fn py_ljust(&self, width: usize, fillchar: Self::Char, len: usize) -> Self::Container {
self.py_pad(0, width - len, fillchar)
}
fn py_rjust(&self, width: usize, fillchar: E, len: usize) -> Self::Container {
fn py_rjust(&self, width: usize, fillchar: Self::Char, len: usize) -> Self::Container {
self.py_pad(width - len, 0, fillchar)
}
fn py_join<'a>(
&self,
mut iter: PyIterator<'a, impl AnyStrWrapper<Self> + TryFromObject>,
mut iter: PyIterator<'a, impl AnyStrWrapper<'s, Str = Self> + TryFromObject>,
) -> PyResult<Self::Container> {
let mut joined = if let Some(elem) = iter.next() {
elem?.as_ref().to_container()

View File

@@ -1,11 +1,12 @@
use super::code::PyCodeRef;
use super::pystr::PyStrRef;
use super::pytype::PyTypeRef;
use crate::coroutine::{Coro, Variant};
use crate::exceptions::PyBaseExceptionRef;
use crate::frame::FrameRef;
use crate::function::OptionalArg;
use crate::pyobject::{
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::slots::PyIter;
use crate::vm::VirtualMachine;
@@ -32,17 +33,27 @@ impl PyAsyncGen {
&self.inner
}
pub fn new(frame: FrameRef, vm: &VirtualMachine) -> PyRef<Self> {
pub fn new(frame: FrameRef, name: PyStrRef) -> Self {
PyAsyncGen {
inner: Coro::new(frame, Variant::AsyncGen),
inner: Coro::new(frame, Variant::AsyncGen, name),
running_async: AtomicCell::new(false),
}
.into_ref(vm)
}
// TODO: fix function names situation
#[pyproperty(magic)]
fn name(&self) {}
fn name(&self) -> PyStrRef {
self.inner.name()
}
#[pyproperty(magic, setter)]
fn set_name(&self, name: PyStrRef) {
self.inner.set_name(name)
}
#[pymethod(magic)]
fn repr(zelf: PyRef<Self>) -> String {
zelf.inner.repr(zelf.get_id())
}
#[pymethod(name = "__aiter__")]
fn aiter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {

View File

@@ -13,15 +13,15 @@ use crate::vm::VirtualMachine;
pub struct PyNativeFuncDef {
pub func: PyNativeFunc,
pub name: Option<PyStrRef>,
pub name: PyStrRef,
pub doc: Option<PyStrRef>,
}
impl From<PyNativeFunc> for PyNativeFuncDef {
fn from(func: PyNativeFunc) -> Self {
impl PyNativeFuncDef {
pub fn new(func: PyNativeFunc, name: PyStrRef) -> Self {
Self {
func,
name: None,
name,
doc: None,
}
}
@@ -70,19 +70,10 @@ impl PyValue for PyBuiltinFunction {
impl fmt::Debug for PyBuiltinFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match &self.value.name {
Some(s) => s.borrow_value(),
None => "<unknown name>",
};
write!(f, "builtin function {}", name)
write!(f, "builtin function {}", self.value.name.borrow_value())
}
}
impl From<PyNativeFunc> for PyBuiltinFunction {
fn from(value: PyNativeFunc) -> Self {
PyNativeFuncDef::from(value).into()
}
}
impl From<PyNativeFuncDef> for PyBuiltinFunction {
fn from(value: PyNativeFuncDef) -> Self {
Self {
@@ -124,7 +115,7 @@ impl PyBuiltinFunction {
vm.unwrap_or_none(self.module.clone())
}
#[pyproperty(magic)]
fn name(&self) -> Option<PyStrRef> {
fn name(&self) -> PyStrRef {
self.value.name.clone()
}
#[pyproperty(magic)]
@@ -184,7 +175,7 @@ impl Callable for PyBuiltinMethod {
#[pyimpl(with(SlotDescriptor, Callable))]
impl PyBuiltinMethod {
#[pyproperty(magic)]
fn name(&self) -> Option<PyStrRef> {
fn name(&self) -> PyStrRef {
self.value.name.clone()
}
#[pyproperty(magic)]

View File

@@ -93,7 +93,7 @@ pub(crate) fn init(context: &PyContext) {
PyByteArray::extend_class(context, &context.types.bytearray_type);
let bytearray_type = &context.types.bytearray_type;
extend_class!(context, bytearray_type, {
"maketrans" => context.new_method(PyBytesInner::maketrans),
"maketrans" => context.new_method("maketrans", PyBytesInner::maketrans),
});
PyByteArrayIterator::extend_class(context, &context.types.bytearray_iterator_type);
@@ -545,11 +545,11 @@ impl PyByteArray {
}
#[pymethod(name = "splitlines")]
fn splitlines(&self, options: anystr::SplitLinesArgs, vm: &VirtualMachine) -> PyResult {
fn splitlines(&self, options: anystr::SplitLinesArgs, vm: &VirtualMachine) -> PyObjectRef {
let lines = self
.borrow_value()
.splitlines(options, |x| vm.ctx.new_bytearray(x.to_vec()));
Ok(vm.ctx.new_list(lines))
vm.ctx.new_list(lines)
}
#[pymethod(name = "zfill")]
@@ -607,9 +607,8 @@ impl PyByteArray {
}
#[pymethod(name = "reverse")]
fn reverse(&self) -> PyResult<()> {
fn reverse(&self) {
self.borrow_value_mut().elements.reverse();
Ok(())
}
#[pymethod]

View File

@@ -91,7 +91,7 @@ pub(crate) fn init(context: &PyContext) {
PyBytes::extend_class(context, &context.types.bytes_type);
let bytes_type = &context.types.bytes_type;
extend_class!(context, bytes_type, {
"maketrans" => context.new_method(PyBytesInner::maketrans),
"maketrans" => context.new_method("maketrans", PyBytesInner::maketrans),
});
PyBytesIterator::extend_class(context, &context.types.bytes_iterator_type);
}
@@ -118,8 +118,8 @@ impl PyBytes {
}
#[pymethod(name = "__sizeof__")]
fn sizeof(&self) -> PyResult<usize> {
Ok(size_of::<Self>() + self.inner.elements.len() * size_of::<u8>())
fn sizeof(&self) -> usize {
size_of::<Self>() + self.inner.elements.len() * size_of::<u8>()
}
#[pymethod(name = "__add__")]
@@ -387,11 +387,11 @@ impl PyBytes {
}
#[pymethod(name = "splitlines")]
fn splitlines(&self, options: anystr::SplitLinesArgs, vm: &VirtualMachine) -> PyResult {
fn splitlines(&self, options: anystr::SplitLinesArgs, vm: &VirtualMachine) -> PyObjectRef {
let lines = self
.inner
.splitlines(options, |x| vm.ctx.new_bytes(x.to_vec()));
Ok(vm.ctx.new_list(lines))
vm.ctx.new_list(lines)
}
#[pymethod(name = "zfill")]

View File

@@ -206,7 +206,7 @@ impl PyCodeRef {
fn repr(self) -> String {
let code = &self.code;
format!(
"<code object {} at 0x{:x} file {:?}, line {}>",
"<code object {} at {:#x} file {:?}, line {}>",
code.obj_name,
self.get_id(),
code.source_path,
@@ -225,7 +225,7 @@ impl PyCodeRef {
}
#[pyproperty]
fn co_filename(self) -> String {
fn co_filename(self) -> PyStrRef {
self.code.source_path.clone()
}
@@ -246,7 +246,7 @@ impl PyCodeRef {
}
#[pyproperty]
fn co_name(self) -> String {
fn co_name(self) -> PyStrRef {
self.code.obj_name.clone()
}
@@ -267,6 +267,12 @@ impl PyCodeRef {
}
}
impl fmt::Display for PyCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
pub fn init(ctx: &PyContext) {
PyCodeRef::extend_class(ctx, &ctx.types.code_type);
}

View File

@@ -435,7 +435,7 @@ fn try_complex(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<(Compl
if let Some(complex) = obj.payload_if_subclass::<PyComplex>(vm) {
return Ok(Some((complex.value, true)));
}
if let Some(float) = float::try_float(obj, vm)? {
if let Some(float) = float::try_float_opt(obj, vm)? {
return Ok(Some((Complex64::new(float, 0.0), false)));
}
Ok(None)

View File

@@ -4,7 +4,7 @@ use super::pytype::PyTypeRef;
use crate::coroutine::{Coro, Variant};
use crate::frame::FrameRef;
use crate::function::OptionalArg;
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::pyobject::{IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::slots::PyIter;
use crate::vm::VirtualMachine;
@@ -28,17 +28,25 @@ impl PyCoroutine {
&self.inner
}
pub fn new(frame: FrameRef, vm: &VirtualMachine) -> PyRef<Self> {
pub fn new(frame: FrameRef, name: PyStrRef) -> Self {
PyCoroutine {
inner: Coro::new(frame, Variant::Coroutine),
inner: Coro::new(frame, Variant::Coroutine, name),
}
.into_ref(vm)
}
// TODO: fix function names situation
#[pyproperty(magic)]
fn name(&self, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.none()
fn name(&self) -> PyStrRef {
self.inner.name()
}
#[pyproperty(magic, setter)]
fn set_name(&self, name: PyStrRef) {
self.inner.set_name(name)
}
#[pymethod(magic)]
fn repr(zelf: PyRef<Self>) -> String {
zelf.inner.repr(zelf.get_id())
}
#[pymethod]

View File

@@ -450,7 +450,7 @@ impl PyDictRef {
/// Take a python dictionary and convert it to attributes.
pub fn to_attributes(self) -> PyAttributes {
let mut attrs = PyAttributes::new();
let mut attrs = PyAttributes::default();
for (key, value) in self {
let key = pystr::clone_value(&key);
attrs.insert(key, value);

View File

@@ -55,7 +55,7 @@ impl From<f64> for PyFloat {
}
}
pub(crate) fn try_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<f64>> {
pub fn try_float_opt(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<f64>> {
if let Some(float) = obj.payload_if_exact::<PyFloat>(vm) {
return Ok(Some(float.value));
}
@@ -76,6 +76,11 @@ pub(crate) fn try_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Opti
Ok(None)
}
pub fn try_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
try_float_opt(obj, vm)?
.ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", obj.class().name)))
}
pub(crate) fn to_op_float(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<f64>> {
let v = if let Some(float) = obj.payload_if_subclass::<PyFloat>(vm) {
Some(float.value)
@@ -176,7 +181,7 @@ impl PyFloat {
val
};
if let Some(f) = try_float(&val, vm)? {
if let Some(f) = try_float_opt(&val, vm)? {
f
} else if let Some(s) = val.payload_if_subclass::<PyStr>(vm) {
float_ops::parse_str(s.borrow_value().trim()).ok_or_else(|| {
@@ -555,7 +560,7 @@ impl Hashable for PyFloat {
pub type PyFloatRef = PyRef<PyFloat>;
// Retrieve inner float value:
pub fn get_value(obj: &PyObjectRef) -> f64 {
pub(crate) fn get_value(obj: &PyObjectRef) -> f64 {
obj.payload::<PyFloat>().unwrap().value
}
@@ -581,9 +586,7 @@ impl IntoPyFloat {
impl TryFromObject for IntoPyFloat {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let value = try_float(&obj, vm)?.ok_or_else(|| {
vm.new_type_error(format!("must be real number, not {}", obj.class().name))
})?;
let value = try_float(&obj, vm)?;
Ok(IntoPyFloat { value })
}
}

View File

@@ -73,7 +73,7 @@ impl FrameRef {
}
#[pyproperty]
fn f_lasti(self) -> usize {
fn f_lasti(self) -> u32 {
self.lasti()
}

View File

@@ -40,6 +40,7 @@ pub struct PyFunction {
closure: Option<PyTupleTyped<PyCellRef>>,
defaults: Option<PyTupleRef>,
kw_only_defaults: Option<PyDictRef>,
name: PyMutex<PyStrRef>,
}
impl PyFunction {
@@ -50,6 +51,7 @@ impl PyFunction {
defaults: Option<PyTupleRef>,
kw_only_defaults: Option<PyDictRef>,
) -> Self {
let name = PyMutex::new(code.obj_name.clone());
PyFunction {
code,
#[cfg(feature = "jit")]
@@ -58,6 +60,7 @@ impl PyFunction {
closure,
defaults,
kw_only_defaults,
name,
}
}
@@ -281,9 +284,9 @@ impl PyFunction {
let is_gen = code.flags.contains(bytecode::CodeFlags::IS_GENERATOR);
let is_coro = code.flags.contains(bytecode::CodeFlags::IS_COROUTINE);
match (is_gen, is_coro) {
(true, false) => Ok(PyGenerator::new(frame, vm).into_object()),
(false, true) => Ok(PyCoroutine::new(frame, vm).into_object()),
(true, true) => Ok(PyAsyncGen::new(frame, vm).into_object()),
(true, false) => Ok(PyGenerator::new(frame, self.name()).into_object(vm)),
(false, true) => Ok(PyCoroutine::new(frame, self.name()).into_object(vm)),
(true, true) => Ok(PyAsyncGen::new(frame, self.name()).into_object(vm)),
(false, false) => vm.run_frame_full(frame),
}
}
@@ -321,6 +324,21 @@ impl PyFunction {
self.globals.clone()
}
#[pyproperty(magic)]
fn name(&self) -> PyStrRef {
self.name.lock().clone()
}
#[pyproperty(magic, setter)]
fn set_name(&self, name: PyStrRef) {
*self.name.lock() = name;
}
#[pymethod(magic)]
fn repr(zelf: PyRef<Self>) -> String {
format!("<function {} at {:#x}>", zelf.name.lock(), zelf.get_id())
}
#[cfg(feature = "jit")]
#[pymethod(magic)]
fn jit(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<()> {

View File

@@ -3,11 +3,12 @@
*/
use super::code::PyCodeRef;
use super::pystr::PyStrRef;
use super::pytype::PyTypeRef;
use crate::coroutine::{Coro, Variant};
use crate::frame::FrameRef;
use crate::function::OptionalArg;
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::pyobject::{IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::slots::PyIter;
use crate::vm::VirtualMachine;
@@ -29,17 +30,25 @@ impl PyGenerator {
&self.inner
}
pub fn new(frame: FrameRef, vm: &VirtualMachine) -> PyRef<Self> {
pub fn new(frame: FrameRef, name: PyStrRef) -> Self {
PyGenerator {
inner: Coro::new(frame, Variant::Gen),
inner: Coro::new(frame, Variant::Gen, name),
}
.into_ref(vm)
}
// TODO: fix function names situation
#[pyproperty(magic)]
fn name(&self, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.none()
fn name(&self) -> PyStrRef {
self.inner.name()
}
#[pyproperty(magic, setter)]
fn set_name(&self, name: PyStrRef) {
self.inner.set_name(name)
}
#[pymethod(magic)]
fn repr(zelf: PyRef<Self>) -> String {
zelf.inner.repr(zelf.get_id())
}
#[pymethod]

View File

@@ -570,11 +570,8 @@ impl PyInt {
}
#[pymethod(name = "as_integer_ratio")]
fn as_integer_ratio(&self, vm: &VirtualMachine) -> PyResult {
Ok(vm.ctx.new_tuple(vec![
vm.ctx.new_bigint(&self.value),
vm.ctx.new_bigint(&BigInt::one()),
]))
fn as_integer_ratio(&self, vm: &VirtualMachine) -> (PyObjectRef, BigInt) {
(vm.ctx.new_bigint(&self.value), BigInt::one())
}
#[pymethod]
@@ -888,7 +885,7 @@ fn detect_base(c: &u8) -> Option<u32> {
}
// Retrieve inner int value:
pub fn get_value(obj: &PyObjectRef) -> &BigInt {
pub(crate) fn get_value(obj: &PyObjectRef) -> &BigInt {
&obj.payload::<PyInt>().unwrap().value
}
@@ -911,7 +908,7 @@ pub(crate) fn try_int(obj: &PyObjectRef, vm: &VirtualMachine) -> PyResult<BigInt
vm.to_repr(obj)?,
))),
}
};
}
// test for strings and bytes
if let Some(s) = obj.downcast_ref::<PyStr>() {

View File

@@ -117,13 +117,13 @@ impl PyList {
}
#[pymethod(name = "__iadd__")]
fn iadd(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn iadd(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
if let Ok(new_elements) = vm.extract_elements(&other) {
let mut e = new_elements;
zelf.borrow_value_mut().append(&mut e);
Ok(zelf.into_object())
zelf.into_object()
} else {
Ok(vm.ctx.not_implemented())
vm.ctx.not_implemented()
}
}

View File

@@ -103,11 +103,11 @@ mod decl {
#[derive(FromArgs)]
#[allow(dead_code)]
struct CompileArgs {
#[pyarg(positional)]
#[pyarg(any)]
source: Either<PyStrRef, PyBytesRef>,
#[pyarg(positional)]
#[pyarg(any)]
filename: PyStrRef,
#[pyarg(positional)]
#[pyarg(any)]
mode: PyStrRef,
#[pyarg(any, optional)]
flags: OptionalArg<PyIntRef>,
@@ -320,8 +320,8 @@ mod decl {
}
#[pyfunction]
fn globals(vm: &VirtualMachine) -> PyResult<PyDictRef> {
Ok(vm.current_globals().clone())
fn globals(vm: &VirtualMachine) -> PyDictRef {
vm.current_globals().clone()
}
#[pyfunction]
@@ -341,15 +341,9 @@ mod decl {
// builtin_help
#[pyfunction]
fn hex(number: PyIntRef, vm: &VirtualMachine) -> PyResult {
fn hex(number: PyIntRef) -> String {
let n = number.borrow_value();
let s = if n.is_negative() {
format!("-0x{:x}", -n)
} else {
format!("0x{:x}", n)
};
Ok(vm.ctx.new_str(s))
format!("{:#x}", n)
}
#[pyfunction]

View File

@@ -23,6 +23,7 @@ use crossbeam_utils::atomic::AtomicCell;
use itertools::Itertools;
use num_bigint::BigInt;
use num_traits::{One, Signed, ToPrimitive, Zero};
use rustpython_common::borrow::BorrowValue;
#[derive(Debug)]
pub struct BufferRef(Box<dyn Buffer>);
@@ -499,7 +500,7 @@ impl PyMemoryView {
.get_pos(i)
.ok_or_else(|| vm.new_index_error("index out of range".to_owned()))?;
let itemsize = zelf.options.itemsize;
let data = zelf.format_spec.pack(&[value], vm)?;
let data = zelf.format_spec.pack(vec![value], vm)?;
zelf.obj_bytes_mut()[i..i + itemsize].copy_from_slice(&data);
Ok(())
}
@@ -654,6 +655,7 @@ impl PyMemoryView {
fn toreadonly(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
zelf.try_not_released(vm)?;
let buffer = BufferRef(Box::new(zelf.clone()));
zelf.exports.fetch_add(1);
Ok(PyMemoryView {
obj: zelf.obj.clone(),
buffer,
@@ -673,9 +675,9 @@ impl PyMemoryView {
#[pymethod(magic)]
fn repr(zelf: PyRef<Self>) -> String {
if zelf.released.load() {
format!("<released memory at 0x{:x}>", zelf.get_id())
format!("<released memory at {:#x}>", zelf.get_id())
} else {
format!("<memory at 0x{:x}>", zelf.get_id())
format!("<memory at {:#x}>", zelf.get_id())
}
}
@@ -703,6 +705,48 @@ impl PyMemoryView {
bytes_to_hex(bytes, sep, bytes_per_sep, vm)
}
// TODO: support cast shape
#[pymethod]
fn cast(zelf: PyRef<Self>, format: PyStrRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
zelf.try_not_released(vm)?;
if !zelf.options.contiguous {
return Err(vm.new_type_error(
"memoryview: casts are restricted to C-contiguous views".to_owned(),
));
}
let format_spec = Self::parse_format(format.borrow_value(), vm)?;
let itemsize = format_spec.size();
let bytelen = zelf.options.len * zelf.options.itemsize;
if bytelen % itemsize != 0 {
return Err(
vm.new_type_error("memoryview: length is not a multiple of itemsize".to_owned())
);
}
let buffer = BufferRef(Box::new(zelf.clone()));
zelf.exports.fetch_add(1);
Ok(PyMemoryView {
obj: zelf.obj.clone(),
buffer,
options: BufferOptions {
itemsize,
len: bytelen / itemsize,
format: format.to_string().into(),
..zelf.options.clone()
},
released: AtomicCell::new(false),
stop: zelf.stop + itemsize - zelf.options.itemsize,
exports: AtomicCell::new(0),
format_spec,
hash: OnceCell::new(),
..*zelf
}
.into_ref(vm))
}
fn eq(zelf: &PyRef<Self>, other: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
if zelf.is(other) {
return Ok(true);

View File

@@ -51,12 +51,7 @@ impl PyModule {
}
#[pymethod(magic)]
fn init(
zelf: PyRef<Self>,
name: PyStrRef,
doc: OptionalOption<PyStrRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
fn init(zelf: PyRef<Self>, name: PyStrRef, doc: OptionalOption<PyStrRef>, vm: &VirtualMachine) {
debug_assert!(crate::pyobject::TypeProtocol::class(zelf.as_object())
.slots
.flags
@@ -67,7 +62,6 @@ impl PyModule {
name.into_object(),
doc.flatten().into_pyobject(vm),
);
Ok(())
}
fn name(zelf: PyRef<Self>, vm: &VirtualMachine) -> Option<String> {
@@ -82,7 +76,7 @@ impl PyModule {
#[pymethod(magic)]
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
let importlib = vm.import("_frozen_importlib", &[], 0)?;
let importlib = vm.import("_frozen_importlib", None, 0)?;
let module_repr = vm.get_attribute(importlib, "_module_repr")?;
vm.invoke(&module_repr, (zelf,))
}

View File

@@ -168,12 +168,12 @@ impl PyBaseObject {
#[pymethod(magic)]
fn repr(zelf: PyObjectRef) -> String {
format!("<{} object at 0x{:x}>", zelf.class().name, zelf.get_id())
format!("<{} object at {:#x}>", zelf.class().name, zelf.get_id())
}
#[pyclassmethod(magic)]
fn subclasshook(_args: FuncArgs, vm: &VirtualMachine) -> PyResult {
Ok(vm.ctx.not_implemented())
fn subclasshook(_args: FuncArgs, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.not_implemented()
}
#[pyclassmethod(magic)]
@@ -314,11 +314,11 @@ pub fn init(context: &PyContext) {
fn common_reduce(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
if proto >= 2 {
let reducelib = vm.import("__reducelib", &[], 0)?;
let reducelib = vm.import("__reducelib", None, 0)?;
let reduce_2 = vm.get_attribute(reducelib, "reduce_2")?;
vm.invoke(&reduce_2, (obj,))
} else {
let copyreg = vm.import("copyreg", &[], 0)?;
let copyreg = vm.import("copyreg", None, 0)?;
let reduce_ex = vm.get_attribute(copyreg, "_reduce_ex")?;
vm.invoke(&reduce_ex, (obj, proto))
}

View File

@@ -162,7 +162,7 @@ pub(crate) fn init(context: &PyContext) {
// }
// Retrieve inner int value:
pub fn get_value(obj: &PyObjectRef) -> bool {
pub(crate) fn get_value(obj: &PyObjectRef) -> bool {
!obj.payload::<PyInt>().unwrap().borrow_value().is_zero()
}

View File

@@ -95,12 +95,14 @@ impl fmt::Display for PyStr {
}
impl TryIntoRef<PyStr> for String {
#[inline]
fn try_into_ref(self, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
Ok(PyStr::from(self).into_ref(vm))
}
}
impl TryIntoRef<PyStr> for &str {
#[inline]
fn try_into_ref(self, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
Ok(PyStr::from(self).into_ref(vm))
}
@@ -570,8 +572,8 @@ impl PyStr {
}
#[pymethod(name = "__rmod__")]
fn rmod(&self, _values: PyObjectRef, vm: &VirtualMachine) -> PyResult {
Ok(vm.ctx.not_implemented())
fn rmod(&self, _values: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.not_implemented()
}
#[pymethod]
@@ -874,7 +876,7 @@ impl PyStr {
fillchar: OptionalArg<PyStrRef>,
vm: &VirtualMachine,
) -> PyResult<String> {
self._pad(width, fillchar, AnyStr::<char>::py_center, vm)
self._pad(width, fillchar, AnyStr::py_center, vm)
}
#[pymethod]
@@ -884,7 +886,7 @@ impl PyStr {
fillchar: OptionalArg<PyStrRef>,
vm: &VirtualMachine,
) -> PyResult<String> {
self._pad(width, fillchar, AnyStr::<char>::py_ljust, vm)
self._pad(width, fillchar, AnyStr::py_ljust, vm)
}
#[pymethod]
@@ -894,7 +896,7 @@ impl PyStr {
fillchar: OptionalArg<PyStrRef>,
vm: &VirtualMachine,
) -> PyResult<String> {
self._pad(width, fillchar, AnyStr::<char>::py_rjust, vm)
self._pad(width, fillchar, AnyStr::py_rjust, vm)
}
#[pymethod]
@@ -902,7 +904,7 @@ impl PyStr {
let tab_stop = args.tabsize();
let mut expanded_str = String::with_capacity(self.value.len());
let mut tab_size = tab_stop;
let mut col_count = 0 as usize;
let mut col_count = 0usize;
for ch in self.value.chars() {
match ch {
'\t' => {
@@ -1155,7 +1157,7 @@ impl TryFromObject for std::ffi::OsString {
}
}
type SplitArgs<'a> = anystr::SplitArgs<'a, PyStrRef, str, char>;
type SplitArgs<'a> = anystr::SplitArgs<'a, PyStrRef>;
#[derive(FromArgs)]
pub struct FindArgs {
@@ -1181,11 +1183,11 @@ pub fn init(ctx: &PyContext) {
PyStrReverseIterator::extend_class(ctx, &ctx.types.str_reverseiterator_type);
}
pub fn clone_value(obj: &PyObjectRef) -> String {
pub(crate) fn clone_value(obj: &PyObjectRef) -> String {
String::from(obj.payload::<PyStr>().unwrap().borrow_value())
}
pub fn borrow_value(obj: &PyObjectRef) -> &str {
pub(crate) fn borrow_value(obj: &PyObjectRef) -> &str {
&obj.payload::<PyStr>().unwrap().value
}
@@ -1336,7 +1338,8 @@ mod tests {
}
}
impl AnyStrWrapper<str> for PyStrRef {
impl<'s> AnyStrWrapper<'s> for PyStrRef {
type Str = str;
fn as_ref(&self) -> &str {
&*self.value
}
@@ -1356,7 +1359,8 @@ impl AnyStrContainer<str> for String {
}
}
impl<'s> AnyStr<'s, char> for str {
impl<'s> AnyStr<'s> for str {
type Char = char;
type Container = String;
type CharIter = std::str::Chars<'s>;
type ElementIter = std::str::Chars<'s>;
@@ -1385,11 +1389,11 @@ impl<'s> AnyStr<'s, char> for str {
str::chars(self)
}
fn get_bytes<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self {
fn get_bytes(&self, range: std::ops::Range<usize>) -> &Self {
&self[range]
}
fn get_chars<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self {
fn get_chars(&self, range: std::ops::Range<usize>) -> &Self {
rustpython_common::str::get_chars(self, range)
}

View File

@@ -2,7 +2,7 @@ use crate::common::lock::{
PyMappedRwLockReadGuard, PyRwLock, PyRwLockReadGuard, PyRwLockUpgradableReadGuard,
PyRwLockWriteGuard,
};
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::fmt;
use super::classmethod::PyClassMethod;
@@ -133,7 +133,7 @@ impl PyType {
pub fn get_attributes(&self) -> PyAttributes {
// Gather all members here:
let mut attributes = PyAttributes::new();
let mut attributes = PyAttributes::default();
for bc in self.iter_mro().rev() {
for (name, value) in bc.attributes.read().iter() {
@@ -791,7 +791,7 @@ pub fn new(
name: &str,
base: PyTypeRef,
bases: Vec<PyTypeRef>,
attrs: HashMap<String, PyObjectRef>,
attrs: PyAttributes,
mut slots: PyTypeSlots,
) -> Result<PyTypeRef, String> {
// Check for duplicates in bases.
@@ -864,7 +864,7 @@ fn calculate_meta_class(
Ok(winner)
}
fn best_base<'a>(bases: &'a [PyTypeRef], vm: &VirtualMachine) -> PyResult<PyTypeRef> {
fn best_base(bases: &[PyTypeRef], vm: &VirtualMachine) -> PyResult<PyTypeRef> {
// let mut base = None;
// let mut winner = None;
@@ -914,8 +914,7 @@ fn best_base<'a>(bases: &'a [PyTypeRef], vm: &VirtualMachine) -> PyResult<PyType
#[cfg(test)]
mod tests {
use super::{linearise_mro, new};
use super::{HashMap, IdProtocol, PyContext, PyTypeRef};
use super::*;
fn map_ids(obj: Result<Vec<PyTypeRef>, String>) -> Result<Vec<usize>, String> {
Ok(obj?.into_iter().map(|x| x.get_id()).collect())
@@ -932,7 +931,7 @@ mod tests {
"A",
object.clone(),
vec![object.clone()],
HashMap::new(),
PyAttributes::default(),
Default::default(),
)
.unwrap();
@@ -941,7 +940,7 @@ mod tests {
"B",
object.clone(),
vec![object.clone()],
HashMap::new(),
PyAttributes::default(),
Default::default(),
)
.unwrap();

View File

@@ -1,6 +1,6 @@
use crate::builtins::pytype::PyTypeRef;
use crate::frame::FrameRef;
use crate::pyobject::{PyClassImpl, PyContext, PyRef, PyValue};
use crate::pyobject::{BorrowValue, PyClassImpl, PyContext, PyRef, PyValue};
use crate::vm::VirtualMachine;
#[pyclass(module = false, name = "traceback")]
@@ -8,7 +8,7 @@ use crate::vm::VirtualMachine;
pub struct PyTraceback {
pub next: Option<PyTracebackRef>, // TODO: Make mutable
pub frame: FrameRef,
pub lasti: usize,
pub lasti: u32,
pub lineno: usize,
}
@@ -22,7 +22,7 @@ impl PyValue for PyTraceback {
#[pyimpl]
impl PyTraceback {
pub fn new(next: Option<PyRef<Self>>, frame: FrameRef, lasti: usize, lineno: usize) -> Self {
pub fn new(next: Option<PyRef<Self>>, frame: FrameRef, lasti: u32, lineno: usize) -> Self {
PyTraceback {
next,
frame,
@@ -37,7 +37,7 @@ impl PyTraceback {
}
#[pyproperty(name = "tb_lasti")]
fn lasti(&self) -> usize {
fn lasti(&self) -> u32 {
self.lasti
}
@@ -53,7 +53,7 @@ impl PyTraceback {
}
impl PyTracebackRef {
pub fn iter<'a>(&'a self) -> impl Iterator<Item = PyTracebackRef> + 'a {
pub fn iter(&self) -> impl Iterator<Item = PyTracebackRef> {
std::iter::successors(Some(self.clone()), |tb| tb.next.clone())
}
}
@@ -67,9 +67,9 @@ impl serde::Serialize for PyTraceback {
use serde::ser::SerializeStruct;
let mut struc = s.serialize_struct("PyTraceback", 3)?;
struc.serialize_field("name", &self.frame.code.obj_name)?;
struc.serialize_field("name", self.frame.code.obj_name.borrow_value())?;
struc.serialize_field("lineno", &self.lineno)?;
struc.serialize_field("filename", &self.frame.code.source_path)?;
struc.serialize_field("filename", self.frame.code.source_path.borrow_value())?;
struc.end()
}
}

View File

@@ -317,6 +317,7 @@ impl<T: TransmuteFromObject> TryFromObject for PyTupleTyped<T> {
impl<'a, T: TransmuteFromObject + 'a> BorrowValue<'a> for PyTupleTyped<T> {
type Borrowed = &'a [T];
#[inline]
fn borrow_value(&'a self) -> Self::Borrowed {
unsafe { &*(self.tuple.borrow_value() as *const [PyObjectRef] as *const [T]) }
}
@@ -327,3 +328,17 @@ impl<T: TransmuteFromObject + fmt::Debug> fmt::Debug for PyTupleTyped<T> {
self.borrow_value().fmt(f)
}
}
impl<T: TransmuteFromObject> From<PyTupleTyped<T>> for PyTupleRef {
#[inline]
fn from(tup: PyTupleTyped<T>) -> Self {
tup.tuple
}
}
impl<T: TransmuteFromObject> IntoPyObject for PyTupleTyped<T> {
#[inline]
fn into_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
self.tuple.into_object()
}
}

View File

@@ -227,7 +227,7 @@ impl ByteInnerTranslateOptions {
}
}
pub type ByteInnerSplitOptions<'a> = anystr::SplitArgs<'a, PyBytesInner, [u8], u8>;
pub type ByteInnerSplitOptions<'a> = anystr::SplitArgs<'a, PyBytesInner>;
#[allow(clippy::len_without_is_empty)]
impl PyBytesInner {
@@ -468,7 +468,7 @@ impl PyBytesInner {
options: ByteInnerPaddingOptions,
vm: &VirtualMachine,
) -> PyResult<Vec<u8>> {
self._pad(options, AnyStr::<u8>::py_center, vm)
self._pad(options, AnyStr::py_center, vm)
}
pub fn ljust(
@@ -476,7 +476,7 @@ impl PyBytesInner {
options: ByteInnerPaddingOptions,
vm: &VirtualMachine,
) -> PyResult<Vec<u8>> {
self._pad(options, AnyStr::<u8>::py_ljust, vm)
self._pad(options, AnyStr::py_ljust, vm)
}
pub fn rjust(
@@ -484,7 +484,7 @@ impl PyBytesInner {
options: ByteInnerPaddingOptions,
vm: &VirtualMachine,
) -> PyResult<Vec<u8>> {
self._pad(options, AnyStr::<u8>::py_rjust, vm)
self._pad(options, AnyStr::py_rjust, vm)
}
pub fn count(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult<usize> {
@@ -938,7 +938,8 @@ pub trait ByteOr: ToPrimitive {
impl ByteOr for BigInt {}
impl AnyStrWrapper<[u8]> for PyBytesInner {
impl<'s> AnyStrWrapper<'s> for PyBytesInner {
type Str = [u8];
fn as_ref(&self) -> &[u8] {
&self.elements
}
@@ -960,7 +961,8 @@ impl AnyStrContainer<[u8]> for Vec<u8> {
const ASCII_WHITESPACES: [u8; 6] = [0x20, 0x09, 0x0a, 0x0c, 0x0d, 0x0b];
impl<'s> AnyStr<'s, u8> for [u8] {
impl<'s> AnyStr<'s> for [u8] {
type Char = u8;
type Container = Vec<u8>;
type CharIter = bstr::Chars<'s>;
type ElementIter = std::iter::Copied<std::slice::Iter<'s, u8>>;
@@ -989,11 +991,11 @@ impl<'s> AnyStr<'s, u8> for [u8] {
self.iter().copied()
}
fn get_bytes<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self {
fn get_bytes(&self, range: std::ops::Range<usize>) -> &Self {
&self[range]
}
fn get_chars<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self {
fn get_chars(&self, range: std::ops::Range<usize>) -> &Self {
&self[range]
}

View File

@@ -1,10 +1,10 @@
use crate::builtins::pytype::PyTypeRef;
use crate::builtins::{PyStrRef, PyTypeRef};
use crate::exceptions::{self, PyBaseExceptionRef};
use crate::frame::{ExecutionResult, FrameRef};
use crate::pyobject::{PyObjectRef, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
use crate::common::lock::PyRwLock;
use crate::common::lock::PyMutex;
use crossbeam_utils::atomic::AtomicCell;
#[derive(Debug, PartialEq, Clone, Copy)]
@@ -37,20 +37,20 @@ pub struct Coro {
frame: FrameRef,
pub closed: AtomicCell<bool>,
running: AtomicCell<bool>,
exceptions: PyRwLock<Vec<PyBaseExceptionRef>>,
started: AtomicCell<bool>,
exceptions: PyMutex<Vec<PyBaseExceptionRef>>,
variant: Variant,
name: PyMutex<PyStrRef>,
}
impl Coro {
pub fn new(frame: FrameRef, variant: Variant) -> Self {
pub fn new(frame: FrameRef, variant: Variant, name: PyStrRef) -> Self {
Coro {
frame,
closed: AtomicCell::new(false),
running: AtomicCell::new(false),
exceptions: PyRwLock::new(vec![]),
started: AtomicCell::new(false),
exceptions: PyMutex::new(vec![]),
variant,
name: PyMutex::new(name),
}
}
@@ -65,21 +65,20 @@ impl Coro {
where
F: FnOnce(FrameRef) -> PyResult<ExecutionResult>,
{
self.running.store(true);
let curr_exception_stack_len = vm.exceptions.borrow().len();
vm.exceptions
.borrow_mut()
.append(&mut self.exceptions.write());
if self.running.compare_exchange(false, true).is_err() {
return Err(vm.new_value_error(format!("{} already executing", self.variant.name())));
}
let curr_exception_stack_len;
{
let mut vm_excs = vm.exceptions.borrow_mut();
curr_exception_stack_len = vm_excs.len();
vm_excs.append(&mut self.exceptions.lock());
}
let result = vm.with_frame(self.frame.clone(), func);
std::mem::swap(
&mut *self.exceptions.write(),
&mut vm
.exceptions
.borrow_mut()
.split_off(curr_exception_stack_len),
);
self.exceptions
.lock()
.extend(vm.exceptions.borrow_mut().drain(curr_exception_stack_len..));
self.running.store(false);
self.started.store(true);
result
}
@@ -87,12 +86,16 @@ impl Coro {
if self.closed.load() {
return Err(vm.new_exception_empty(self.variant.stop_iteration(vm)));
}
if !self.started.load() && !vm.is_none(&value) {
let value = if self.frame.lasti() > 0 {
Some(value)
} else if !vm.is_none(&value) {
return Err(vm.new_type_error(format!(
"can't send non-None value to a just-started {}",
self.variant.name()
)));
}
} else {
None
};
let result = self.run_with_context(vm, |f| f.resume(value, vm));
self.maybe_close(&result);
match result {
@@ -153,9 +156,6 @@ impl Coro {
}
}
pub fn started(&self) -> bool {
self.started.load()
}
pub fn running(&self) -> bool {
self.running.load()
}
@@ -165,8 +165,19 @@ impl Coro {
pub fn frame(&self) -> FrameRef {
self.frame.clone()
}
pub fn name(&self) -> String {
self.frame.code.obj_name.clone()
pub fn name(&self) -> PyStrRef {
self.name.lock().clone()
}
pub fn set_name(&self, name: PyStrRef) {
*self.name.lock() = name;
}
pub fn repr(&self, id: usize) -> String {
format!(
"<{} object {} at {:#x}>",
self.variant.name(),
self.name.lock(),
id
)
}
}

View File

@@ -240,13 +240,13 @@ fn write_traceback_entry<W: Write>(
output: &mut W,
tb_entry: &PyTracebackRef,
) -> Result<(), W::Error> {
let filename = tb_entry.frame.code.source_path.to_owned();
let filename = tb_entry.frame.code.source_path.borrow_value();
writeln!(
output,
r##" File "{}", line {}, in {}"##,
filename, tb_entry.lineno, tb_entry.frame.code.obj_name
)?;
print_source_line(output, &filename, tb_entry.lineno)?;
print_source_line(output, filename, tb_entry.lineno)?;
Ok(())
}
@@ -660,7 +660,7 @@ impl ExceptionZoo {
});
extend_class!(ctx, &excs.import_error, {
"__init__" => ctx.new_method(import_error_init),
"__init__" => ctx.new_method("__init__", import_error_init),
"msg" => ctx.new_readonly_getset("msg", make_arg_getter(0)),
});
@@ -669,7 +669,7 @@ impl ExceptionZoo {
});
extend_class!(ctx, &excs.key_error, {
"__str__" => ctx.new_method(key_error_str),
"__str__" => ctx.new_method("__str__", key_error_str),
});
extend_class!(ctx, &excs.unicode_decode_error, {

File diff suppressed because it is too large Load Diff

View File

@@ -19,8 +19,10 @@ pub fn map_frozen<'a>(
})
}
pub fn get_module_inits(vm: &VirtualMachine) -> HashMap<String, code::FrozenModule> {
let mut modules = HashMap::new();
pub fn get_module_inits(
vm: &VirtualMachine,
) -> HashMap<String, code::FrozenModule, ahash::RandomState> {
let mut modules = HashMap::default();
macro_rules! ext_modules {
($($t:tt)*) => {

View File

@@ -8,8 +8,8 @@ use crate::pyobject::{
};
use crate::vm::VirtualMachine;
use indexmap::IndexMap;
use itertools::Itertools;
use result_like::impl_option_like;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::ops::RangeInclusive;
@@ -98,15 +98,24 @@ impl FuncArgs {
Self { args, kwargs }
}
pub fn with_kwargs_names(mut args: Vec<PyObjectRef>, kwarg_names: Vec<String>) -> Self {
pub fn with_kwargs_names<A, KW>(mut args: A, kwarg_names: KW) -> Self
where
A: ExactSizeIterator<Item = PyObjectRef>,
KW: ExactSizeIterator<Item = String>,
{
// last `kwarg_names.len()` elements of args in order of appearance in the call signature
let kwarg_values = args.drain((args.len() - kwarg_names.len())..);
let total_argc = args.len();
let kwargc = kwarg_names.len();
let posargc = total_argc - kwargc;
let mut kwargs = IndexMap::new();
for (name, value) in kwarg_names.iter().zip(kwarg_values) {
kwargs.insert(name.clone(), value);
let posargs = args.by_ref().take(posargc).collect();
let kwargs = kwarg_names.zip_eq(args).collect::<IndexMap<_, _>>();
FuncArgs {
args: posargs,
kwargs,
}
FuncArgs { args, kwargs }
}
pub fn prepend_arg(&mut self, item: PyObjectRef) {
@@ -168,9 +177,7 @@ impl FuncArgs {
self.kwargs.swap_remove(name)
}
pub fn remaining_keywords<'a>(
&'a mut self,
) -> impl Iterator<Item = (String, PyObjectRef)> + 'a {
pub fn remaining_keywords(&mut self) -> impl Iterator<Item = (String, PyObjectRef)> + '_ {
self.kwargs.drain(..)
}
@@ -317,9 +324,9 @@ impl<T> KwArgs<T> {
self.0.remove(name)
}
}
impl<T> From<HashMap<String, T>> for KwArgs<T> {
fn from(kwargs: HashMap<String, T>) -> Self {
KwArgs(kwargs.into_iter().collect())
impl<T> std::iter::FromIterator<(String, T)> for KwArgs<T> {
fn from_iter<I: IntoIterator<Item = (String, T)>>(iter: I) -> Self {
KwArgs(iter.into_iter().collect())
}
}
impl<T> Default for KwArgs<T> {

View File

@@ -9,7 +9,7 @@ use crate::builtins::{code, list};
#[cfg(feature = "rustpython-compiler")]
use crate::compile;
use crate::exceptions::PyBaseExceptionRef;
use crate::pyobject::{ItemProtocol, PyResult, PyValue, TryFromObject, TypeProtocol};
use crate::pyobject::{BorrowValue, ItemProtocol, PyResult, PyValue, TryFromObject, TypeProtocol};
use crate::scope::Scope;
use crate::version::get_git_revision;
use crate::vm::{InitParameter, VirtualMachine};
@@ -36,7 +36,7 @@ pub(crate) fn init_importlib(
let install_external = vm.get_attribute(importlib, "_install_external_importers")?;
vm.invoke(&install_external, ())?;
// Set pyc magic number to commit hash. Should be changed when bytecode will be more stable.
let importlib_external = vm.import("_frozen_importlib_external", &[], 0)?;
let importlib_external = vm.import("_frozen_importlib_external", None, 0)?;
let mut magic = get_git_revision().into_bytes();
magic.truncate(4);
if magic.len() != 4 {
@@ -44,7 +44,7 @@ pub(crate) fn init_importlib(
}
vm.set_attr(&importlib_external, "MAGIC_NUMBER", vm.ctx.new_bytes(magic))?;
let zipimport_res = (|| -> PyResult<()> {
let zipimport = vm.import("zipimport", &[], 0)?;
let zipimport = vm.import("zipimport", None, 0)?;
let zipimporter = vm.get_attribute(zipimport, "zipimporter")?;
let path_hooks = vm.get_attribute(vm.sys_module.clone(), "path_hooks")?;
let path_hooks = list::PyListRef::try_from_object(vm, path_hooks)?;
@@ -139,12 +139,12 @@ fn remove_importlib_frames_inner(
return (None, false);
};
let file_name = &traceback.frame.code.source_path;
let file_name = traceback.frame.code.source_path.borrow_value();
let (inner_tb, mut now_in_importlib) =
remove_importlib_frames_inner(vm, traceback.next.clone(), always_trim);
if file_name == "_frozen_importlib" || file_name == "_frozen_importlib_external" {
if traceback.frame.code.obj_name == "_call_with_frames_removed" {
if traceback.frame.code.obj_name.borrow_value() == "_call_with_frames_removed" {
now_in_importlib = true;
}
if always_trim || now_in_importlib {

View File

@@ -12,10 +12,7 @@
#![allow(clippy::module_inception)]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/master/logo.png")]
#![doc(html_root_url = "https://docs.rs/rustpython-vm/")]
#![cfg_attr(
target_os = "redox",
feature(matches_macro, proc_macro_hygiene, result_map_or)
)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "flame-it")]
#[macro_use]
@@ -25,8 +22,6 @@ extern crate flamer;
extern crate bitflags;
#[macro_use]
extern crate log;
#[macro_use]
extern crate maplit;
// extern crate env_logger;
#[macro_use]
@@ -77,7 +72,7 @@ mod vm;
// pub use self::pyobject::Executor;
pub use self::vm::{InitParameter, Interpreter, PySettings, VirtualMachine};
pub use rustpython_bytecode::*;
pub use rustpython_bytecode as bytecode;
pub use rustpython_common as common;
#[cfg(feature = "rustpython-compiler")]
pub use rustpython_compiler as compile;

View File

@@ -1,16 +1,3 @@
#[macro_export]
macro_rules! no_kwargs {
( $vm: ident, $args:ident ) => {
// Zero-arg case
if $args.kwargs.len() != 0 {
return Err($vm.new_type_error(format!(
"Expected no keyword arguments (got: {})",
$args.kwargs.len()
)));
}
};
}
#[macro_export]
macro_rules! py_module {
( $vm:expr, $module_name:expr, { $($name:expr => $value:expr),* $(,)? }) => {{
@@ -241,9 +228,9 @@ macro_rules! named_function {
#[allow(unused_variables)] // weird lint, something to do with paste probably
let ctx: &$crate::pyobject::PyContext = &$ctx;
$crate::__exports::paste::expr! {
ctx.new_function_named(
ctx.make_funcdef(
stringify!($module),
[<$module _ $func>],
stringify!($module).to_owned(),
)
.into_function()
.with_module(ctx.new_str(stringify!($func).to_owned()))
@@ -269,3 +256,21 @@ cfg_if::cfg_if! {
}
}
}
/// A modified version of the hashmap! macro from the maplit crate
macro_rules! hashmap {
(@single $($x:tt)*) => (());
(@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));
(hasher=$hasher:expr, $($key:expr => $value:expr,)+) => { hashmap!(hasher=$hasher, $($key => $value),+) };
(hasher=$hasher:expr, $($key:expr => $value:expr),*) => {
{
let _cap = hashmap!(@count $($key),*);
let mut _map = ::std::collections::HashMap::with_capacity_and_hasher(_cap, $hasher);
$(
let _ = _map.insert($key, $value);
)*
_map
}
};
}

View File

@@ -30,6 +30,25 @@ impl Write for PyWriter<'_> {
}
}
pub fn write_all(
mut buf: &[u8],
mut write: impl FnMut(&[u8]) -> io::Result<usize>,
) -> io::Result<()> {
while !buf.is_empty() {
match write(buf) {
Ok(0) => {
return Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
))
}
Ok(n) => buf = &buf[n..],
Err(e) => return Err(e),
}
}
Ok(())
}
pub fn file_readline(obj: &PyObjectRef, size: Option<usize>, vm: &VirtualMachine) -> PyResult {
let args = size.map_or_else(Vec::new, |size| vec![vm.ctx.new_int(size)]);
let ret = vm.call_method(obj, "readline", args)?;

View File

@@ -64,7 +64,7 @@ pub type PyResult<T = PyObjectRef> = Result<T, PyBaseExceptionRef>; // A valid v
/// For attributes we do not use a dict, but a hashmap. This is probably
/// faster, unordered, and only supports strings as keys.
/// TODO: class attributes should maintain insertion order (use IndexMap here)
pub type PyAttributes = HashMap<String, PyObjectRef>;
pub type PyAttributes = HashMap<String, PyObjectRef, ahash::RandomState>;
// TODO: remove this impl
impl fmt::Display for PyObjectRef {
@@ -133,8 +133,9 @@ impl PyContext {
let string_cache = Dict::default();
let new_str = PyRef::new_ref(pystr::PyStr::from("__new__"), types.str_type.clone(), None);
let tp_new_wrapper = create_object(
PyNativeFuncDef::from(pytype::tp_new_wrapper.into_func()).into_function(),
PyNativeFuncDef::new(pytype::tp_new_wrapper.into_func(), new_str).into_function(),
&types.builtin_function_or_method_type,
)
.into_object();
@@ -273,45 +274,44 @@ impl PyContext {
)
}
pub fn new_function<F, FKind>(&self, f: F) -> PyObjectRef
where
F: IntoPyNativeFunc<FKind>,
{
PyNativeFuncDef::from(f.into_func()).build_function(self)
}
pub(crate) fn new_stringref(&self, s: String) -> pystr::PyStrRef {
PyRef::new_ref(pystr::PyStr::from(s), self.types.str_type.clone(), None)
}
pub fn new_function_named<F, FKind>(&self, f: F, name: String) -> PyNativeFuncDef
#[inline]
pub fn make_funcdef<F, FKind>(&self, name: impl Into<String>, f: F) -> PyNativeFuncDef
where
F: IntoPyNativeFunc<FKind>,
{
let mut f = PyNativeFuncDef::from(f.into_func());
f.name = Some(self.new_stringref(name));
f
PyNativeFuncDef::new(f.into_func(), self.new_stringref(name.into()))
}
pub fn new_method<F, FKind>(&self, f: F) -> PyObjectRef
pub fn new_function<F, FKind>(&self, name: impl Into<String>, f: F) -> PyObjectRef
where
F: IntoPyNativeFunc<FKind>,
{
PyNativeFuncDef::from(f.into_func()).build_method(self)
self.make_funcdef(name, f).build_function(self)
}
pub fn new_classmethod<F, FKind>(&self, f: F) -> PyObjectRef
pub fn new_method<F, FKind>(&self, name: impl Into<String>, f: F) -> PyObjectRef
where
F: IntoPyNativeFunc<FKind>,
{
PyNativeFuncDef::from(f.into_func()).build_classmethod(self)
self.make_funcdef(name, f).build_method(self)
}
pub fn new_staticmethod<F, FKind>(&self, f: F) -> PyObjectRef
pub fn new_classmethod<F, FKind>(&self, name: impl Into<String>, f: F) -> PyObjectRef
where
F: IntoPyNativeFunc<FKind>,
{
self.make_funcdef(name, f).build_classmethod(self)
}
pub fn new_staticmethod<F, FKind>(&self, name: impl Into<String>, f: F) -> PyObjectRef
where
F: IntoPyNativeFunc<FKind>,
{
PyObject::new(
PyStaticMethod::from(self.new_method(f)),
PyStaticMethod::from(self.new_method(name, f)),
self.types.staticmethod_type.clone(),
None,
)
@@ -763,6 +763,7 @@ pub trait TryIntoRef<T: PyObjectPayload> {
}
impl<T: PyObjectPayload> TryIntoRef<T> for PyRef<T> {
#[inline]
fn try_into_ref(self, _vm: &VirtualMachine) -> PyResult<PyRef<T>> {
Ok(self)
}
@@ -1103,9 +1104,11 @@ pub trait PyClassImpl: PyClassDef {
fn extend_slots(slots: &mut PyTypeSlots);
fn make_slots() -> PyTypeSlots {
let mut slots = PyTypeSlots::default();
slots.flags = Self::TP_FLAGS;
slots.name = PyRwLock::new(Some(Self::TP_NAME.to_owned()));
let mut slots = PyTypeSlots {
flags: Self::TP_FLAGS,
name: PyRwLock::new(Some(Self::TP_NAME.to_owned())),
..Default::default()
};
Self::extend_slots(&mut slots);
slots
}

View File

@@ -317,7 +317,7 @@ impl Drop for PyObjectRef {
Ok(v) => println!("{}", v.to_string()),
Err(_) => println!("{}", del_method.class().name),
}
let tb_module = vm.import("traceback", &[], 0).unwrap();
let tb_module = vm.import("traceback", None, 0).unwrap();
// TODO: set exc traceback
let print_stack = vm.get_attribute(tb_module, "print_stack").unwrap();
vm.invoke(&print_stack, ()).unwrap();
@@ -489,7 +489,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef) {
bases: vec![],
mro: vec![],
subclasses: PyRwLock::default(),
attributes: PyRwLock::new(PyAttributes::new()),
attributes: PyRwLock::new(PyAttributes::default()),
slots: PyType::make_slots(),
};
let object_payload = PyType {
@@ -498,7 +498,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef) {
bases: vec![],
mro: vec![],
subclasses: PyRwLock::default(),
attributes: PyRwLock::new(PyAttributes::new()),
attributes: PyRwLock::new(PyAttributes::default()),
slots: object::PyBaseObject::make_slots(),
};
let type_type = PyRc::new(partially_init!(

View File

@@ -391,7 +391,7 @@ impl TryFromObject for SequenceIndex {
// Use PySliceableSequence::wrap_index for implementors
pub(crate) fn wrap_index(p: isize, len: usize) -> Option<usize> {
let neg = p.is_negative();
let p = p.abs().to_usize()?;
let p = p.wrapping_abs() as usize;
if neg {
len.checked_sub(p)
} else if p >= len {

View File

@@ -1,10 +1,9 @@
use crate::builtins::bytes::PyBytesRef;
use crate::builtins::code::PyCode;
use crate::builtins::module::PyModuleRef;
use crate::builtins::pystr;
use crate::builtins::pystr::PyStrRef;
use crate::builtins::pystr::{self, PyStr, PyStrRef};
use crate::import;
use crate::pyobject::{BorrowValue, ItemProtocol, PyObjectRef, PyResult};
use crate::pyobject::{BorrowValue, ItemProtocol, PyObjectRef, PyResult, PyValue};
use crate::vm::VirtualMachine;
#[cfg(feature = "threading")]
@@ -82,7 +81,7 @@ fn _imp_get_frozen_object(name: PyStrRef, vm: &VirtualMachine) -> PyResult<PyCod
.get(name.borrow_value())
.map(|frozen| {
let mut frozen = frozen.code.clone();
frozen.source_path = format!("frozen {}", name);
frozen.source_path = PyStr::from(format!("frozen {}", name)).into_ref(vm);
PyCode::new(frozen)
})
.ok_or_else(|| vm.new_import_error(format!("No such frozen object named {}", name), name))

View File

@@ -984,10 +984,7 @@ mod decl {
args: ProductArgs,
vm: &VirtualMachine,
) -> PyResult<PyRef<Self>> {
let repeat = match args.repeat.into_option() {
Some(i) => i,
None => 1,
};
let repeat = args.repeat.unwrap_or(1);
let mut pools = Vec::new();
for arg in iterables.into_iter() {

View File

@@ -39,6 +39,7 @@ static ESCAPE_CHARS: [&str; 0x20] = [
// And which one need to be escaped (1)
// The characters that need escaping are 0x00 to 0x1F, 0x22 ("), 0x5C (\), 0x7F (DEL)
// Non-ASCII unicode characters can be safely included in a JSON string
#[allow(clippy::unusual_byte_groupings)] // it's groups of 16, come on clippy
static NEEDS_ESCAPING_BITSET: [u64; 4] = [
//fedcba9876543210_fedcba9876543210_fedcba9876543210_fedcba9876543210
0b0000000000000000_0000000000000100_1111111111111111_1111111111111111, // 3_2_1_0

View File

@@ -6,21 +6,18 @@ mod decl {
use rustpython_parser::lexer;
use crate::builtins::pystr::PyStrRef;
use crate::pyobject::{BorrowValue, PyObjectRef, PyResult};
use crate::pyobject::{BorrowValue, PyObjectRef};
use crate::vm::VirtualMachine;
#[pyfunction]
fn iskeyword(s: PyStrRef, vm: &VirtualMachine) -> PyResult {
let keywords = lexer::get_keywords();
let value = keywords.contains_key(s.borrow_value());
let value = vm.ctx.new_bool(value);
Ok(value)
fn iskeyword(s: PyStrRef) -> bool {
lexer::KEYWORDS.contains_key(s.borrow_value())
}
#[pyattr]
fn kwlist(vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.new_list(
lexer::get_keywords()
lexer::KEYWORDS
.keys()
.map(|k| vm.ctx.new_str(k.to_owned()))
.collect(),

View File

@@ -23,8 +23,14 @@ mod decl {
#[pyfunction]
fn loads(code_bytes: PyBytesLike, vm: &VirtualMachine) -> PyResult<PyCode> {
let code = bytecode::CodeObject::from_bytes(&*code_bytes.borrow_value())
.map_err(|_| vm.new_value_error("Couldn't deserialize python bytecode".to_owned()))?;
let code =
bytecode::CodeObject::from_bytes(&*code_bytes.borrow_value()).map_err(|e| match e {
bytecode::CodeDeserializeError::Eof => vm.new_exception_msg(
vm.ctx.exceptions.eof_error.clone(),
"end of file while deserializing bytecode".to_owned(),
),
_ => vm.new_value_error("Couldn't deserialize python bytecode".to_owned()),
})?;
Ok(PyCode {
code: vm.map_codeobj(code),
})

View File

@@ -5,13 +5,12 @@
use num_bigint::BigInt;
use num_traits::{One, Signed, Zero};
use statrs::function::erf::{erf, erfc};
use statrs::function::gamma::{gamma, ln_gamma};
use puruspe::{erf, erfc, gamma, ln_gamma};
use crate::builtins::float::{self, IntoPyFloat, PyFloatRef};
use crate::builtins::int::{self, PyInt, PyIntRef};
use crate::function::{Args, OptionalArg};
use crate::pyobject::{BorrowValue, Either, PyObjectRef, PyResult, TypeProtocol};
use crate::pyobject::{BorrowValue, Either, PyIterable, PyObjectRef, PyResult, TypeProtocol};
use crate::vm::VirtualMachine;
use rustpython_common::float_ops;
@@ -372,6 +371,104 @@ fn math_lcm(args: Args<PyIntRef>) -> BigInt {
math_perf_arb_len_int_op(args, |x, y| x.lcm(y.borrow_value()), BigInt::one())
}
fn math_fsum(iter: PyIterable<IntoPyFloat>, vm: &VirtualMachine) -> PyResult<f64> {
let mut partials = vec![];
let mut special_sum = 0.0;
let mut inf_sum = 0.0;
for obj in iter.iter(vm)? {
let mut x = obj?.to_f64();
let xsave = x;
let mut j = 0;
// This inner loop applies `hi`/`lo` summation to each
// partial so that the list of partial sums remains exact.
for i in 0..partials.len() {
let mut y: f64 = partials[i];
if x.abs() < y.abs() {
std::mem::swap(&mut x, &mut y);
}
// Rounded `x+y` is stored in `hi` with round-off stored in
// `lo`. Together `hi+lo` are exactly equal to `x+y`.
let hi = x + y;
let lo = y - (hi - x);
if lo != 0.0 {
partials[j] = lo;
j += 1;
}
x = hi;
}
if !x.is_finite() {
// a nonfinite x could arise either as
// a result of intermediate overflow, or
// as a result of a nan or inf in the
// summands
if xsave.is_finite() {
return Err(vm.new_overflow_error("intermediate overflow in fsum".to_owned()));
}
if xsave.is_infinite() {
inf_sum += xsave;
}
special_sum += xsave;
// reset partials
partials.clear();
}
if j >= partials.len() {
partials.push(x);
} else {
partials[j] = x;
partials.truncate(j + 1);
}
}
if special_sum != 0.0 {
return if inf_sum.is_nan() {
Err(vm.new_overflow_error("-inf + inf in fsum".to_owned()))
} else {
Ok(special_sum)
};
}
let mut n = partials.len();
if n > 0 {
n -= 1;
let mut hi = partials[n];
let mut lo = 0.0;
while n > 0 {
let x = hi;
n -= 1;
let y = partials[n];
hi = x + y;
lo = y - (hi - x);
if lo != 0.0 {
break;
}
}
if n > 0 && ((lo < 0.0 && partials[n - 1] < 0.0) || (lo > 0.0 && partials[n - 1] > 0.0)) {
let y = lo + lo;
let x = hi + y;
// Make half-even rounding work across multiple partials.
// Needed so that sum([1e-16, 1, 1e16]) will round-up the last
// digit to two instead of down to zero (the 1e-16 makes the 1
// slightly closer to two). With a potential 1 ULP rounding
// error fixed-up, math.fsum() can guarantee commutativity.
#[allow(clippy::float_cmp)]
if y == x - hi {
hi = x;
}
}
Ok(hi)
} else {
Ok(0.0)
}
}
fn math_factorial(value: PyIntRef, vm: &VirtualMachine) -> PyResult<BigInt> {
let value = value.borrow_value();
if value.is_negative() {
@@ -516,6 +613,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"ldexp" => named_function!(ctx, math, ldexp),
"modf" => named_function!(ctx, math, modf),
"fmod" => named_function!(ctx, math, fmod),
"fsum" => named_function!(ctx, math, fsum),
"remainder" => named_function!(ctx, math, remainder),
// Rounding functions:

View File

@@ -71,9 +71,10 @@ mod zlib;
pub type StdlibInitFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine) -> PyObjectRef)>;
pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
pub fn get_module_inits() -> HashMap<String, StdlibInitFunc, ahash::RandomState> {
#[allow(unused_mut)]
let mut modules = hashmap! {
hasher = ahash::RandomState::default(),
"array".to_owned() => Box::new(array::make_module) as StdlibInitFunc,
"atexit".to_owned() => Box::new(atexit::make_module),
"binascii".to_owned() => Box::new(binascii::make_module),

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