Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
|
8c95fcbd85 | ||
|
2f690250ae | ||
|
cd1d83714b | ||
|
4306dcc6c0 | ||
|
b4fc95c64b | ||
|
229cefe028 | ||
|
ba8f854b28 |
25 changed files with 776 additions and 107 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1 @@
|
||||||
/target
|
target
|
||||||
|
|
136
Cargo.lock
generated
136
Cargo.lock
generated
|
@ -45,9 +45,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.64"
|
version = "0.3.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f"
|
checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cc",
|
"cc",
|
||||||
|
@ -78,9 +78,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "3.1.9"
|
version = "3.1.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6aad2534fad53df1cc12519c5cda696dd3e20e6118a027e24054aea14a0bdcbe"
|
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
@ -95,9 +95,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "3.1.7"
|
version = "3.1.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
|
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
|
@ -108,9 +108,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669"
|
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
@ -150,6 +150,7 @@ dependencies = [
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"from_variants",
|
"from_variants",
|
||||||
|
"gc",
|
||||||
"itertools",
|
"itertools",
|
||||||
"match_any",
|
"match_any",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -158,9 +159,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.13.1"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4"
|
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"darling_macro",
|
"darling_macro",
|
||||||
|
@ -168,9 +169,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_core"
|
name = "darling_core"
|
||||||
version = "0.13.1"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324"
|
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"ident_case",
|
"ident_case",
|
||||||
|
@ -182,9 +183,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_macro"
|
name = "darling_macro"
|
||||||
version = "0.13.1"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
|
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -205,9 +206,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eyre"
|
name = "eyre"
|
||||||
version = "0.6.7"
|
version = "0.6.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9289ed2c0440a6536e65119725cf91fc2c6b5e513bfd2e36e1134d7cca6ca12f"
|
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indenter",
|
"indenter",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -240,6 +241,22 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"gctrace-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gctrace-derive"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.26.1"
|
version = "0.26.1"
|
||||||
|
@ -306,15 +323,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.121"
|
version = "0.2.126"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.14"
|
version = "0.4.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
@ -336,52 +353,51 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.4.1"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.4.4"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"adler",
|
||||||
"autocfg",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.27.1"
|
version = "0.28.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
|
checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.0.0"
|
version = "6.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owo-colors"
|
name = "owo-colors"
|
||||||
version = "3.3.0"
|
version = "3.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e72e30578e0d0993c8ae20823dd9cff2bc5517d2f586a8aef462a581e8a03eb"
|
checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
|
@ -409,27 +425,27 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.36"
|
version = "1.0.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.16"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57"
|
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.5.5"
|
version = "1.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
@ -445,9 +461,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.25"
|
version = "0.6.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
|
@ -478,13 +494,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.89"
|
version = "1.0.98"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
|
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-xid",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -513,9 +529,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.32"
|
version = "0.1.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
|
checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
@ -525,9 +541,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-attributes"
|
name = "tracing-attributes"
|
||||||
version = "0.1.20"
|
version = "0.1.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b"
|
checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -536,9 +552,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.23"
|
version = "0.1.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
|
checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"valuable",
|
"valuable",
|
||||||
|
@ -556,9 +572,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-log"
|
name = "tracing-log"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
|
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
@ -567,9 +583,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.9"
|
version = "0.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce"
|
checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -584,10 +600,10 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-ident"
|
||||||
version = "0.2.2"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
|
|
|
@ -3,7 +3,14 @@ name = "crftng-intrprtrs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"gc",
|
||||||
|
"gc/gctrace-derive"
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
gc = { path = "./gc" }
|
||||||
clap = { version = "3.1.9", features = ["derive"] }
|
clap = { version = "3.1.9", features = ["derive"] }
|
||||||
color-eyre = "0.6.1"
|
color-eyre = "0.6.1"
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
|
|
7
gc/Cargo.toml
Normal file
7
gc/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "gc"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gctrace-derive = { version = "0.1.0", path = "gctrace-derive" }
|
3
gc/fuzz/.gitignore
vendored
Normal file
3
gc/fuzz/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
target
|
||||||
|
corpus
|
||||||
|
artifacts
|
105
gc/fuzz/Cargo.lock
generated
Normal file
105
gc/fuzz/Cargo.lock
generated
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arbitrary"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
|
||||||
|
dependencies = [
|
||||||
|
"derive_arbitrary",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_arbitrary"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"gctrace-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gc-fuzz"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"gc",
|
||||||
|
"libfuzzer-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gctrace-derive"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libfuzzer-sys"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "336244aaeab6a12df46480dc585802aa743a72d66b11937844c61bbca84c991d"
|
||||||
|
dependencies = [
|
||||||
|
"arbitrary",
|
||||||
|
"cc",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
25
gc/fuzz/Cargo.toml
Normal file
25
gc/fuzz/Cargo.toml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "gc-fuzz"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = ["Automatically generated"]
|
||||||
|
publish = false
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
cargo-fuzz = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] }
|
||||||
|
|
||||||
|
[dependencies.gc]
|
||||||
|
path = ".."
|
||||||
|
|
||||||
|
# Prevent this from interfering with workspaces
|
||||||
|
[workspace]
|
||||||
|
members = ["."]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "fuzz_target_1"
|
||||||
|
path = "fuzz_targets/fuzz_target_1.rs"
|
||||||
|
test = false
|
||||||
|
doc = false
|
83
gc/fuzz/fuzz_targets/fuzz_target_1.rs
Normal file
83
gc/fuzz/fuzz_targets/fuzz_target_1.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#![no_main]
|
||||||
|
use gc::{self, gc_ref::GcRef, test_utils::GotDropped, trace::GCTrace};
|
||||||
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use libfuzzer_sys::arbitrary;
|
||||||
|
|
||||||
|
#[derive(arbitrary::Arbitrary, Debug)]
|
||||||
|
struct ChildIDx(usize);
|
||||||
|
|
||||||
|
impl ChildIDx {
|
||||||
|
fn choose<'a, T>(&self, choices: &'a [T]) -> Option<&'a T> {
|
||||||
|
let idx = self.choose_index(choices.len())?;
|
||||||
|
Some(choices.get(idx).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_index(&self, len: usize) -> Option<usize> {
|
||||||
|
(len != 0).then(|| self.0 % len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(arbitrary::Arbitrary, Debug)]
|
||||||
|
enum GraphExplore {
|
||||||
|
ExploreChild(ChildIDx, Box<GraphExplore>),
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(arbitrary::Arbitrary, Debug)]
|
||||||
|
enum Op {
|
||||||
|
AddLink(GraphExplore, Option<GraphExplore>),
|
||||||
|
RemoveChild(GraphExplore, ChildIDx),
|
||||||
|
CollectGarbage,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(GCTrace, Default)]
|
||||||
|
struct Node {
|
||||||
|
children: Vec<GCNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type GCNode = GcRef<RefCell<Node>>;
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
fn explore(node: GCNode, instructions: GraphExplore) -> GCNode {
|
||||||
|
match instructions {
|
||||||
|
GraphExplore::ExploreChild(child_idx, child_instructions) => {
|
||||||
|
let child = child_idx
|
||||||
|
.choose(&*node.borrow().children)
|
||||||
|
.map(|v| v.clone());
|
||||||
|
child
|
||||||
|
.map(|c| Node::explore(c, *child_instructions))
|
||||||
|
.unwrap_or(node)
|
||||||
|
}
|
||||||
|
GraphExplore::Stop => node,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzz_target!(|ops: Vec<Op>| {
|
||||||
|
let mut allocator = gc::allocator::GCAllocator::default();
|
||||||
|
let root: GCNode = allocator.alloc(RefCell::default());
|
||||||
|
for op in ops {
|
||||||
|
match op {
|
||||||
|
Op::AddLink(parent_path, child_path) => {
|
||||||
|
let child = child_path
|
||||||
|
.map(|c| Node::explore(root.clone(), c))
|
||||||
|
.unwrap_or_else(|| allocator.alloc(RefCell::default()));
|
||||||
|
|
||||||
|
let parent = Node::explore(root.clone(), parent_path);
|
||||||
|
parent.borrow_mut().children.push(child);
|
||||||
|
}
|
||||||
|
Op::RemoveChild(parent_path, child_idx) => {
|
||||||
|
let parent = Node::explore(root.clone(), parent_path);
|
||||||
|
let children = &mut parent.borrow_mut().children;
|
||||||
|
let idx = child_idx.choose_index(children.len());
|
||||||
|
if let Some(idx) = idx {
|
||||||
|
children.remove(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::CollectGarbage => unsafe { allocator.gc(&root) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe { allocator.gc(&()) };
|
||||||
|
});
|
12
gc/gctrace-derive/Cargo.toml
Normal file
12
gc/gctrace-derive/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "gctrace-derive"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = "1.0.40"
|
||||||
|
quote = "1.0.20"
|
||||||
|
syn = "1.0.98"
|
75
gc/gctrace-derive/src/lib.rs
Normal file
75
gc/gctrace-derive/src/lib.rs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
use quote::{quote, quote_spanned};
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
use syn::{
|
||||||
|
parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics, Index,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a bound `T: GcTrace` to every type parameter T.
|
||||||
|
fn add_trait_bounds(mut generics: Generics) -> Generics {
|
||||||
|
for param in &mut generics.params {
|
||||||
|
if let GenericParam::Type(ref mut type_param) = *param {
|
||||||
|
type_param.bounds.push(parse_quote!(gc::trace::GcTrace));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generics
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate an expression to call trace on every gc field recursively.
|
||||||
|
fn gctrace_fields(data: &Data) -> TokenStream2 {
|
||||||
|
match *data {
|
||||||
|
Data::Struct(ref data) => match data.fields {
|
||||||
|
Fields::Named(ref fields) => {
|
||||||
|
let recurse = fields.named.iter().map(|f| {
|
||||||
|
let name = &f.ident;
|
||||||
|
quote_spanned! {f.span()=>
|
||||||
|
gc::trace::GCTrace::trace(&self.#name, tracer)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quote! {
|
||||||
|
#(#recurse;)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fields::Unnamed(ref fields) => {
|
||||||
|
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
||||||
|
let index = Index::from(i);
|
||||||
|
quote_spanned! {f.span()=>
|
||||||
|
gc::trace::GCTrace::trace(&self.#index, tracer)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quote! {
|
||||||
|
#(#recurse;)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fields::Unit => TokenStream2::default(),
|
||||||
|
},
|
||||||
|
Data::Enum(_) | Data::Union(_) => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(GCTrace)]
|
||||||
|
pub fn gctrace_derive(input: TokenStream) -> TokenStream {
|
||||||
|
// Parse the input tokens into a syntax tree
|
||||||
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
||||||
|
let name = input.ident;
|
||||||
|
|
||||||
|
let generics = add_trait_bounds(input.generics);
|
||||||
|
|
||||||
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
let trace_fields = gctrace_fields(&input.data);
|
||||||
|
|
||||||
|
// Build the output, possibly using quasi-quotation
|
||||||
|
//
|
||||||
|
let expanded = quote! {
|
||||||
|
unsafe impl #impl_generics gc::trace::GCTrace for #name #ty_generics #where_clause {
|
||||||
|
fn trace(&self, tracer: &mut gc::trace::GCTracer) {
|
||||||
|
#trace_fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hand the output tokens back to the compiler
|
||||||
|
TokenStream::from(expanded)
|
||||||
|
}
|
86
gc/src/allocator.rs
Normal file
86
gc/src/allocator.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
use super::gc_ref::GcRef;
|
||||||
|
use super::trace;
|
||||||
|
use crate::trace::GCTrace;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct GCAllocator {
|
||||||
|
allocations: Vec<Allocation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GCAllocator {
|
||||||
|
#[inline(always)]
|
||||||
|
/// Allocate a value on the heap
|
||||||
|
pub fn alloc<T: trace::GCTrace>(&mut self, x: T) -> GcRef<T> {
|
||||||
|
let alloc = Allocation::new(x);
|
||||||
|
let ptr = alloc.ptr as *mut T;
|
||||||
|
self.allocations.push(alloc);
|
||||||
|
unsafe { GcRef::new(NonNull::new(ptr).unwrap()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// Root needs to contain all the accessible gc allocated references
|
||||||
|
/// In case root itself is gc allocated use [`gc_ref_root`]
|
||||||
|
///
|
||||||
|
/// [`gc_ref_root`]: GCAllocator::gc_ref_root
|
||||||
|
pub unsafe fn gc<T: trace::GCTrace>(&mut self, root: &T) {
|
||||||
|
// Mark
|
||||||
|
let mut tracer = trace::GCTracer::with_capacity(self.allocations.len());
|
||||||
|
root.trace(&mut tracer);
|
||||||
|
|
||||||
|
// And sweep
|
||||||
|
let inaccessible = self
|
||||||
|
.allocations
|
||||||
|
.drain_filter(|a| !tracer.is_accessible(a.ptr));
|
||||||
|
|
||||||
|
// And sweep
|
||||||
|
for mut to_free in inaccessible {
|
||||||
|
to_free.drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specialization when ;-;
|
||||||
|
/// [`gc`] but for roots that are allocated on the heap
|
||||||
|
/// # Safety
|
||||||
|
/// See [`gc`]
|
||||||
|
///
|
||||||
|
/// [`gc`]: GCAllocator::gc
|
||||||
|
pub unsafe fn gc_ref_root<T: trace::GCTrace>(&mut self, root: &GcRef<T>) {
|
||||||
|
// Mark
|
||||||
|
let mut tracer = trace::GCTracer::with_capacity(self.allocations.len());
|
||||||
|
tracer.mark_reachable_rec(root);
|
||||||
|
root.trace(&mut tracer);
|
||||||
|
|
||||||
|
let inaccessible = self
|
||||||
|
.allocations
|
||||||
|
.drain_filter(|a| !tracer.is_accessible(a.ptr));
|
||||||
|
|
||||||
|
// And sweep
|
||||||
|
for mut to_free in inaccessible {
|
||||||
|
to_free.drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Allocation {
|
||||||
|
ptr: *mut (),
|
||||||
|
drop: unsafe fn(*mut ()),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Allocation {
|
||||||
|
fn new<T>(x: T) -> Self {
|
||||||
|
let alloc = Box::new(x);
|
||||||
|
let ptr = Box::into_raw(alloc) as *mut ();
|
||||||
|
|
||||||
|
let drop = |ptr| unsafe {
|
||||||
|
std::mem::drop(Box::from_raw(ptr as *mut T));
|
||||||
|
};
|
||||||
|
|
||||||
|
Self { ptr, drop }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { (self.drop)(self.ptr) };
|
||||||
|
}
|
||||||
|
}
|
44
gc/src/gc_ref.rs
Normal file
44
gc/src/gc_ref.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use std::{marker::PhantomData, ptr::NonNull};
|
||||||
|
|
||||||
|
use crate::trace::GCTrace;
|
||||||
|
|
||||||
|
pub struct GcRef<T: GCTrace>(pub(crate) NonNull<T>, PhantomData<T>);
|
||||||
|
|
||||||
|
impl<T: GCTrace> Clone for GcRef<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: GCTrace> GcRef<T> {
|
||||||
|
pub(crate) unsafe fn new(ptr: NonNull<T>) -> Self {
|
||||||
|
Self(ptr, PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The caller needs to ensure that the underlying pointer hasn't been garbage collected.
|
||||||
|
/// Since the drop order for garbage collected structs is undefined that means it is never
|
||||||
|
/// safe to call this function in a [Drop::drop].
|
||||||
|
///
|
||||||
|
/// Do note that this doesn't mean that any particular instance of GcRef has to be marked
|
||||||
|
/// as reachable during a call to [GCAllocator::gc][`crate::allocator::GCAllocator::gc`]
|
||||||
|
/// but instead any GcRef instance referring to the same underlying pointer has to be reachable
|
||||||
|
pub unsafe fn get(&self) -> &T {
|
||||||
|
unsafe { self.0.as_ref() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The caller needs to ensure that the underlying pointer hasn't been garbage collected.
|
||||||
|
/// See [GcRef::get] for more details
|
||||||
|
///
|
||||||
|
/// The caller needs to ensure that this is the only instance of a pointer to the underlying value
|
||||||
|
/// (in other words that [Clone] hasn't been called, or that all other clones of the pointer have
|
||||||
|
/// already been dropped).
|
||||||
|
///
|
||||||
|
/// This function is hard(but not impossible) to use without causing UB. Unless you have a
|
||||||
|
/// really special use case you might want to instead use one of various [cell][`std::cell`]
|
||||||
|
/// types as the allocated type.
|
||||||
|
pub unsafe fn get_mut(this: &mut Self) -> &mut T {
|
||||||
|
this.0.as_mut()
|
||||||
|
}
|
||||||
|
}
|
36
gc/src/lib.rs
Normal file
36
gc/src/lib.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#![feature(drain_filter)]
|
||||||
|
#![feature(negative_impls)]
|
||||||
|
|
||||||
|
pub mod allocator;
|
||||||
|
pub mod gc_ref;
|
||||||
|
pub mod trace;
|
||||||
|
mod trace_impl;
|
||||||
|
|
||||||
|
// make the test_utils mod pub to use it in fuzzing
|
||||||
|
pub mod test_utils;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) mod tests {
|
||||||
|
|
||||||
|
use super::allocator::GCAllocator;
|
||||||
|
use super::test_utils::GotDropped;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gc_allocates_and_frees_structs() {
|
||||||
|
let got_dropped = GotDropped::default();
|
||||||
|
|
||||||
|
let mut gc = GCAllocator::default();
|
||||||
|
gc.alloc(got_dropped.make_drop_checker());
|
||||||
|
|
||||||
|
unsafe { gc.gc(&()) };
|
||||||
|
assert!(got_dropped.was_dropped());
|
||||||
|
|
||||||
|
let got_dropped = GotDropped::default();
|
||||||
|
let drop_checker = gc.alloc(got_dropped.make_drop_checker());
|
||||||
|
|
||||||
|
unsafe { gc.gc(&(drop_checker,)) };
|
||||||
|
assert!(!got_dropped.was_dropped());
|
||||||
|
unsafe { gc.gc(&()) };
|
||||||
|
assert!(got_dropped.was_dropped());
|
||||||
|
}
|
||||||
|
}
|
28
gc/src/test_utils.rs
Normal file
28
gc/src/test_utils.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
use crate::trace::GCTrace;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct GotDropped(AtomicBool);
|
||||||
|
|
||||||
|
impl GotDropped {
|
||||||
|
pub fn make_drop_checker(&self) -> DropChecker {
|
||||||
|
DropChecker(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn was_dropped(&self) -> bool {
|
||||||
|
self.0.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DropChecker<'a>(pub &'a GotDropped);
|
||||||
|
|
||||||
|
impl<'a> Drop for DropChecker<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0 .0.store(true, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> GCTrace for DropChecker<'a> {
|
||||||
|
fn trace(&self, _tracer: &mut crate::trace::GCTracer) {}
|
||||||
|
}
|
45
gc/src/trace.rs
Normal file
45
gc/src/trace.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use std::{collections::HashSet, ops::Deref};
|
||||||
|
|
||||||
|
use crate::gc_ref::GcRef;
|
||||||
|
|
||||||
|
pub struct GCTracer {
|
||||||
|
accessible: HashSet<*const ()>,
|
||||||
|
explored: HashSet<*const ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GCTracer {
|
||||||
|
pub(super) fn with_capacity(cap: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
accessible: HashSet::with_capacity(cap),
|
||||||
|
explored: HashSet::with_capacity(cap),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_accessible(&self, ptr: *const ()) -> bool {
|
||||||
|
self.accessible.contains(&ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_reachable_rec<T: GCTrace>(&mut self, obj: &T) {
|
||||||
|
let ptr = obj as *const T as *const ();
|
||||||
|
if self.explored.insert(ptr) {
|
||||||
|
obj.trace(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use gctrace_derive::GCTrace;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Implementors of the trait *need* to ensure that every reachable reference gets marked as
|
||||||
|
/// reachable by callign trace on it
|
||||||
|
pub unsafe trait GCTrace {
|
||||||
|
fn trace(&self, _tracer: &mut GCTracer) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: GCTrace> GCTrace for GcRef<T> {
|
||||||
|
fn trace(&self, tracer: &mut GCTracer) {
|
||||||
|
tracer.accessible.insert(self.0.as_ptr() as *const ());
|
||||||
|
tracer.mark_reachable_rec(self.deref());
|
||||||
|
}
|
||||||
|
}
|
51
gc/src/trace_impl.rs
Normal file
51
gc/src/trace_impl.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use super::trace::{GCTrace, GCTracer};
|
||||||
|
use std::{cell::RefCell, collections::HashMap, ops::Deref};
|
||||||
|
unsafe impl GCTrace for () {}
|
||||||
|
unsafe impl GCTrace for i32 {}
|
||||||
|
unsafe impl GCTrace for u32 {}
|
||||||
|
unsafe impl GCTrace for i64 {}
|
||||||
|
unsafe impl GCTrace for u64 {}
|
||||||
|
unsafe impl GCTrace for f32 {}
|
||||||
|
unsafe impl GCTrace for f64 {}
|
||||||
|
unsafe impl GCTrace for bool {}
|
||||||
|
unsafe impl GCTrace for isize {}
|
||||||
|
unsafe impl GCTrace for usize {}
|
||||||
|
unsafe impl GCTrace for String {}
|
||||||
|
|
||||||
|
unsafe impl<T: GCTrace> GCTrace for (T,) {
|
||||||
|
fn trace(&self, tracer: &mut GCTracer) {
|
||||||
|
tracer.mark_reachable_rec(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: GCTrace> GCTrace for RefCell<T> {
|
||||||
|
fn trace(&self, tracer: &mut GCTracer) {
|
||||||
|
let borrow = self.borrow();
|
||||||
|
tracer.mark_reachable_rec(borrow.deref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: GCTrace> GCTrace for Option<T> {
|
||||||
|
fn trace(&self, tracer: &mut GCTracer) {
|
||||||
|
if let Some(ref v) = self {
|
||||||
|
tracer.mark_reachable_rec(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<K: GCTrace, V: GCTrace> GCTrace for HashMap<K, V> {
|
||||||
|
fn trace(&self, tracer: &mut GCTracer) {
|
||||||
|
for (k, v) in self.iter() {
|
||||||
|
tracer.mark_reachable_rec(k);
|
||||||
|
tracer.mark_reachable_rec(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: GCTrace> GCTrace for Vec<T> {
|
||||||
|
fn trace(&self, tracer: &mut GCTracer) {
|
||||||
|
for val in self.iter() {
|
||||||
|
tracer.mark_reachable_rec(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,20 +5,20 @@
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
if ! cargo fmt -- --check
|
if ! cargo fmt --all -- --check
|
||||||
then
|
then
|
||||||
echo "There are some code style issues."
|
echo "There are some code style issues."
|
||||||
echo "Run cargo fmt first."
|
echo "Run cargo fmt first."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! cargo clippy --all-targets -- -D warnings
|
if ! cargo clippy --all-targets --workspace -- -D warnings
|
||||||
then
|
then
|
||||||
echo "There are some clippy issues."
|
echo "There are some clippy issues."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! cargo test
|
if ! cargo test --workspace
|
||||||
then
|
then
|
||||||
echo "There are some test issues."
|
echo "There are some test issues."
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -52,6 +52,7 @@ impl<T: Error> ErrorLocationWrapper<T> {
|
||||||
|
|
||||||
impl<T: std::error::Error> ErrorWithLocation for ErrorLocationWrapper<T> {
|
impl<T: std::error::Error> ErrorWithLocation for ErrorLocationWrapper<T> {
|
||||||
fn get_location(&self) -> Location {
|
fn get_location(&self) -> Location {
|
||||||
|
#[allow(clippy::needless_borrow)]
|
||||||
(&self.location).into()
|
(&self.location).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::Interpret;
|
use super::Interpret;
|
||||||
use super::{types::Value, RuntimeError};
|
use super::{types::Primitive, RuntimeError};
|
||||||
use crate::ast::expression::{
|
use crate::ast::expression::{
|
||||||
self,
|
self,
|
||||||
operator::{Operator, UnaryOperator},
|
operator::{Operator, UnaryOperator},
|
||||||
|
@ -7,19 +7,19 @@ use crate::ast::expression::{
|
||||||
use crate::interpreter::world::World;
|
use crate::interpreter::world::World;
|
||||||
|
|
||||||
impl Interpret for expression::ExpressionNode {
|
impl Interpret for expression::ExpressionNode {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
expression::all_variants!(self, n => n.interpret(w))
|
expression::all_variants!(self, n => n.interpret(w))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for expression::Literal {
|
impl Interpret for expression::Literal {
|
||||||
fn interpret(&self, _: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, _: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
Ok(self.clone().into())
|
Ok(self.clone().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for expression::BinaryExpr {
|
impl Interpret for expression::BinaryExpr {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
let left_val = self.left.interpret(w).expect("expected lval");
|
let left_val = self.left.interpret(w).expect("expected lval");
|
||||||
let right_val = self.right.interpret(w).expect("expected rval");
|
let right_val = self.right.interpret(w).expect("expected rval");
|
||||||
match self.operator {
|
match self.operator {
|
||||||
|
@ -36,13 +36,13 @@ impl Interpret for expression::BinaryExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for expression::UnaryExpr {
|
impl Interpret for expression::UnaryExpr {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
let val = self.right.interpret(w)?;
|
let val = self.right.interpret(w)?;
|
||||||
match self.operator {
|
match self.operator {
|
||||||
UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())),
|
UnaryOperator::Bang => Ok(Primitive::Bool(!val.truthy())),
|
||||||
UnaryOperator::Minus => match val {
|
UnaryOperator::Minus => match val {
|
||||||
Value::Int(i) => Ok(Value::Int(-i)),
|
Primitive::Int(i) => Ok(Primitive::Int(-i)),
|
||||||
Value::Float(f) => Ok(Value::Float(-f)),
|
Primitive::Float(f) => Ok(Primitive::Float(-f)),
|
||||||
_ => Err(RuntimeError),
|
_ => Err(RuntimeError),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -50,25 +50,25 @@ impl Interpret for expression::UnaryExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for expression::GroupingExpr {
|
impl Interpret for expression::GroupingExpr {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
self.0.interpret(w)
|
self.0.interpret(w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for expression::VariableExpr {
|
impl Interpret for expression::VariableExpr {
|
||||||
fn interpret(&self, world: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, world: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
match world.get_var(&self.var_name) {
|
match world.get_var(&self.var_name) {
|
||||||
Some(v) => Ok(v.clone()),
|
Some(v) => Ok(v),
|
||||||
None => Err(RuntimeError),
|
None => Err(RuntimeError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for expression::BlockExpr {
|
impl Interpret for expression::BlockExpr {
|
||||||
fn interpret(&self, world: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, world: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
for stmnt in self.statements.iter() {
|
for stmnt in self.statements.iter() {
|
||||||
stmnt.interpret(world)?;
|
stmnt.interpret(world)?;
|
||||||
}
|
}
|
||||||
Ok(Value::Nil)
|
Ok(Primitive::Nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
mod expression_interpreter;
|
mod expression_interpreter;
|
||||||
mod statement_interpreter;
|
mod statement_interpreter;
|
||||||
pub use super::{error::RuntimeError, types};
|
pub use super::{error::RuntimeError, types};
|
||||||
use super::{types::Value, world::World};
|
use super::{types::Primitive, world::World};
|
||||||
|
|
||||||
pub trait Interpret {
|
pub trait Interpret {
|
||||||
fn interpret(&self, world: &mut World) -> Result<Value, RuntimeError>;
|
fn interpret(&self, world: &mut World) -> Result<Primitive, RuntimeError>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use super::Interpret;
|
use super::Interpret;
|
||||||
use super::{types::Value, RuntimeError};
|
use super::{types::Primitive, RuntimeError};
|
||||||
use crate::ast::statement;
|
use crate::ast::statement;
|
||||||
use crate::interpreter::world::World;
|
use crate::interpreter::world::World;
|
||||||
|
|
||||||
impl Interpret for statement::Statement {
|
impl Interpret for statement::Statement {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
statement::all_variants!(self, n => n.interpret(w))
|
statement::all_variants!(self, n => n.interpret(w))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for statement::PrintStatement {
|
impl Interpret for statement::PrintStatement {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
let res = self.0.interpret(w)?;
|
let res = self.0.interpret(w)?;
|
||||||
println!("{:?}", res);
|
println!("{:?}", res);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
@ -18,13 +18,13 @@ impl Interpret for statement::PrintStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for statement::ExpressionStatement {
|
impl Interpret for statement::ExpressionStatement {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
self.0.interpret(w)
|
self.0.interpret(w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for statement::VariableAssignmentStatement {
|
impl Interpret for statement::VariableAssignmentStatement {
|
||||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
fn interpret(&self, w: &mut World) -> Result<Primitive, RuntimeError> {
|
||||||
let expr_val = self.node.interpret(w)?;
|
let expr_val = self.node.interpret(w)?;
|
||||||
// Clone for now, later this will use a GC and won't need to clone
|
// Clone for now, later this will use a GC and won't need to clone
|
||||||
w.set_var(self.var_name.clone(), expr_val.clone());
|
w.set_var(self.var_name.clone(), expr_val.clone());
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::ast::expression;
|
use crate::ast::expression;
|
||||||
use from_variants::FromVariants;
|
use from_variants::FromVariants;
|
||||||
|
use gc::trace::GCTrace;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Clone, FromVariants)]
|
#[derive(Debug, PartialEq, PartialOrd, Clone, FromVariants)]
|
||||||
pub enum Value {
|
pub enum Primitive {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Float(f32),
|
Float(f32),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
@ -11,7 +12,9 @@ pub enum Value {
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<expression::Literal> for Value {
|
unsafe impl GCTrace for Primitive {}
|
||||||
|
|
||||||
|
impl From<expression::Literal> for Primitive {
|
||||||
fn from(l: expression::Literal) -> Self {
|
fn from(l: expression::Literal) -> Self {
|
||||||
match_any::match_any!(l,
|
match_any::match_any!(l,
|
||||||
expression::Literal::Int(v) | expression::Literal::Bool(v) | expression::Literal::Float(v) | expression::Literal::String(v) => v.into(),
|
expression::Literal::Int(v) | expression::Literal::Bool(v) | expression::Literal::Float(v) | expression::Literal::String(v) => v.into(),
|
||||||
|
@ -20,13 +23,13 @@ impl From<expression::Literal> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Value {
|
impl Default for Primitive {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Nil
|
Self::Nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Primitive {
|
||||||
pub fn truthy(&self) -> bool {
|
pub fn truthy(&self) -> bool {
|
||||||
!(matches!(*self, Self::Bool(false)))
|
!(matches!(*self, Self::Bool(false)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,59 @@
|
||||||
use std::collections::HashMap;
|
use std::{cell::RefCell, collections::HashMap};
|
||||||
|
|
||||||
|
use gc::{allocator::GCAllocator, gc_ref::GcRef, trace::GCTrace};
|
||||||
|
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ast_walker::{Interpret, RuntimeError},
|
ast_walker::{Interpret, RuntimeError},
|
||||||
types::Value,
|
types::Primitive,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default, GCTrace)]
|
||||||
|
pub struct Environment {
|
||||||
|
variables: HashMap<String, Primitive>,
|
||||||
|
parent: Option<GcRef<RefCell<Environment>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Environment {
|
||||||
|
// Update an already existing variable in current scope
|
||||||
|
pub fn update_var(&mut self, name: &str, v: Primitive) -> Option<Primitive> {
|
||||||
|
if let Some(cur) = self.variables.get_mut(name) {
|
||||||
|
Some(std::mem::replace(cur, v))
|
||||||
|
} else if let Some(ref parent) = self.parent {
|
||||||
|
unsafe { parent.get().borrow_mut().update_var(name, v) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_var(&mut self, name: String, v: Primitive) -> Option<Primitive> {
|
||||||
|
self.update_var(&name, v.clone())
|
||||||
|
.or_else(|| self.variables.insert(name, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_var(&self, name: &str) -> Option<Primitive> {
|
||||||
|
self.variables.get(name).cloned().or_else(|| {
|
||||||
|
if let Some(ref parent) = self.parent {
|
||||||
|
unsafe { parent.get().borrow().get_var(name) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct World {
|
pub struct World {
|
||||||
variables: HashMap<String, Value>,
|
env: GcRef<RefCell<Environment>>,
|
||||||
|
_gc: GCAllocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
pub fn set_var(&mut self, name: String, v: Value) -> Option<Value> {
|
pub fn set_var(&mut self, name: String, v: Primitive) -> Option<Primitive> {
|
||||||
self.variables.insert(name, v)
|
unsafe { self.env.get().borrow_mut().set_var(name, v) }
|
||||||
}
|
}
|
||||||
pub fn get_var(&mut self, name: &str) -> Option<&Value> {
|
pub fn get_var(&self, name: &str) -> Option<Primitive> {
|
||||||
self.variables.get(name)
|
unsafe { self.env.get().borrow().get_var(name) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,11 +61,17 @@ impl World {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
pub fn exec(&mut self, nodes: Vec<Statement>) -> Result<Value, RuntimeError> {
|
pub fn exec(&mut self, nodes: Vec<Statement>) -> Result<Primitive, RuntimeError> {
|
||||||
let mut last_res = Value::Nil;
|
nodes
|
||||||
for statement in nodes {
|
.into_iter()
|
||||||
last_res = statement.interpret(self)?;
|
.try_fold(Primitive::Nil, |_, stmnt| stmnt.interpret(self))
|
||||||
}
|
}
|
||||||
Ok(last_res)
|
}
|
||||||
|
|
||||||
|
impl Default for World {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut gc = GCAllocator::default();
|
||||||
|
let env = gc.alloc(RefCell::default());
|
||||||
|
Self { env, _gc: gc }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ impl<'a, 'b> Lexer<'a, 'b> {
|
||||||
}
|
}
|
||||||
found_period = true;
|
found_period = true;
|
||||||
}
|
}
|
||||||
c.is_digit(10) || c == '.'
|
c.is_ascii_digit() || c == '.'
|
||||||
});
|
});
|
||||||
let res = if found_period {
|
let res = if found_period {
|
||||||
num_str
|
num_str
|
||||||
|
|
|
@ -7,7 +7,7 @@ pub mod lexer;
|
||||||
use ast::parser::ParseAllResult;
|
use ast::parser::ParseAllResult;
|
||||||
use ast::statement::Statement;
|
use ast::statement::Statement;
|
||||||
use interpreter::ast_walker::{Interpret, RuntimeError};
|
use interpreter::ast_walker::{Interpret, RuntimeError};
|
||||||
use interpreter::types::Value;
|
use interpreter::types::Primitive;
|
||||||
use interpreter::world::World;
|
use interpreter::world::World;
|
||||||
use lexer::{token::Token, Lexer, LexingError};
|
use lexer::{token::Token, Lexer, LexingError};
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ pub fn parse(tokens: Vec<Token>) -> ParseAllResult {
|
||||||
parser.parse_all()
|
parser.parse_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec(nodes: Vec<Statement>) -> Result<Value, RuntimeError> {
|
pub fn exec(nodes: Vec<Statement>) -> Result<Primitive, RuntimeError> {
|
||||||
let mut last_res = Value::Nil;
|
let mut last_res = Primitive::Nil;
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
for statement in nodes {
|
for statement in nodes {
|
||||||
last_res = statement.interpret(&mut world)?;
|
last_res = statement.interpret(&mut world)?;
|
||||||
|
@ -33,7 +33,7 @@ pub fn exec(nodes: Vec<Statement>) -> Result<Value, RuntimeError> {
|
||||||
Ok(last_res)
|
Ok(last_res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(code: &str) -> Result<Value, run::Error> {
|
pub fn run(code: &str) -> Result<Primitive, run::Error> {
|
||||||
let tokens = lex(code, None)?;
|
let tokens = lex(code, None)?;
|
||||||
let nodes = parse(tokens)?;
|
let nodes = parse(tokens)?;
|
||||||
Ok(exec(nodes)?)
|
Ok(exec(nodes)?)
|
||||||
|
|
Loading…
Reference in a new issue