Compare commits

...

25 Commits

Author SHA1 Message Date
c3315f04e5 Working basic guard that falls back to interp on fail 2024-02-07 23:21:29 -05:00
ff95c5d9e7 implemented Lookup (also fix passing wrong function to one of the stack functions or something) 2024-02-07 02:03:57 -05:00
23fbfe9db3 add JIT support for Define, Drop, and Const 2024-02-06 02:13:19 -05:00
525b103f38 swap ret_stack to a repr(C) struct for manipulation from JIT 2024-02-05 01:41:55 -05:00
fd843bc807 Swap ID to NonZeroI64 so Option<ID> is a single word and we can test for 0 in JIT for if we have an ID (for looking at ret_stack) 2024-02-05 01:34:53 -05:00
a4500fed36 Implement (but have not tested) all primitive functions in JIT) 2024-02-05 01:26:57 -05:00
99d4fa5021 first jitted instruction! 2024-02-04 21:45:42 -05:00
776fc7c921 integrated JIT compiler with simple generated do-nothing JIT traces. Modified JIT trace interface so that it can return a trace-id and offset to jump to, allowing the trace interpreter to handle hard cases, etc. (or in this case, all cases, as it just immediatly returns the current id and offset 0). 2024-02-02 01:46:13 -05:00
9cd46a31eb had trouble getting going again today. Did create a compiled_traces map and integrated using it into execute_trace, with ideas for what the api there should be. 2024-02-01 02:09:04 -05:00
0ce6d90aa9 minor cleanup to wrap JIT stuff in a struct with a compile function and move to lib, in anticipation of actually JIT compiling. Not a ton of work today, was pretty tired / didn't get going. 2024-01-31 01:21:57 -05:00
facd9a34b9 Cranelift JIT experiments, with multiple functions, tail calls, non-tail-calls, calling host functions, etc 2024-01-30 02:36:06 -05:00
8e06037b4a Finished porting everything over to new packed, JIT-friendly Form, with all the tracing! 2024-01-29 02:22:56 -05:00
069c9775e1 Ported interpreter (without trace execution) to use new packed, JIT-friendly Form, with all needed additions 2024-01-29 02:03:59 -05:00
0696ad5594 Finished-ish writing the new JIT-friendly, packed Form, this time with extra repr(C) Vec implementation 2024-01-28 21:51:01 -05:00
a16e126aa1 Started writing our new Form designed to be used from JIT with repr(C) and packed into a single word, and our own repr(C) Rc implementation to go with it. 2024-01-28 02:46:08 -05:00
56cd4f7088 cleanup, fix closure scope error 2024-01-27 17:41:53 -05:00
3002bd9237 Working ExtendedBasicBlock tracing/lazy-construction! Not all constructs traceable, and no inlining, but it works! 2024-01-07 00:15:44 -05:00
1e59c8ed94 Small one today, getting started was hard but glad I got a tiny bit done to continue the streak. Modifed follow-on data to be stored on Ctx itself and only pass an ID around so it can be on the return stack multiple times without wasting a lot of space. 2024-01-04 01:15:42 -05:00
c15e857171 First barely-working trace replay! Need to clean up, finish implementing, have trace-reply restore traces, jump directly to other traces, eventually inline and concat traces, etc etc 2024-01-03 01:55:40 -05:00
71a2272f34 mostly correct looking traces. given up on actual constant prop during tracing, only constant tracking. Will need later pass to optimize. Also, want to shift the post-call trace to after the innermost return instead of tracking with the return stack. 2024-01-02 01:35:55 -05:00
2d5315f880 tracing/cont rework main 2023-12-29 23:37:04 -05:00
88e3fa9d39 Move dynamic stuff out of Cont and into two stacks so that Cont is good for resuming traces (having them depend only on code). Remove currently unneeded IDs from Symbol and Pair. Added an InlinePrim Op to tracing, and a nc: Cont to Call. IDs are probs only for trace points now (function starts and side-exits). 2023-12-26 01:03:56 -05:00
b40c928026 Reorganize naming scheme 2023-12-10 12:50:44 -05:00
3f3ea56375 Start working on calls 2023-12-10 00:56:02 -05:00
63a5b019ed Website typing improvements, uncommitted JIT work 2023-12-09 19:03:22 -05:00
22 changed files with 2551 additions and 1653 deletions

View File

@@ -12,11 +12,12 @@ Currently developing the fourth iteration, a Scheme-like based on a functional V
Working up to a JIT for fexprs by starting with
- sl - a Simple Lisp JIT (WIP)
- ?
- ?
- ?
- kv - A fexpr interpeter with mutation and delimited continuations - need to add a JIT to this
- [ ] slj - a Simple Lisp JIT (WIP)
- [ ] clj - a continuation lisp JIT?
- [ ] mlj - a mutation lisp JIT?
- [ ] flj - a fexpr Lisp JIT?
- [x] ki - A fexpr interpeter with mutation and delimited continuations
- [ ] kj - A fexpr+mutation+delimited continuations JIT
koka_bench: Licensed under Apache-2.0, as they are derived from the benchmarks of the Koka project, see the readme and license in koka_bench for more, or https://github.com/koka-lang/koka for the source project.

View File

View File

@@ -2,18 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@@ -71,142 +59,12 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50babaf4da30fd349e1b913760300266143535f15a0b7be7ce1ce9efafa8ff5e"
dependencies = [
"cranelift-codegen",
"cranelift-frontend",
]
[[package]]
name = "cranelift-bforest"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1277fbfa94bc82c8ec4af2ded3e639d49ca5f7f3c7eeab2c66accd135ece4e70"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e8c31ad3b2270e9aeec38723888fe1b0ace3bea2b06b3f749ccf46661d3220"
dependencies = [
"bumpalo",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"cranelift-entity",
"cranelift-isle",
"gimli",
"hashbrown 0.13.2",
"log",
"regalloc2",
"smallvec",
"target-lexicon",
]
[[package]]
name = "cranelift-codegen-meta"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ac5ac30d62b2d66f12651f6b606dbdfd9c2cfd0908de6b387560a277c5c9da"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd82b8b376247834b59ed9bdc0ddeb50f517452827d4a11bccf5937b213748b8"
[[package]]
name = "cranelift-entity"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40099d38061b37e505e63f89bab52199037a72b931ad4868d9089ff7268660b0"
[[package]]
name = "cranelift-frontend"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d"
dependencies = [
"cranelift-codegen",
"log",
"smallvec",
"target-lexicon",
]
[[package]]
name = "cranelift-isle"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80de6a7d0486e4acbd5f9f87ec49912bf4c8fb6aea00087b989685460d4469ba"
[[package]]
name = "cranelift-jit"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ca96b05988aa057eda09a817a6e31915fabd7f476b513123aff08053cd193dd"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"cranelift-module",
"cranelift-native",
"libc",
"log",
"region",
"target-lexicon",
"wasmtime-jit-icache-coherence",
"windows-sys 0.45.0",
]
[[package]]
name = "cranelift-module"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5112c0be9cc5da064e0620570d67852f11ce44f2e572a58ecf7f11df73978b8"
dependencies = [
"anyhow",
"cranelift-codegen",
]
[[package]]
name = "cranelift-native"
version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6b03e0e03801c4b3fd8ce0758a94750c07a44e7944cc0ffbf0d3f2e7c79b00"
dependencies = [
"cranelift-codegen",
"libc",
"target-lexicon",
]
[[package]]
name = "crunchy"
version = "0.2.2"
@@ -263,35 +121,20 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.7"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "getrandom"
version = "0.2.11"
@@ -303,37 +146,11 @@ dependencies = [
"wasi",
]
[[package]]
name = "gimli"
version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
dependencies = [
"fallible-iterator",
"indexmap 1.9.3",
"stable_deref_trait",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "hermit-abi"
@@ -341,16 +158,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.1.0"
@@ -358,7 +165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown 0.14.2",
"hashbrown",
]
[[package]]
@@ -382,14 +189,10 @@ dependencies = [
]
[[package]]
name = "kv"
name = "ki"
version = "0.1.0"
dependencies = [
"anyhow",
"cranelift",
"cranelift-jit",
"cranelift-module",
"cranelift-native",
"lalrpop",
"lalrpop-util",
"once_cell",
@@ -429,9 +232,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.150"
version = "0.2.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]]
name = "libredox"
@@ -446,9 +249,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.4.11"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "lock_api"
@@ -466,15 +269,6 @@ version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "mach"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.6.4"
@@ -489,9 +283,9 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "once_cell"
version = "1.18.0"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "parking_lot"
@@ -523,7 +317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [
"fixedbitset",
"indexmap 2.1.0",
"indexmap",
]
[[package]]
@@ -543,9 +337,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro2"
version = "1.0.69"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
dependencies = [
"unicode-ident",
]
@@ -579,18 +373,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "regalloc2"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80535183cae11b149d618fbd3c37e38d7cda589d82d7769e196ca9a9042d7621"
dependencies = [
"fxhash",
"log",
"slice-group-by",
"smallvec",
]
[[package]]
name = "regex"
version = "1.10.2"
@@ -626,29 +408,17 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "region"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
dependencies = [
"bitflags 1.3.2",
"libc",
"mach",
"winapi",
]
[[package]]
name = "rustix"
version = "0.38.25"
version = "0.38.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -669,24 +439,12 @@ version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "slice-group-by"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
[[package]]
name = "smallvec"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "string_cache"
version = "0.8.7"
@@ -711,12 +469,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "target-lexicon"
version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
[[package]]
name = "term"
version = "0.7.0"
@@ -769,29 +521,12 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "8.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd"
dependencies = [
"cfg-if",
"libc",
"windows-sys 0.45.0",
]
[[package]]
name = "winapi"
version = "0.3.9"
@@ -814,15 +549,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@@ -833,18 +559,12 @@ dependencies = [
]
[[package]]
name = "windows-targets"
version = "0.42.2"
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
"windows-targets 0.52.0",
]
[[package]]
@@ -863,10 +583,19 @@ dependencies = [
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
@@ -875,10 +604,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
@@ -887,10 +616,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
@@ -899,10 +628,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
@@ -911,10 +640,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
@@ -923,10 +652,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -935,10 +664,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
@@ -947,21 +676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "zerocopy"
version = "0.7.26"
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"

View File

@@ -1,5 +1,5 @@
[package]
name = "kv"
name = "ki"
version = "0.1.0"
edition = "2021"
build = "build.rs"
@@ -15,10 +15,6 @@ lalrpop-util = {version="0.19.7", features=["lexer"]}
regex = "1"
once_cell = "1.17.0"
anyhow = "1"
cranelift = "0.95.1"
cranelift-module = "0.95.1"
cranelift-jit = "0.95.1"
cranelift-native = "0.95.1"
[build-dependencies]
lalrpop = "0.19.7"

View File

@@ -1,7 +1,6 @@
use std::str::FromStr;
use std::rc::Rc;
use crate::basic::Form;
use crate::eval::FormT;
use ki::Form;
grammar;

View File

@@ -4,8 +4,6 @@ use std::rc::Rc;
use std::cell::RefCell;
use std::convert::From;
use crate::eval::{FormT,Cont,Cursor,PrimCombI};
#[derive(Debug, Eq, PartialEq)]
pub enum Form {
Nil,
@@ -16,7 +14,7 @@ pub enum Form {
Pair(Rc<Form>,Rc<Form>),
PrimComb { eval_limit: i32, ins: PrimCombI },
DeriComb { se: Rc<Form>, de: Option<String>, params: String, body: Rc<Form> },
ContComb(Cont<Form>),
ContComb(Cont),
}
// todo, strings not symbols?
@@ -88,9 +86,6 @@ impl Form {
_ => None,
}
}
}
impl FormT for Form {
fn sym(&self) -> Option<&str> {
match self {
Form::Symbol(s) => Some(s),
@@ -121,7 +116,7 @@ impl FormT for Form {
_ => false,
}
}
fn call(&self, p: Rc<Self>, e: Rc<Self>, nc: Box<Cont<Self>>, metac: Cont<Self>) -> Cursor<Self> {
fn call(&self, p: Rc<Self>, e: Rc<Self>, nc: Box<Cont>, metac: Cont) -> Cursor {
match self {
Form::PrimComb{eval_limit, ins} => {
Cursor { f: Rc::new(Form::Nil), c: Cont::PramEval { eval_limit: *eval_limit, to_eval: p, collected: None, e, ins: *ins, nc: nc }, metac }
@@ -142,7 +137,7 @@ impl FormT for Form {
}
}
}
fn impl_prim(ins: PrimCombI, e: Rc<Self>, ps: Vec<Rc<Self>>, c: Cont<Self>, metac: Cont<Self>) -> Cursor<Self> {
fn impl_prim(ins: PrimCombI, e: Rc<Self>, ps: Vec<Rc<Self>>, c: Cont, metac: Cont) -> Cursor {
match ins {
PrimCombI::Eval => Cursor { f: Rc::clone(&ps[0]), c: Cont::Eval { e: Rc::clone(&ps[1]), nc: Box::new(c) }, metac },
PrimCombI::Vau => {
@@ -238,6 +233,7 @@ impl FormT for Form {
}
}
fn assoc(k: &str, v: Rc<Form>, l: Rc<Form>) -> Rc<Form> {
Rc::new(Form::Pair(
Rc::new(Form::Pair(
@@ -306,3 +302,125 @@ pub fn root_env() -> Rc<Form> {
])
}
#[derive(Debug, Eq, PartialEq)]
pub enum Cont {
Exit,
MetaRet,
CatchRet { nc: Box<Cont>, restore_meta: Box<Cont> },
Eval { e: Rc<Form>, nc: Box<Cont> },
Call { p: Rc<Form>, e: Rc<Form>, nc: Box<Cont> },
PramEval { eval_limit: i32, to_eval: Rc<Form>, collected: Option<Vec<Rc<Form>>>, e: Rc<Form>, ins: PrimCombI, nc: Box<Cont> },
}
impl Clone for Cont {
fn clone(&self) -> Self {
match self {
Cont::Exit => Cont::Exit,
Cont::MetaRet => Cont::MetaRet,
Cont::CatchRet { nc, restore_meta } => Cont::CatchRet { nc: nc.clone(), restore_meta: restore_meta.clone() },
Cont::Eval { e, nc } => Cont::Eval { e: Rc::clone(e), nc: nc.clone() },
Cont::Call { p, e, nc } => Cont::Call { p: Rc::clone(p), e: Rc::clone(e), nc: nc.clone() },
Cont::PramEval { eval_limit, to_eval, collected, e, ins, nc} => Cont::PramEval { eval_limit: *eval_limit, to_eval: Rc::clone(to_eval),
collected: collected.as_ref().map(|x| x.iter().map(|x| Rc::clone(x)).collect()),
e: Rc::clone(e), ins: ins.clone(), nc: nc.clone() },
}
}
}
pub struct Cursor { pub f: Rc<Form>, pub c: Cont, pub metac: Cont }
pub fn eval(e: Rc<Form>, f: Rc<Form>) -> Rc<Form> {
let mut cursor = Cursor { f, c: Cont::Eval { e, nc: Box::new(Cont::MetaRet) }, metac: Cont::Exit };
loop {
let Cursor { f, c, metac } = cursor;
match c {
Cont::Exit => {
return f;
},
Cont::MetaRet => {
cursor = Cursor { f: f, c: metac.clone(), metac: metac };
},
Cont::CatchRet { nc, restore_meta } => {
cursor = Cursor { f: f, c: *nc, metac: *restore_meta };
},
Cont::Eval { e, nc } => {
if let Some((comb, p)) = f.pair() {
cursor = Cursor { f: comb, c: Cont::Eval { e: Rc::clone(&e), nc: Box::new(Cont::Call { p, e, nc }) }, metac }
} else if let Some(s) = f.sym() {
let mut t = Rc::clone(&e);
while s != t.car().unwrap().car().unwrap().sym().unwrap() {
t = t.cdr().unwrap();
}
cursor = Cursor { f: t.car().unwrap().cdr().unwrap(), c: *nc, metac };
} else {
cursor = Cursor { f: Rc::clone(&f), c: *nc, metac };
}
},
Cont::PramEval { eval_limit, to_eval, collected, e, ins, nc } => {
let mut next_collected = if let Some(mut collected) = collected {
collected.push(f); collected
} else { vec![] };
if eval_limit == 0 || to_eval.is_nil() {
let mut traverse = to_eval;
while !traverse.is_nil() {
next_collected.push(traverse.car().unwrap());
traverse = traverse.cdr().unwrap();
}
cursor = Form::impl_prim(ins, e, next_collected, *nc, metac);
} else {
cursor = Cursor { f: to_eval.car().unwrap(), c: Cont::Eval { e: Rc::clone(&e), nc: Box::new(Cont::PramEval { eval_limit: eval_limit - 1,
to_eval: to_eval.cdr().unwrap(),
collected: Some(next_collected),
e, ins, nc }) }, metac };
}
},
Cont::Call { p, e, nc } => {
cursor = f.call(p, e, nc, metac);
},
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum PrimCombI {
Eval,
Vau,
If,
Reset,
Shift,
Cell,
Set,
Get,
Cons,
Car,
Cdr,
Quote,
Assert,
Eq,
Lt,
LEq,
Gt,
GEq,
Plus,
Minus,
Mult,
Div,
Mod,
And,
Or,
Xor,
CombP,
CellP,
PairP,
SymbolP,
IntP,
BoolP,
NilP,
}

View File

@@ -3,12 +3,7 @@ lalrpop_mod!(pub grammar);
use std::rc::Rc;
mod basic;
use crate::basic::{root_env,Form};
mod eval;
use crate::eval::{eval};
mod opt;
use crate::opt::{OptForm};
use ki::{root_env,eval};
#[cfg(test)]
mod test;
@@ -21,11 +16,6 @@ fn main() {
//println!("Parsed input is {} - {:?}", parsed_input, parsed_input);
let root = root_env();
let result = eval(Rc::clone(&root), Rc::clone(&parsed_input));
let opt_root: Rc<OptForm> = (&*root).into();
let opt_input: Rc<OptForm> = (&*parsed_input).into();
let opt_result = eval(opt_root, opt_input);
println!("Result is {} - {:?}", result, result);
println!("Opt Result is {} - {:?}", opt_result, opt_result);
assert!(opt_result.congruent(&*result));
}

View File

@@ -1,9 +1,7 @@
use std::rc::Rc;
use crate::grammar;
use crate::basic::{root_env,Form};
use crate::opt::{OptForm};
use crate::eval::{eval};
use ki::{root_env,Form,eval};
#[test]
fn parse_test() {
@@ -20,83 +18,74 @@ fn parse_test() {
assert!(g.parse("((22)").is_err());
}
fn eval_test<T: Into<Form>>(also_pe: bool, gram: &grammar::TermParser, e: &Rc<Form>, code: &str, expected: T) {
fn eval_test<T: Into<Form>>(gram: &grammar::TermParser, e: &Rc<Form>, code: &str, expected: T) {
println!("Doing test {}", code);
let parsed = gram.parse(code).unwrap();
let basic_result = eval(Rc::clone(e), Rc::clone(&parsed));
assert_eq!(*basic_result, expected.into());
let opt_root: Rc<OptForm> = (&**e).into();
let opt_input: Rc<OptForm> = (&*parsed).into();
let opt_result = eval(opt_root, opt_input);
assert!(opt_result.congruent(&*basic_result));
//if also_pe {
//}
}
#[test]
fn basic_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, "(+ 2 (car (cons 4 '(1 2))))", 6);
eval_test(true, &g, &e, "(= 17 ((vau d p (+ (eval (car p) d) 13)) (+ 1 3)))", true);
eval_test(true, &g, &e, "(if (= 2 2) (+ 1 2) (+ 3 4))", 3);
eval_test(true, &g, &e, "(quote a)", "a");
eval_test(true, &g, &e, "'a", "a");
eval_test(true, &g, &e, "'(1 . a)", (1, "a"));
eval_test(true, &g, &e, "'(1 a)", (1, ("a", Form::Nil)));
eval_test(true, &g, &e, "true", true);
eval_test(true, &g, &e, "false", false);
eval_test(true, &g, &e, "nil", Form::Nil);
eval_test(&g, &e, "(+ 2 (car (cons 4 '(1 2))))", 6);
eval_test(&g, &e, "(= 17 ((vau d p (+ (eval (car p) d) 13)) (+ 1 3)))", true);
eval_test(&g, &e, "(if (= 2 2) (+ 1 2) (+ 3 4))", 3);
eval_test(&g, &e, "(quote a)", "a");
eval_test(&g, &e, "'a", "a");
eval_test(&g, &e, "'(1 . a)", (1, "a"));
eval_test(&g, &e, "'(1 a)", (1, ("a", Form::Nil)));
eval_test(&g, &e, "true", true);
eval_test(&g, &e, "false", false);
eval_test(&g, &e, "nil", Form::Nil);
eval_test(true, &g, &e, "(+ 1 2)", 3);
eval_test(true, &g, &e, "(- 1 2)", -1);
eval_test(true, &g, &e, "(* 1 2)", 2);
eval_test(true, &g, &e, "(/ 4 2)", 2);
eval_test(true, &g, &e, "(% 3 2)", 1);
eval_test(true, &g, &e, "(& 3 2)", 2);
eval_test(true, &g, &e, "(| 2 1)", 3);
eval_test(true, &g, &e, "(^ 2 1)", 3);
eval_test(true, &g, &e, "(^ 3 1)", 2);
eval_test(&g, &e, "(+ 1 2)", 3);
eval_test(&g, &e, "(- 1 2)", -1);
eval_test(&g, &e, "(* 1 2)", 2);
eval_test(&g, &e, "(/ 4 2)", 2);
eval_test(&g, &e, "(% 3 2)", 1);
eval_test(&g, &e, "(& 3 2)", 2);
eval_test(&g, &e, "(| 2 1)", 3);
eval_test(&g, &e, "(^ 2 1)", 3);
eval_test(&g, &e, "(^ 3 1)", 2);
eval_test(true, &g, &e, "(< 3 1)", false);
eval_test(true, &g, &e, "(<= 3 1)", false);
eval_test(true, &g, &e, "(> 3 1)", true);
eval_test(true, &g, &e, "(>= 3 1)", true);
eval_test(&g, &e, "(< 3 1)", false);
eval_test(&g, &e, "(<= 3 1)", false);
eval_test(&g, &e, "(> 3 1)", true);
eval_test(&g, &e, "(>= 3 1)", true);
eval_test(true, &g, &e, "(comb? +)", true);
eval_test(true, &g, &e, "(comb? (vau d p 1))", true);
eval_test(true, &g, &e, "(comb? 1)", false);
eval_test(true, &g, &e, "(pair? '(a))", true);
//eval_test(true, &g, &e, "(pair? '())", true);
eval_test(true, &g, &e, "(nil? nil)", true);
eval_test(true, &g, &e, "(nil? 1)", false);
eval_test(true, &g, &e, "(pair? 1)", false);
eval_test(true, &g, &e, "(symbol? 'a)", true);
eval_test(true, &g, &e, "(symbol? 1)", false);
eval_test(true, &g, &e, "(int? 1)", true);
eval_test(true, &g, &e, "(int? true)", false);
eval_test(true, &g, &e, "(bool? true)", true);
eval_test(true, &g, &e, "(bool? 1)", false);
eval_test(&g, &e, "(comb? +)", true);
eval_test(&g, &e, "(comb? (vau d p 1))", true);
eval_test(&g, &e, "(comb? 1)", false);
eval_test(&g, &e, "(pair? '(a))", true);
//eval_test(&g, &e, "(pair? '())", true);
eval_test(&g, &e, "(nil? nil)", true);
eval_test(&g, &e, "(nil? 1)", false);
eval_test(&g, &e, "(pair? 1)", false);
eval_test(&g, &e, "(symbol? 'a)", true);
eval_test(&g, &e, "(symbol? 1)", false);
eval_test(&g, &e, "(int? 1)", true);
eval_test(&g, &e, "(int? true)", false);
eval_test(&g, &e, "(bool? true)", true);
eval_test(&g, &e, "(bool? 1)", false);
eval_test(true, &g, &e, "!(bool?) 1", false);
eval_test(true, &g, &e, "!(bool?) true", true);
eval_test(&g, &e, "!(bool?) 1", false);
eval_test(&g, &e, "!(bool?) true", true);
eval_test(true, &g, &e, "((vau root_env _ (eval 'a (cons (cons 'a 2) root_env))))", 2);
eval_test(true, &g, &e, "'name-dash", "name-dash");
eval_test(&g, &e, "((vau root_env _ (eval 'a (cons (cons 'a 2) root_env))))", 2);
eval_test(&g, &e, "'name-dash", "name-dash");
eval_test(true, &g, &e, "(get (cell 1))", 1);
eval_test(true, &g, &e, "(set (cell 1) 2)", 1);
eval_test(true, &g, &e, "(cell? (cell 1))", true);
eval_test(true, &g, &e, "((vau de p (eval (quote (cons (set a 2) (get a))) (cons (cons (quote a) (cell 1)) de))))", (1,2));
eval_test(&g, &e, "(get (cell 1))", 1);
eval_test(&g, &e, "(set (cell 1) 2)", 1);
eval_test(&g, &e, "(cell? (cell 1))", true);
eval_test(&g, &e, "((vau de p (eval (quote (cons (set a 2) (get a))) (cons (cons (quote a) (cell 1)) de))))", (1,2));
eval_test(true, &g, &e, "(reset 1)", 1);
eval_test(true, &g, &e, "(reset (+ 1 2))", 3);
eval_test(true, &g, &e, "(reset (+ 1 (shift (vau de p 2))))", 2);
eval_test(true, &g, &e, "(reset (+ 1 (shift (vau de p ((car p) 2)))))", 3);
eval_test(true, &g, &e, "(reset (+ 1 (shift (vau de p ((car p) ((car p) 2)) ))))", 4);
eval_test(true, &g, &e, "(reset (+ 1 (shift (vau de p (+ ((car p) 3) ((car p) ((car p) 2))) ))))", 8);
eval_test(true, &g, &e, "((reset (+ 1 (shift (vau de p (car p))))) 2)", 3);
eval_test(&g, &e, "(reset 1)", 1);
eval_test(&g, &e, "(reset (+ 1 2))", 3);
eval_test(&g, &e, "(reset (+ 1 (shift (vau de p 2))))", 2);
eval_test(&g, &e, "(reset (+ 1 (shift (vau de p ((car p) 2)))))", 3);
eval_test(&g, &e, "(reset (+ 1 (shift (vau de p ((car p) ((car p) 2)) ))))", 4);
eval_test(&g, &e, "(reset (+ 1 (shift (vau de p (+ ((car p) 3) ((car p) ((car p) 2))) ))))", 8);
eval_test(&g, &e, "((reset (+ 1 (shift (vau de p (car p))))) 2)", 3);
}
@@ -111,7 +100,7 @@ static LET: Lazy<String> = Lazy::new(|| {
#[test]
fn fib_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (let1 x 10 (+ x 7))", *LET), 17);
eval_test(&g, &e, &format!("{} (let1 x 10 (+ x 7))", *LET), 17);
let def_fib = "
!(let1 fib (vau de p
!(let1 self (eval (car p) de))
@@ -120,7 +109,7 @@ fn fib_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
!(if (= 1 n) 1)
(+ (self self (- n 1)) (self self (- n 2)))
))";
eval_test(false, &g, &e, &format!("{} {} (fib fib 6)", *LET, def_fib), 8);
eval_test(&g, &e, &format!("{} {} (fib fib 6)", *LET, def_fib), 8);
}
#[test]
fn fact_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
@@ -131,7 +120,7 @@ fn fact_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
!(if (= 0 n) 1)
(* n (self self (- n 1)))
))";
eval_test(true, &g, &e, &format!("{} {} (fact fact 6)", *LET, def_fact), 720);
eval_test(&g, &e, &format!("{} {} (fact fact 6)", *LET, def_fact), 720);
}
static VAPPLY: Lazy<String> = Lazy::new(|| {
format!("
@@ -161,7 +150,7 @@ fn vapply_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
))", *VAPPLY);
// Won't work unless tail calls work
// so no PE?
eval_test(false, &g, &e, &format!("{} (badid 1000)", def_badid), 1000);
eval_test(&g, &e, &format!("{} (badid 1000)", def_badid), 1000);
}
static VMAP: Lazy<String> = Lazy::new(|| {
@@ -181,8 +170,8 @@ static VMAP: Lazy<String> = Lazy::new(|| {
#[test]
fn vmap_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
// Maybe define in terms of a right fold?
//eval_test(true, &g, &e, &format!("{} (vmap (vau de p (+ 1 (car p))) '(1 2 3))", *VMAP), (2, (3, (4, Form::Nil))));
eval_test(true, &g, &e, &format!("{} (vmap (vau de p (+ 1 (car p))) '(1))", *VMAP), (2, Form::Nil));
//eval_test(&g, &e, &format!("{} (vmap (vau de p (+ 1 (car p))) '(1 2 3))", *VMAP), (2, (3, (4, Form::Nil))));
eval_test(&g, &e, &format!("{} (vmap (vau de p (+ 1 (car p))) '(1))", *VMAP), (2, Form::Nil));
}
static WRAP: Lazy<String> = Lazy::new(|| {
@@ -196,7 +185,7 @@ static WRAP: Lazy<String> = Lazy::new(|| {
#[test]
fn wrap_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
// Make sure (wrap (vau ...)) and internal style are optimized the same
eval_test(true, &g, &e, &format!("{} ((wrap (vau _ p (+ (car p) 1))) (+ 1 2))", *WRAP), 4);
eval_test(&g, &e, &format!("{} ((wrap (vau _ p (+ (car p) 1))) (+ 1 2))", *WRAP), 4);
}
static UNWRAP: Lazy<String> = Lazy::new(|| {
@@ -211,10 +200,10 @@ static UNWRAP: Lazy<String> = Lazy::new(|| {
fn unwrap_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
// Can't represent prims in tests :( - they do work though, uncommenting and checking the
// failed assert verifies
//eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (car p))) (+ 1 2))", def_unwrap), ("quote", (("+", (1, (2, Form::Nil))), Form::Nil)));
//eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (eval (car p) de))) (+ 1 2))", def_unwrap), (("+", (1, (2, Form::Nil))), Form::Nil));
eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (eval (eval (car p) de) de))) (+ 1 2))", *UNWRAP), 3);
eval_test(true, &g, &e, &format!("{} ((unwrap (vau de p (+ (eval (eval (car p) de) de) 1))) (+ 1 2))", *UNWRAP), 4);
//eval_test(&g, &e, &format!("{} ((unwrap (vau de p (car p))) (+ 1 2))", def_unwrap), ("quote", (("+", (1, (2, Form::Nil))), Form::Nil)));
//eval_test(&g, &e, &format!("{} ((unwrap (vau de p (eval (car p) de))) (+ 1 2))", def_unwrap), (("+", (1, (2, Form::Nil))), Form::Nil));
eval_test(&g, &e, &format!("{} ((unwrap (vau de p (eval (eval (car p) de) de))) (+ 1 2))", *UNWRAP), 3);
eval_test(&g, &e, &format!("{} ((unwrap (vau de p (+ (eval (eval (car p) de) de) 1))) (+ 1 2))", *UNWRAP), 4);
}
static LAPPLY: Lazy<String> = Lazy::new(|| {
@@ -245,7 +234,7 @@ fn lapply_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
))", *LAPPLY);
// Won't work unless tail calls work
// takes a while though
eval_test(false, &g, &e, &format!("{} (lbadid 1000)", def_lbadid), 1000);
eval_test(&g, &e, &format!("{} (lbadid 1000)", def_lbadid), 1000);
}
static VFOLDL: Lazy<String> = Lazy::new(|| {
@@ -265,7 +254,7 @@ static VFOLDL: Lazy<String> = Lazy::new(|| {
});
#[test]
fn vfoldl_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (vfoldl (vau de p (+ (car p) (car (cdr p)))) 0 '(1 2 3))", *VFOLDL), 6);
eval_test(&g, &e, &format!("{} (vfoldl (vau de p (+ (car p) (car (cdr p)))) 0 '(1 2 3))", *VFOLDL), 6);
}
static ZIPD: Lazy<String> = Lazy::new(|| {
format!("
@@ -284,7 +273,7 @@ static ZIPD: Lazy<String> = Lazy::new(|| {
});
#[test]
fn zipd_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (zipd '(1 2 3) '(4 5 6))", *ZIPD), ((1,4), ((2,5), ((3,6), Form::Nil))));
eval_test(&g, &e, &format!("{} (zipd '(1 2 3) '(4 5 6))", *ZIPD), ((1,4), ((2,5), ((3,6), Form::Nil))));
}
static CONCAT: Lazy<String> = Lazy::new(|| {
format!("
@@ -303,7 +292,7 @@ static CONCAT: Lazy<String> = Lazy::new(|| {
#[test]
fn concat_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (concat '(1 2 3) '(4 5 6))", *CONCAT), (1, (2, (3, (4, (5, (6, Form::Nil)))))));
eval_test(&g, &e, &format!("{} (concat '(1 2 3) '(4 5 6))", *CONCAT), (1, (2, (3, (4, (5, (6, Form::Nil)))))));
}
static BVAU: Lazy<String> = Lazy::new(|| {
@@ -339,20 +328,20 @@ static BVAU: Lazy<String> = Lazy::new(|| {
});
#[test]
fn bvau_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} ((bvau _ (a b c) (+ a (- b c))) 10 2 3)", *BVAU), 9);
eval_test(true, &g, &e, &format!("{} ((bvau (a b c) (+ a (- b c))) 10 2 3)", *BVAU), 9);
eval_test(&g, &e, &format!("{} ((bvau _ (a b c) (+ a (- b c))) 10 2 3)", *BVAU), 9);
eval_test(&g, &e, &format!("{} ((bvau (a b c) (+ a (- b c))) 10 2 3)", *BVAU), 9);
eval_test(true, &g, &e, &format!("{} ((bvau (a b . c) c) 10 2 3)", *BVAU), (3, Form::Nil));
eval_test(true, &g, &e, &format!("{} ((bvau (a b . c) c) 10 2)", *BVAU), Form::Nil);
eval_test(true, &g, &e, &format!("{} ((bvau (a b . c) c) 10 2 3 4 5)", *BVAU), (3, (4, (5, Form::Nil))));
eval_test(true, &g, &e, &format!("{} ((bvau c c) 3 4 5)", *BVAU), (3, (4, (5, Form::Nil))));
eval_test(true, &g, &e, &format!("{} ((bvau c c))", *BVAU), Form::Nil);
eval_test(true, &g, &e, &format!("{} ((bvau ((a b) . c) c) (10 2) 3 4 5)", *BVAU), (3, (4, (5, Form::Nil))));
eval_test(true, &g, &e, &format!("{} ((bvau ((a b) . c) a) (10 2) 3 4 5)", *BVAU), 10);
eval_test(true, &g, &e, &format!("{} ((bvau ((a b) . c) b) (10 2) 3 4 5)", *BVAU), 2);
eval_test(&g, &e, &format!("{} ((bvau (a b . c) c) 10 2 3)", *BVAU), (3, Form::Nil));
eval_test(&g, &e, &format!("{} ((bvau (a b . c) c) 10 2)", *BVAU), Form::Nil);
eval_test(&g, &e, &format!("{} ((bvau (a b . c) c) 10 2 3 4 5)", *BVAU), (3, (4, (5, Form::Nil))));
eval_test(&g, &e, &format!("{} ((bvau c c) 3 4 5)", *BVAU), (3, (4, (5, Form::Nil))));
eval_test(&g, &e, &format!("{} ((bvau c c))", *BVAU), Form::Nil);
eval_test(&g, &e, &format!("{} ((bvau ((a b) . c) c) (10 2) 3 4 5)", *BVAU), (3, (4, (5, Form::Nil))));
eval_test(&g, &e, &format!("{} ((bvau ((a b) . c) a) (10 2) 3 4 5)", *BVAU), 10);
eval_test(&g, &e, &format!("{} ((bvau ((a b) . c) b) (10 2) 3 4 5)", *BVAU), 2);
eval_test(true, &g, &e, &format!("{} ((wrap (bvau _ (a b c) (+ a (- b c)))) (+ 10 1) (+ 2 2) (+ 5 3))", *BVAU), 7);
eval_test(true, &g, &e, &format!("{} ((wrap (bvau (a b c) (+ a (- b c)))) (+ 10 1) (+ 2 2) (+ 5 3))", *BVAU), 7);
eval_test(&g, &e, &format!("{} ((wrap (bvau _ (a b c) (+ a (- b c)))) (+ 10 1) (+ 2 2) (+ 5 3))", *BVAU), 7);
eval_test(&g, &e, &format!("{} ((wrap (bvau (a b c) (+ a (- b c)))) (+ 10 1) (+ 2 2) (+ 5 3))", *BVAU), 7);
}
static LAMBDA: Lazy<String> = Lazy::new(|| {
@@ -364,19 +353,19 @@ static LAMBDA: Lazy<String> = Lazy::new(|| {
});
#[test]
fn lambda_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} ((lambda (a b c) (+ a (- b c))) (+ 10 1) (+ 2 2) (+ 5 3))", *LAMBDA), 7);
eval_test(true, &g, &e, &format!("{} ((lambda (a b . c) c) 10 2 3)", *LAMBDA), (3, Form::Nil));
eval_test(true, &g, &e, &format!("{} ((lambda (a b . c) c) 10 2)", *LAMBDA), Form::Nil);
eval_test(true, &g, &e, &format!("{} ((lambda (a b . c) c) 10 2 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil))));
eval_test(true, &g, &e, &format!("{} ((lambda c c) 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil))));
eval_test(true, &g, &e, &format!("{} ((lambda c c))", *LAMBDA), Form::Nil);
eval_test(true, &g, &e, &format!("{} ((lambda ((a b) . c) c) '(10 2) 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil))));
eval_test(true, &g, &e, &format!("{} ((lambda ((a b) . c) a) '(10 2) 3 4 5)", *LAMBDA), 10);
eval_test(true, &g, &e, &format!("{} ((lambda ((a b) . c) b) '(10 2) 3 4 5)", *LAMBDA), 2);
eval_test(true, &g, &e, &format!("{} ((lambda ((a b . c) d) b) '(10 2 3 4) 3)", *LAMBDA), 2);
eval_test(true, &g, &e, &format!("{} ((lambda ((a b . c) d) c) '(10 2 3 4) 3)", *LAMBDA), (3, (4, Form::Nil)));
eval_test(&g, &e, &format!("{} ((lambda (a b c) (+ a (- b c))) (+ 10 1) (+ 2 2) (+ 5 3))", *LAMBDA), 7);
eval_test(&g, &e, &format!("{} ((lambda (a b . c) c) 10 2 3)", *LAMBDA), (3, Form::Nil));
eval_test(&g, &e, &format!("{} ((lambda (a b . c) c) 10 2)", *LAMBDA), Form::Nil);
eval_test(&g, &e, &format!("{} ((lambda (a b . c) c) 10 2 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil))));
eval_test(&g, &e, &format!("{} ((lambda c c) 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil))));
eval_test(&g, &e, &format!("{} ((lambda c c))", *LAMBDA), Form::Nil);
eval_test(&g, &e, &format!("{} ((lambda ((a b) . c) c) '(10 2) 3 4 5)", *LAMBDA), (3, (4, (5, Form::Nil))));
eval_test(&g, &e, &format!("{} ((lambda ((a b) . c) a) '(10 2) 3 4 5)", *LAMBDA), 10);
eval_test(&g, &e, &format!("{} ((lambda ((a b) . c) b) '(10 2) 3 4 5)", *LAMBDA), 2);
eval_test(&g, &e, &format!("{} ((lambda ((a b . c) d) b) '(10 2 3 4) 3)", *LAMBDA), 2);
eval_test(&g, &e, &format!("{} ((lambda ((a b . c) d) c) '(10 2 3 4) 3)", *LAMBDA), (3, (4, Form::Nil)));
// should fail
//eval_test(true, &g, &e, &format!("{} ((lambda (a b c) c) 10 2 3 4)", *LAMBDA), 3);
//eval_test(&g, &e, &format!("{} ((lambda (a b c) c) 10 2 3 4)", *LAMBDA), 3);
}
static LET2: Lazy<String> = Lazy::new(|| {
@@ -391,16 +380,16 @@ static LET2: Lazy<String> = Lazy::new(|| {
#[test]
fn let2_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (let1 x (+ 10 1) (+ x 1))", *LET2), 12);
eval_test(true, &g, &e, &format!("{} (let1 x '(10 1) x)", *LET2), (10, (1, Form::Nil)));
eval_test(true, &g, &e, &format!("{} (let1 (a b) '(10 1) a)", *LET2), 10);
eval_test(true, &g, &e, &format!("{} (let1 (a b) '(10 1) b)", *LET2), 1);
eval_test(true, &g, &e, &format!("{} (let1 (a b . c) '(10 1) c)", *LET2), Form::Nil);
eval_test(true, &g, &e, &format!("{} (let1 (a b . c) '(10 1 2 3) c)", *LET2), (2, (3, Form::Nil)));
eval_test(true, &g, &e, &format!("{} (let1 ((a . b) . c) '((10 1) 2 3) a)", *LET2), 10);
eval_test(true, &g, &e, &format!("{} (let1 ((a . b) . c) '((10 1) 2 3) b)", *LET2), (1, Form::Nil));
eval_test( &g, &e, &format!("{} (let1 x (+ 10 1) (+ x 1))", *LET2), 12);
eval_test( &g, &e, &format!("{} (let1 x '(10 1) x)", *LET2), (10, (1, Form::Nil)));
eval_test( &g, &e, &format!("{} (let1 (a b) '(10 1) a)", *LET2), 10);
eval_test( &g, &e, &format!("{} (let1 (a b) '(10 1) b)", *LET2), 1);
eval_test( &g, &e, &format!("{} (let1 (a b . c) '(10 1) c)", *LET2), Form::Nil);
eval_test( &g, &e, &format!("{} (let1 (a b . c) '(10 1 2 3) c)", *LET2), (2, (3, Form::Nil)));
eval_test( &g, &e, &format!("{} (let1 ((a . b) . c) '((10 1) 2 3) a)", *LET2), 10);
eval_test( &g, &e, &format!("{} (let1 ((a . b) . c) '((10 1) 2 3) b)", *LET2), (1, Form::Nil));
// should fail
//eval_test(true, &g, &e, &format!("{} (let1 (a b c) '(10 2 3 4) a)", *LET2), 10);
//eval_test(&g, &e, &format!("{} (let1 (a b c) '(10 2 3 4) a)", *LET2), 10);
}
static LIST: Lazy<String> = Lazy::new(|| {
@@ -412,7 +401,7 @@ static LIST: Lazy<String> = Lazy::new(|| {
#[test]
fn list_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (list 1 2 (+ 3 4))", *LIST), (1, (2, (7, Form::Nil))));
eval_test(&g, &e, &format!("{} (list 1 2 (+ 3 4))", *LIST), (1, (2, (7, Form::Nil))));
}
static Y: Lazy<String> = Lazy::new(|| {
@@ -428,7 +417,7 @@ static Y: Lazy<String> = Lazy::new(|| {
#[test]
fn y_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} ((Y (lambda (recurse) (lambda (n) (if (= 0 n) 1 (* n (recurse (- n 1))))))) 5)", *Y), 120);
eval_test(&g, &e, &format!("{} ((Y (lambda (recurse) (lambda (n) (if (= 0 n) 1 (* n (recurse (- n 1))))))) 5)", *Y), 120);
}
@@ -443,7 +432,7 @@ static RLAMBDA: Lazy<String> = Lazy::new(|| {
#[test]
fn rlambda_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} ((rlambda recurse (n) (if (= 0 n) 1 (* n (recurse (- n 1))))) 5)", *RLAMBDA), 120);
eval_test(&g, &e, &format!("{} ((rlambda recurse (n) (if (= 0 n) 1 (* n (recurse (- n 1))))) 5)", *RLAMBDA), 120);
}
static AND_OR: Lazy<String> = Lazy::new(|| {
// need to extend for varidac
@@ -462,15 +451,15 @@ static AND_OR: Lazy<String> = Lazy::new(|| {
#[test]
fn and_or_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (and true true)", *AND_OR), true);
eval_test(true, &g, &e, &format!("{} (and false true)", *AND_OR), false);
eval_test(true, &g, &e, &format!("{} (and true false)", *AND_OR), false);
eval_test(true, &g, &e, &format!("{} (and false false)", *AND_OR), false);
eval_test(&g, &e, &format!("{} (and true true)", *AND_OR), true);
eval_test(&g, &e, &format!("{} (and false true)", *AND_OR), false);
eval_test(&g, &e, &format!("{} (and true false)", *AND_OR), false);
eval_test(&g, &e, &format!("{} (and false false)", *AND_OR), false);
eval_test(true, &g, &e, &format!("{} (or true true)", *AND_OR), true);
eval_test(true, &g, &e, &format!("{} (or false true)", *AND_OR), true);
eval_test(true, &g, &e, &format!("{} (or true false)", *AND_OR), true);
eval_test(true, &g, &e, &format!("{} (or false false)", *AND_OR), false);
eval_test(&g, &e, &format!("{} (or true true)", *AND_OR), true);
eval_test(&g, &e, &format!("{} (or false true)", *AND_OR), true);
eval_test(&g, &e, &format!("{} (or true false)", *AND_OR), true);
eval_test(&g, &e, &format!("{} (or false false)", *AND_OR), false);
}
static LEN: Lazy<String> = Lazy::new(|| {
format!("
@@ -487,10 +476,10 @@ static LEN: Lazy<String> = Lazy::new(|| {
#[test]
fn len_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (len '())", *LEN), 0);
eval_test(true, &g, &e, &format!("{} (len '(1))", *LEN), 1);
eval_test(true, &g, &e, &format!("{} (len '(1 2))", *LEN), 2);
eval_test(true, &g, &e, &format!("{} (len '(1 2 3))", *LEN), 3);
eval_test(&g, &e, &format!("{} (len '())", *LEN), 0);
eval_test(&g, &e, &format!("{} (len '(1))", *LEN), 1);
eval_test(&g, &e, &format!("{} (len '(1 2))", *LEN), 2);
eval_test(&g, &e, &format!("{} (len '(1 2 3))", *LEN), 3);
}
static MATCH: Lazy<String> = Lazy::new(|| {
format!("
@@ -527,11 +516,11 @@ static MATCH: Lazy<String> = Lazy::new(|| {
});
#[test]
fn match_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(true, &g, &e, &format!("{} (match (+ 1 2) 1 2 2 3 3 4 _ 0)", *MATCH), 4);
eval_test(true, &g, &e, &format!("{} (match '(1 2) 1 2 2 3 3 4 _ 0)", *MATCH), 0);
eval_test(true, &g, &e, &format!("{} (match '(1 2) 1 2 2 3 (a b) (+ a (+ 2 b)) _ 0)", *MATCH), 5);
eval_test(true, &g, &e, &format!("{} (match '(1 2) 1 2 2 3 '(1 2) 7 _ 0)", *MATCH), 7);
eval_test(true, &g, &e, &format!("{} (let1 a 70 (match (+ 60 10) (unquote a) 100 2 3 _ 0))", *MATCH), 100);
eval_test(&g, &e, &format!("{} (match (+ 1 2) 1 2 2 3 3 4 _ 0)", *MATCH), 4);
eval_test(&g, &e, &format!("{} (match '(1 2) 1 2 2 3 3 4 _ 0)", *MATCH), 0);
eval_test(&g, &e, &format!("{} (match '(1 2) 1 2 2 3 (a b) (+ a (+ 2 b)) _ 0)", *MATCH), 5);
eval_test(&g, &e, &format!("{} (match '(1 2) 1 2 2 3 '(1 2) 7 _ 0)", *MATCH), 7);
eval_test(&g, &e, &format!("{} (let1 a 70 (match (+ 60 10) (unquote a) 100 2 3 _ 0))", *MATCH), 100);
}
static RBTREE: Lazy<String> = Lazy::new(|| {
format!("
@@ -578,6 +567,6 @@ static RBTREE: Lazy<String> = Lazy::new(|| {
});
#[test]
fn rbtree_eval_test() { let g = grammar::TermParser::new(); let e = root_env();
eval_test(false, &g, &e, &format!("{} (reduce-test-tree (make-test-tree 10 map-empty))", *RBTREE), 1);
//eval_test(false, &g, &e, &format!("{} (reduce-test-tree (make-test-tree 20 map-empty))", *RBTREE), 2);
eval_test(&g, &e, &format!("{} (reduce-test-tree (make-test-tree 10 map-empty))", *RBTREE), 1);
//eval_test(&g, &e, &format!("{} (reduce-test-tree (make-test-tree 20 map-empty))", *RBTREE), 2);
}

View File

@@ -1,136 +0,0 @@
use std::fmt;
use std::boxed::Box;
use std::rc::Rc;
use std::cell::RefCell;
use std::convert::From;
pub trait FormT: std::fmt::Debug {
fn sym(&self) -> Option<&str>;
fn pair(&self) -> Option<(Rc<Self>,Rc<Self>)>;
fn car(&self) -> Option<Rc<Self>>;
fn cdr(&self) -> Option<Rc<Self>>;
fn is_nil(&self) -> bool;
fn call(&self, p: Rc<Self>, e: Rc<Self>, nc: Box<Cont<Self>>, metac: Cont<Self>) -> Cursor<Self>;
fn impl_prim(ins: PrimCombI, e: Rc<Self>, ps: Vec<Rc<Self>>, c: Cont<Self>, metac: Cont<Self>) -> Cursor<Self>;
}
#[derive(Debug, Eq, PartialEq)]
pub enum Cont<F: FormT + ?Sized> {
Exit,
MetaRet,
CatchRet { nc: Box<Cont<F>>, restore_meta: Box<Cont<F>> },
Eval { e: Rc<F>, nc: Box<Cont<F>> },
Call { p: Rc<F>, e: Rc<F>, nc: Box<Cont<F>> },
PramEval { eval_limit: i32, to_eval: Rc<F>, collected: Option<Vec<Rc<F>>>, e: Rc<F>, ins: PrimCombI, nc: Box<Cont<F>> },
}
impl<F: FormT> Clone for Cont<F> {
fn clone(&self) -> Self {
match self {
Cont::Exit => Cont::Exit,
Cont::MetaRet => Cont::MetaRet,
Cont::CatchRet { nc, restore_meta } => Cont::CatchRet { nc: nc.clone(), restore_meta: restore_meta.clone() },
Cont::Eval { e, nc } => Cont::Eval { e: Rc::clone(e), nc: nc.clone() },
Cont::Call { p, e, nc } => Cont::Call { p: Rc::clone(p), e: Rc::clone(e), nc: nc.clone() },
Cont::PramEval { eval_limit, to_eval, collected, e, ins, nc} => Cont::PramEval { eval_limit: *eval_limit, to_eval: Rc::clone(to_eval),
collected: collected.as_ref().map(|x| x.iter().map(|x| Rc::clone(x)).collect()),
e: Rc::clone(e), ins: ins.clone(), nc: nc.clone() },
}
}
}
pub struct Cursor<F: FormT + ?Sized> { pub f: Rc<F>, pub c: Cont<F>, pub metac: Cont<F> }
pub fn eval<F: FormT>(e: Rc<F>, f: Rc<F>) -> Rc<F> {
let mut cursor = Cursor::<F> { f, c: Cont::Eval { e, nc: Box::new(Cont::MetaRet) }, metac: Cont::Exit };
loop {
let Cursor { f, c, metac } = cursor;
match c {
Cont::Exit => {
return f;
},
Cont::MetaRet => {
cursor = Cursor { f: f, c: metac.clone(), metac: metac };
},
Cont::CatchRet { nc, restore_meta } => {
cursor = Cursor { f: f, c: *nc, metac: *restore_meta };
},
Cont::Eval { e, nc } => {
if let Some((comb, p)) = f.pair() {
cursor = Cursor { f: comb, c: Cont::Eval { e: Rc::clone(&e), nc: Box::new(Cont::Call { p, e, nc }) }, metac }
} else if let Some(s) = f.sym() {
let mut t = Rc::clone(&e);
while s != t.car().unwrap().car().unwrap().sym().unwrap() {
t = t.cdr().unwrap();
}
cursor = Cursor { f: t.car().unwrap().cdr().unwrap(), c: *nc, metac };
} else {
cursor = Cursor { f: Rc::clone(&f), c: *nc, metac };
}
},
Cont::PramEval { eval_limit, to_eval, collected, e, ins, nc } => {
let mut next_collected = if let Some(mut collected) = collected {
collected.push(f); collected
} else { vec![] };
if eval_limit == 0 || to_eval.is_nil() {
let mut traverse = to_eval;
while !traverse.is_nil() {
next_collected.push(traverse.car().unwrap());
traverse = traverse.cdr().unwrap();
}
cursor = F::impl_prim(ins, e, next_collected, *nc, metac);
} else {
cursor = Cursor { f: to_eval.car().unwrap(), c: Cont::Eval { e: Rc::clone(&e), nc: Box::new(Cont::PramEval { eval_limit: eval_limit - 1,
to_eval: to_eval.cdr().unwrap(),
collected: Some(next_collected),
e, ins, nc }) }, metac };
}
},
Cont::Call { p, e, nc } => {
cursor = f.call(p, e, nc, metac);
},
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum PrimCombI {
Eval,
Vau,
If,
Reset,
Shift,
Cell,
Set,
Get,
Cons,
Car,
Cdr,
Quote,
Assert,
Eq,
Lt,
LEq,
Gt,
GEq,
Plus,
Minus,
Mult,
Div,
Mod,
And,
Or,
Xor,
CombP,
CellP,
PairP,
SymbolP,
IntP,
BoolP,
NilP,
}

View File

@@ -1,294 +0,0 @@
use std::fmt;
use std::boxed::Box;
use std::rc::Rc;
use std::cell::RefCell;
use std::convert::From;
use crate::eval::{FormT,Cont,Cursor,PrimCombI};
use crate::basic::Form;
#[derive(Debug, Eq, PartialEq)]
struct Trace {}
#[derive(Debug, Eq, PartialEq)]
pub struct OptForm {
inner: OptFormInner,
trace: Option<Rc<Trace>>
}
#[derive(Debug, Eq, PartialEq)]
pub enum OptFormInner {
Nil,
Int(i32),
Bool(bool),
Symbol(String),
Cell(RefCell<Rc<OptForm>>),
Pair(Rc<OptForm>,Rc<OptForm>),
PrimComb { eval_limit: i32, ins: PrimCombI },
DeriComb { se: Rc<OptForm>, de: Option<String>, params: String, body: Rc<OptForm>, code: Option<Rc<RefCell<Vec<ByteCode>>>> },
ContComb(Cont<OptForm>),
}
#[derive(Debug, Eq, PartialEq)]
pub enum ByteCode {
Ins(PrimCombI)
}
impl fmt::Display for OptForm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
OptFormInner::Nil => write!(f, "nil"),
OptFormInner::Int(i) => write!(f, "{i}"),
OptFormInner::Bool(b) => write!(f, "{b}"),
OptFormInner::Symbol(s) => write!(f, "{s}"),
OptFormInner::Cell(c) => write!(f, "@{}", c.borrow()),
OptFormInner::Pair(car, cdr) => {
write!(f, "({}", car)?;
let mut traverse: Rc<OptForm> = Rc::clone(cdr);
loop {
match &traverse.inner {
OptFormInner::Pair(ref carp, ref cdrp) => {
write!(f, " {}", carp)?;
traverse = Rc::clone(cdrp);
},
OptFormInner::Nil => {
write!(f, ")")?;
return Ok(());
},
x => {
write!(f, ". {})", traverse)?;
return Ok(());
},
}
}
},
OptFormInner::PrimComb { eval_limit, ins } => write!(f, "<{eval_limit}> - {ins:?}"),
OptFormInner::DeriComb { se: _, de, params, body, code: _ } => {
write!(f, "<{} {} {}>", de.as_ref().unwrap_or(&"".to_string()), params, body)
},
OptFormInner::ContComb(_) => write!(f, "<cont>"),
}
}
}
impl From<&Form> for Rc<OptForm> {
fn from(x: &Form) -> Self {
match x {
Form::Nil => OptForm::new(OptFormInner::Nil, None),
Form::Int(i) => OptForm::new(OptFormInner::Int(*i), None),
Form::Bool(b) => OptForm::new(OptFormInner::Bool(*b), None),
Form::Symbol(s) => OptForm::new(OptFormInner::Symbol(s.to_owned()), None),
Form::Cell(cell) => panic!("bad"),
Form::Pair(car,cdr) => OptForm::new(OptFormInner::Pair((&**car).into(), (&**cdr).into()), None),
Form::PrimComb { eval_limit, ins } => OptForm::new(OptFormInner::PrimComb { eval_limit: *eval_limit, ins: *ins }, None),
Form::DeriComb { .. } => panic!("bad"),
Form::ContComb(c) => panic!("bad"),
}
}
}
impl OptForm {
fn tc(&self) -> Option<Rc<Trace>> {
self.trace.as_ref().map(Rc::clone)
}
fn tor(&self, o: &Rc<OptForm>) -> Option<Rc<Trace>> {
match &self.trace {
Some(t) => Some(Rc::clone(t)),
None => o.trace.as_ref().map(Rc::clone)
}
}
fn new(inner: OptFormInner, trace: Option<Rc<Trace>>) -> Rc<Self> { Rc::new(OptForm { inner, trace }) }
fn truthy(&self) -> bool {
match &self.inner {
OptFormInner::Bool(b) => *b,
OptFormInner::Nil => false,
_ => true,
}
}
fn int(&self) -> Option<i32> {
match &self.inner {
OptFormInner::Int(i) => Some(*i),
_ => None,
}
}
fn append(&self, x: Rc<OptForm>) -> Option<Rc<OptForm>> {
let trace = self.tor(&x);
match &self.inner {
OptFormInner::Pair(car, cdr) => cdr.append(x).map(|x| OptForm::new(OptFormInner::Pair(Rc::clone(car), x), trace)),
OptFormInner::Nil => Some(OptForm::new(OptFormInner::Pair(x, OptForm::new(OptFormInner::Nil, trace.as_ref().map(Rc::clone))), trace)),
_ => None,
}
}
pub fn congruent(&self, other: &Form) -> bool {
match other {
Form::Nil => self.inner == OptFormInner::Nil,
Form::Int(i) => self.inner == OptFormInner::Int(*i),
Form::Bool(b) => self.inner == OptFormInner::Bool(*b),
Form::Symbol(s) => self.inner == OptFormInner::Symbol(s.to_owned()),
Form::Cell(cell) => panic!("bad"),
Form::Pair(car,cdr) => match &self.inner { OptFormInner::Pair(carp, cdrp) => carp.congruent(car) && cdrp.congruent(cdr), _ => false },
Form::PrimComb { eval_limit, ins } => self.inner == OptFormInner::PrimComb { eval_limit: *eval_limit, ins: *ins },
Form::DeriComb { .. } => panic!("bad"),
Form::ContComb(c) => panic!("bad"),
}
}
}
impl FormT for OptForm {
fn sym(&self) -> Option<&str> {
match &self.inner {
OptFormInner::Symbol(s) => Some(s),
_ => None,
}
}
fn pair(&self) -> Option<(Rc<OptForm>,Rc<OptForm>)> {
match &self.inner {
OptFormInner::Pair(car, cdr) => Some((Rc::clone(car),Rc::clone(cdr))),
_ => None,
}
}
fn car(&self) -> Option<Rc<OptForm>> {
match &self.inner {
OptFormInner::Pair(car, _cdr) => Some(Rc::clone(car)),
_ => None,
}
}
fn cdr(&self) -> Option<Rc<OptForm>> {
match &self.inner {
OptFormInner::Pair(_car, cdr) => Some(Rc::clone(cdr)),
_ => None,
}
}
fn is_nil(&self) -> bool {
match &self.inner {
OptFormInner::Nil => true,
_ => false,
}
}
fn call(&self, p: Rc<Self>, e: Rc<Self>, nc: Box<Cont<Self>>, metac: Cont<Self>) -> Cursor<Self> {
match &self.inner {
OptFormInner::PrimComb{eval_limit, ins} => {
Cursor { f: OptForm::new(OptFormInner::Nil, None), c: Cont::PramEval { eval_limit: *eval_limit, to_eval: p, collected: None, e, ins: *ins, nc: nc }, metac }
}
OptFormInner::DeriComb {se, de, params, body, code} => {
// TODO: Add traces here?
let mut new_e = Rc::clone(se);
if let Some(de) = de {
new_e = assoc(&de, Rc::clone(&e), new_e);
}
new_e = assoc(&params, p, new_e);
Cursor { f: Rc::clone(body), c: Cont::Eval { e: new_e, nc: nc }, metac }
}
OptFormInner::ContComb(c) => {
// TODO: Add traces here?
Cursor { f: p.car().unwrap(), c: Cont::Eval { e, nc: Box::new(c.clone()) }, metac: Cont::CatchRet { nc: nc, restore_meta: Box::new(metac) } }
}
_ => {
panic!("Tried to call not a Prim/DeriComb/ContComb {:?}, nc was {:?}", self, nc);
}
}
}
fn impl_prim(ins: PrimCombI, e: Rc<Self>, ps: Vec<Rc<Self>>, c: Cont<Self>, metac: Cont<Self>) -> Cursor<Self> {
match ins {
PrimCombI::Eval => Cursor { f: Rc::clone(&ps[0]), c: Cont::Eval { e: Rc::clone(&ps[1]), nc: Box::new(c) }, metac },
PrimCombI::Vau => {
// Add traces here? If no on-going?
let de = ps[0].sym().map(|s| s.to_owned());
let params = ps[1].sym().unwrap().to_owned();
let body = Rc::clone(&ps[2]);
Cursor { f: OptForm::new(OptFormInner::DeriComb { se: e, de, params, body, code: Some(Rc::new(RefCell::new(vec![]))) }, None), c, metac }
},
PrimCombI::If => if ps[0].truthy() {
Cursor { f: Rc::clone(&ps[1]), c: Cont::Eval { e: e, nc: Box::new(c) }, metac }
} else {
Cursor { f: Rc::clone(&ps[2]), c: Cont::Eval { e: e, nc: Box::new(c) }, metac }
},
PrimCombI::Reset => Cursor { f: Rc::clone(&ps[0]),
c: Cont::Eval { e: e, nc: Box::new(Cont::MetaRet) },
metac: Cont::CatchRet { nc: Box::new(c), restore_meta: Box::new(metac) } },
PrimCombI::Shift => Cursor { f: Rc::clone(&ps[0]),
// Trace here
c: Cont::Call { p: OptForm::new(OptFormInner::Pair(OptForm::new(OptFormInner::ContComb(c), None),
OptForm::new(OptFormInner::Nil, None)), None),
e: e,
nc: Box::new(Cont::MetaRet) },
metac: Cont::CatchRet { nc: Box::new(metac.clone()), restore_meta: Box::new(metac) } },
PrimCombI::Assert => {
let thing = Rc::clone(&ps[0]);
if !thing.truthy() {
println!("Assert failed: {:?}", thing);
}
assert!(thing.truthy());
Cursor { f: Rc::clone(&ps[1]), c: Cont::Eval { e: e, nc: Box::new(c) }, metac }
},
PrimCombI::Cell => Cursor { f: OptForm::new(OptFormInner::Cell(RefCell::new(Rc::clone(&ps[0]))), ps[0].tc()), c, metac },
PrimCombI::Set => match &ps[0].inner {
OptFormInner::Cell(cell) => Cursor { f: cell.replace(Rc::clone(&ps[1])), c, metac },
_ => panic!("set on not cell"),
},
PrimCombI::Get => match &ps[0].inner {
OptFormInner::Cell(cell) => Cursor { f: Rc::clone(&cell.borrow()), c, metac },
_ => panic!("get on not cell"),
},
PrimCombI::Cons => Cursor { f: OptForm::new(OptFormInner::Pair(Rc::clone(&ps[0]), Rc::clone(&ps[1])), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Car => Cursor { f: ps[0].car().unwrap(), c, metac },
PrimCombI::Cdr => Cursor { f: ps[0].cdr().unwrap(), c, metac },
PrimCombI::Quote => Cursor { f: Rc::clone(&ps[0]), c, metac },
PrimCombI::Eq => Cursor { f: OptForm::new(OptFormInner::Bool(ps[0] == ps[1]), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Lt => Cursor { f: OptForm::new(OptFormInner::Bool(ps[0].int().unwrap() < ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::LEq => Cursor { f: OptForm::new(OptFormInner::Bool(ps[0].int().unwrap() <= ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Gt => Cursor { f: OptForm::new(OptFormInner::Bool(ps[0].int().unwrap() > ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::GEq => Cursor { f: OptForm::new(OptFormInner::Bool(ps[0].int().unwrap() >= ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Plus => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() + ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Minus => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() - ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Mult => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() * ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Div => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() / ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Mod => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() % ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::And => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() & ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Or => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() | ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::Xor => Cursor { f: OptForm::new(OptFormInner::Int(ps[0].int().unwrap() ^ ps[1].int().unwrap()), ps[0].tor(&ps[1])), c, metac },
PrimCombI::CombP => Cursor { f: OptForm::new(OptFormInner::Bool(match &ps[0].inner {
OptFormInner::PrimComb { .. } => true,
OptFormInner::DeriComb { .. } => true,
_ => false,
}), ps[0].tc()), c, metac },
PrimCombI::CellP => Cursor { f: OptForm::new(OptFormInner::Bool(match &ps[0].inner {
OptFormInner::Cell(_c) => true,
_ => false,
}), ps[0].tc()), c, metac },
PrimCombI::PairP => Cursor { f: OptForm::new(OptFormInner::Bool(match &ps[0].inner {
OptFormInner::Pair(_a,_b) => true,
_ => false,
}), ps[0].tc()), c, metac },
PrimCombI::SymbolP => Cursor { f: OptForm::new(OptFormInner::Bool(match &ps[0].inner {
OptFormInner::Symbol(_) => true,
_ => false,
}), ps[0].tc()), c, metac },
PrimCombI::IntP => Cursor { f: OptForm::new(OptFormInner::Bool(match &ps[0].inner {
OptFormInner::Int(_) => true,
_ => false,
}), ps[0].tc()), c, metac },
PrimCombI::BoolP => Cursor { f: OptForm::new(OptFormInner::Bool(match &ps[0].inner {
OptFormInner::Bool(_) => true,
_ => false,
}), ps[0].tc()), c, metac },
PrimCombI::NilP => Cursor { f: OptForm::new(OptFormInner::Bool(ps[0].is_nil()), ps[0].tc()), c, metac },
}
}
}
fn assoc(k: &str, v: Rc<OptForm>, l: Rc<OptForm>) -> Rc<OptForm> {
let at = v.tc();
let bt = v.tc();
let tort = v.tor(&l);
OptForm::new(OptFormInner::Pair(
OptForm::new(OptFormInner::Pair(
OptForm::new(OptFormInner::Symbol(k.to_owned()), at),
v), bt),
l), tort)
}

View File

@@ -1,32 +0,0 @@
use std::str::FromStr;
use std::rc::Rc;
use std::cell::RefCell;
use sl::Form;
grammar;
pub Term: Rc<Form> = {
NUM => Rc::new(Form::Int(i32::from_str(<>).unwrap())),
SYM => Rc::new(Form::Symbol(<>.to_owned(),RefCell::new(None))),
"(" <ListInside?> ")" => <>.unwrap_or(Rc::new(Form::Nil)),
"'" <Term> => Rc::new(Form::Pair(Rc::new(Form::Symbol("quote".to_owned(),RefCell::new(None))), Rc::new(Form::Pair(<>, Rc::new(Form::Nil),RefCell::new(None))),RefCell::new(None))),
"!" <h: Term> <t: Term> => {
h.append(t).unwrap()
},
};
ListInside: Rc<Form> = {
<Term> => Rc::new(Form::Pair(<>, Rc::new(Form::Nil),RefCell::new(None))),
<h: Term> <t: ListInside> => Rc::new(Form::Pair(h, t,RefCell::new(None))),
<a: Term> "." <d: Term> => Rc::new(Form::Pair(a, d,RefCell::new(None))),
}
match {
"(",
")",
".",
"'",
"!",
r"[0-9]+" => NUM,
r"[a-zA-Z+*/_=?%&|^<>-][\w+*/=_?%&|^<>-]*" => SYM,
r"(;[^\n]*\n)|\s+" => { }
}

View File

@@ -1,614 +0,0 @@
use std::rc::Rc;
use std::collections::BTreeMap;
use std::fmt;
use std::cell::RefCell;
use anyhow::{anyhow,bail,Result};
// This first Simple Lisp really is
//
// No fexprs, no mutation, no continuations, no macros, no strings.
// Int/Bool/Nil/Pair/Symbol/Closure/Prim.
//
// Figuring out GC between a JIT and Rust will be tricky.
// Can start with a like tracing-JIT-into-bytecode
// Replcing Env with pairs or somesuch would make JIT interop easier I think, because we wouldn't
// have to deal with refcell, but then we would again for mutation.
// Maybe doing all allocation on the Rust side with #[no_mangle] functions would make things easier
// mmmm no let's make our own Box, Rc, maybe Arc
// rustonomicon
// What if we're cute and use the ID
// like we will eventually use value tagging
// like, use the same encoding
// interned symbols and all
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
pub struct ID {
id: i64
}
impl fmt::Display for ID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.id)
}
}
#[derive(Debug)]
pub enum Form {
Nil,
Int(i32),
Bool(bool),
Symbol(String, RefCell<Option<ID>>),
Pair(Rc<Form>, Rc<Form>, RefCell<Option<ID>>),
Closure(Vec<String>, Rc<RefCell<Env>>, Rc<Form>, ID),
Prim(Prim),
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum Prim {
Add,
Sub,
Mul,
Div,
Mod,
Eq,
Cons,
Car,
Cdr,
}
impl Form {
fn my_eq(&self, o: &Rc<Form>) -> bool {
match self {
Form::Nil => o.is_nil(),
Form::Int(i) => if let Ok(oi) = o.int() { *i == oi } else { false },
Form::Bool(b) => if let Ok(ob) = o.bool() { *b == ob } else { false },
Form::Symbol(s, _id) => if let Ok(os) = o.sym() { s == os } else { false },
Form::Pair(a,b,_id) => if let Ok((oa,ob)) = o.pair() { a.my_eq(&oa) && b.my_eq(&ob) } else { false },
Form::Closure(_, _, _, _) => false,
Form::Prim(p) => match &**o { Form::Prim(op) => p == op, _ => false },
}
}
fn new_pair(car: Rc<Form>, cdr: Rc<Form>) -> Rc<Form> {
Rc::new(Form::Pair(car, cdr, RefCell::new(None)))
}
fn new_nil() -> Rc<Form> {
Rc::new(Form::Nil)
}
fn new_int(i: i32) -> Rc<Form> {
Rc::new(Form::Int(i))
}
fn new_bool(b: bool) -> Rc<Form> {
Rc::new(Form::Bool(b))
}
fn new_closure(params: Vec<String>, env: Rc<RefCell<Env>>, body: Rc<Form>, ctx: &mut Ctx) -> Rc<Form> {
Rc::new(Form::Closure(params, env, body, ctx.alloc_id()))
}
fn truthy(&self) -> bool {
match self {
Form::Bool(b) => *b,
Form::Nil => false,
_ => true,
}
}
fn bool(&self) -> Result<bool> {
match self {
Form::Bool(b) => Ok(*b),
_ => Err(anyhow!("bool on not a bool")),
}
}
fn int(&self) -> Result<i32> {
match self {
Form::Int(i) => Ok(*i),
_ => Err(anyhow!("int on not a int")),
}
}
fn prim(&self) -> Result<Prim> {
match self {
Form::Prim(p) => Ok(*p),
_ => Err(anyhow!("prim on not a prim")),
}
}
fn sym(&self) -> Result<&str> {
match self {
Form::Symbol(s, _id) => Ok(s),
_ => Err(anyhow!("sym on not a sym")),
}
}
fn pair(&self) -> Result<(Rc<Form>,Rc<Form>)> {
match self {
Form::Pair(car, cdr, _id) => Ok((Rc::clone(car),Rc::clone(cdr))),
_ => Err(anyhow!("pair on not a pair")),
}
}
fn car(&self) -> Result<Rc<Form>> {
match self {
Form::Pair(car, _cdr, _id) => Ok(Rc::clone(car)),
_ => Err(anyhow!("car on not a pair")),
}
}
fn cdr(&self) -> Result<Rc<Form>> {
match self {
Form::Pair(_car, cdr, _id) => Ok(Rc::clone(cdr)),
_ => Err(anyhow!("cdr on not a pair")),
}
}
fn is_nil(&self) -> bool {
match self {
Form::Nil => true,
_ => false,
}
}
pub fn append(&self, x: Rc<Form>) -> Result<Rc<Form>> {
match self {
Form::Pair(car, cdr, _id) => cdr.append(x).map(|x| Rc::new(Form::Pair(Rc::clone(car), x, RefCell::new(None)))),
Form::Nil => Ok(Rc::new(Form::Pair(x, Rc::new(Form::Nil), RefCell::new(None)))),
_ => Err(anyhow!("append to not a pair")),
}
}
}
#[derive(Debug)]
pub struct Env {
u: Option<Rc<RefCell<Env>>>,
// split this into
// BTreeMap<String, usize>
// Vec<usize> so that traced code can refer by index
m: BTreeMap<String, Rc<Form>>
}
impl Env {
pub fn root_env() -> Rc<RefCell<Env>> {
Rc::new(RefCell::new(Env {
u: None,
m: [
("+", Rc::new(Form::Prim(Prim::Add))),
("-", Rc::new(Form::Prim(Prim::Sub))),
("*", Rc::new(Form::Prim(Prim::Mul))),
("/", Rc::new(Form::Prim(Prim::Div))),
("%", Rc::new(Form::Prim(Prim::Mod))),
("cons", Rc::new(Form::Prim(Prim::Cons))),
("cdr", Rc::new(Form::Prim(Prim::Cdr))),
("car", Rc::new(Form::Prim(Prim::Car))),
("=", Rc::new(Form::Prim(Prim::Eq))),
("nil", Form::new_nil()),
].into_iter().map(|(s,p)| (s.to_owned(), p)).collect()
}))
}
pub fn chain(o: &Rc<RefCell<Env>>) -> Rc<RefCell<Env>> {
Rc::new(RefCell::new(Env {
u: Some(Rc::clone(o)),
m: BTreeMap::new(),
}))
}
pub fn lookup(&self, s: &str) -> Result<Rc<Form>> {
if let Some(r) = self.m.get(s) {
Ok(Rc::clone(r))
} else if let Some(u) = &self.u {
u.borrow().lookup(s)
} else {
bail!("lookup of {s} failed")
}
}
pub fn define(&mut self, s: String, v: Rc<Form>) {
// no mutation, shadowing in inner scope ok
assert!(!self.m.contains_key(&s));
self.m.insert(s, v);
}
}
#[derive(Debug)]
enum Op {
Guard { const_value: Rc<Form>, side: (Option<Rc<Form>>, Rc<Cont>) },
Debug,
Define { sym: String },
}
impl fmt::Display for Op {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Op::Guard { const_value, side } => write!(f, "Guard"),
Op::Debug => write!(f, "Debug"),
Op::Define { sym } => write!(f, "Define {sym}"),
}
}
}
#[derive(Debug)]
struct Trace {
id: ID,
// needs to track which are constants
ops: Vec<Op>,
}
impl Trace {
fn new(id: ID) -> Self {
Trace { id, ops: vec![] }
}
}
impl fmt::Display for Trace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Trace for {} [", self.id)?;
for op in &self.ops {
write!(f, " {}", op)?;
}
write!(f, " ]")?;
Ok(())
}
}
#[derive(Debug)]
struct Ctx {
id_counter: i64,
func_calls: BTreeMap<ID, i64>,
tracing: Option<Trace>,
traces: BTreeMap<ID, Trace>,
}
impl fmt::Display for Ctx {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Ctx")
}
}
impl Ctx {
fn new() -> Ctx {
Ctx {
id_counter: 0,
func_calls: BTreeMap::new(),
tracing: None,
traces: BTreeMap::new(),
}
}
fn alloc_id(&mut self) -> ID {
self.id_counter += 1;
ID { id: self.id_counter }
}
fn trace_running(&self) -> bool { self.tracing.is_some() }
fn trace_call_start(&mut self, id: ID) {
// Needs to take and use parameters for mid-trace
// needs to guard on function called if non-constant
let entry = self.func_calls.entry(id).or_insert(0);
println!("tracing call start for {id}, has been called {} times so far", *entry);
*entry += 1;
if let Some(trace) = &self.tracing {
if trace.id == id {
println!("Ending trace at recursive call!");
println!("\t{}", trace);
self.traces.insert(id, self.tracing.take().unwrap());
}
} else if *entry > 1 && self.traces.get(&id).is_none() {
self.tracing = Some(Trace::new(id));
}
}
fn trace_call_end(&mut self, id: ID) {
// associate with it or something
println!("tracing call end for {id}");
if let Some(trace) = &self.tracing {
if trace.id == id {
println!("Ending trace at end of call!");
println!("\t{}", trace);
self.traces.insert(id, self.tracing.take().unwrap());
}
}
}
fn trace_guard<T: Into<Form> + std::fmt::Debug >(&mut self, value: T, other: impl Fn()->(Option<Rc<Form>>,Rc<Cont>)) {
println!("Tracing guard {value:?}");
if let Some(trace) = &mut self.tracing {
trace.ops.push(Op::Guard { const_value: Rc::new(value.into()), side: other() });
}
}
fn trace_debug(&mut self) {
if let Some(trace) = &mut self.tracing {
trace.ops.push(Op::Debug);
}
}
fn trace_define(&mut self, sym: &str) {
if let Some(trace) = &mut self.tracing {
trace.ops.push(Op::Define { sym: sym.to_owned() });
}
}
fn trace_call_bit(&mut self) {
if let Some(trace) = &mut self.tracing {
// TODO
}
}
// Trace call start, of course, handles the other side!
// Though I guess that means call start should recieve the parameters
// also, for like variables, it should guard on what function
// if dynamic, interacts with the constant tracking
fn trace_prim(&mut self, p: &Prim) {
if let Some(trace) = &mut self.tracing {
// TODO
}
}
fn trace_lookup(&mut self, s: &str) {
if let Some(trace) = &mut self.tracing {
// TODO
}
}
fn trace_constant(&mut self, c: &Rc<Form>) {
if let Some(trace) = &mut self.tracing {
// TODO
}
}
fn trace_lambda(&mut self, params: &[String], e: &Rc<RefCell<Env>>, body: &Rc<Form>) {
if let Some(trace) = &mut self.tracing {
// TODO
}
}
}
#[derive(Clone,Debug)]
enum Cont {
MetaRet,
Ret { e: Rc<RefCell<Env>>, id: ID, c: Rc<Cont> },
Eval { c: Rc<Cont> },
Prim { s: &'static str, to_go: Rc<Form>, c: Rc<Cont> },
Call { evaled: Vec<Rc<Form>>, to_go: Rc<Form>, c: Rc<Cont> },
}
pub fn eval(f: Rc<Form>) -> Result<Rc<Form>> {
let mut ctx = Ctx::new();
let mut f = f;
let mut e = Env::root_env();
let mut c = Cont::Eval { c: Rc::new(Cont::MetaRet) };
loop {
match c {
Cont::MetaRet => {
println!("Ctx was {ctx}");
assert!(!ctx.trace_running());
return Ok(f);
}
Cont::Ret { e: ne, id, c: nc } => {
ctx.trace_call_end(id);
e = ne;
c = (*nc).clone();
},
Cont::Prim { s, to_go, c: nc } => {
match s {
"if" => {
let thn = to_go.car()?;
let els = to_go.cdr()?.car()?;
if f.truthy() {
ctx.trace_guard(true, || (Some(Rc::clone(&els)), Rc::new(Cont::Eval { c: Rc::clone(&nc) })));
f = thn;
} else {
ctx.trace_guard(false, ||(Some(Rc::clone(&thn)), Rc::new(Cont::Eval { c: Rc::clone(&nc) })));
f = els;
}
c = Cont::Eval { c: nc };
},
"or" => {
let other = to_go.car()?;
if !f.truthy() {
ctx.trace_guard(false, || (None, nc.clone()));
f = other;
c = Cont::Eval { c: nc };
} else {
ctx.trace_guard(true, || (Some(Rc::clone(&other)), Rc::new(Cont::Eval { c: Rc::clone(&nc) })));
c = (*nc).clone();
}
},
"and" => {
let other = to_go.car()?;
if f.truthy() {
ctx.trace_guard(true, || (None, nc.clone()));
f = other;
c = Cont::Eval { c: nc };
} else {
ctx.trace_guard(false, || (Some(Rc::clone(&other)), Rc::new(Cont::Eval { c: Rc::clone(&nc) })));
c = (*nc).clone();
}
},
"begin" => {
if to_go.is_nil() {
c = (*nc).clone();
} else {
f = to_go.car()?;
c = Cont::Eval { c: Rc::new(Cont::Prim { s: "begin", to_go: to_go.cdr()?, c: nc }) };
}
},
"debug" => {
println!("Debug: {f}");
ctx.trace_debug();
c = (*nc).clone();
},
"define" => {
let sym = to_go.sym()?.to_string();
ctx.trace_define(&sym);
e.borrow_mut().define(sym, Rc::clone(&f));
c = (*nc).clone();
},
_ => {
panic!("bad prim {s}");
}
}
},
Cont::Call { mut evaled, to_go, c: nc } => {
ctx.trace_call_bit();
evaled.push(f);
if to_go.is_nil() {
// do call
let arg_len = evaled.len() - 1;
let mut evaled_iter = evaled.into_iter();
let comb = evaled_iter.next().unwrap();
match &*comb {
Form::Closure(ps, ie, b, id) => {
if ps.len() != arg_len {
bail!("arguments length doesn't match");
}
let new_env = Env::chain(&ie);
for (name, value) in ps.iter().zip(evaled_iter) {
new_env.borrow_mut().define(name.to_string(), value);
}
ctx.trace_call_start(*id);
c = Cont::Eval { c: Rc::new(Cont::Ret { e: Rc::clone(&e), id: *id, c: nc }) };
f = Rc::clone(&b);
e = new_env;
},
Form::Prim(p) => {
ctx.trace_prim(p);
let a = evaled_iter.next().unwrap();
f = match comb.prim().unwrap() {
Prim::Car => a.car()?,
Prim::Cdr => a.cdr()?,
_ => {
let b = evaled_iter.next().unwrap();
match comb.prim().unwrap() {
Prim::Add => Form::new_int(a.int()? + b.int()?),
Prim::Sub => Form::new_int(a.int()? - b.int()?),
Prim::Mul => Form::new_int(a.int()? * b.int()?),
Prim::Div => Form::new_int(a.int()? / b.int()?),
Prim::Mod => Form::new_int(a.int()? % b.int()?),
Prim::Cons => Form::new_pair(a, b),
Prim::Eq => Form::new_bool(a.my_eq(&b)),
_ => unreachable!(),
}
}
};
c = (*nc).clone();
},
_ => {
bail!("tried to call a non-comb {}", comb)
},
}
} else {
f = to_go.car()?;
c = Cont::Eval { c: Rc::new(Cont::Call { evaled, to_go: to_go.cdr()?, c: nc }) };
}
}
Cont::Eval { c: nc } => {
let tmp = f;
match &*tmp {
Form::Symbol(s, _id) => {
ctx.trace_lookup(s);
f = e.borrow().lookup(s)?;
c = (*nc).clone();
},
Form::Pair(car, cdr, _id) => {
match &**car {
Form::Symbol(s, _id) if s == "if" => {
f = cdr.car()?;
c = Cont::Eval { c: Rc::new(Cont::Prim { s: "if", to_go: cdr.cdr()?, c: nc }) };
}
// and/or has to short-circut, so special form
// just like Scheme (bad ;) )
Form::Symbol(s, _id) if s == "or" => {
f = cdr.car()?;
c = Cont::Eval { c: Rc::new(Cont::Prim { s: "or", to_go: cdr.cdr()?, c: nc }) };
}
Form::Symbol(s, _id) if s == "and" => {
f = cdr.car()?;
c = Cont::Eval { c: Rc::new(Cont::Prim { s: "and", to_go: cdr.cdr()?, c: nc }) };
}
Form::Symbol(s, _id) if s == "begin" => {
f = cdr.car()?;
c = Cont::Eval { c: Rc::new(Cont::Prim { s: "begin", to_go: cdr.cdr()?, c: nc }) };
}
Form::Symbol(s, _id) if s == "debug" => {
f = cdr.car()?;
c = Cont::Eval { c: Rc::new(Cont::Prim { s: "debug", to_go: cdr.cdr()?, c: nc }) };
}
// This is a fast and loose ~simple lisp~, so just go for it
// and can have convention that this is always top levelish
Form::Symbol(s, _id) if s == "define" => {
// note the swap, evaluating the second not the first (define a value..)
f = cdr.cdr()?.car()?;
c = Cont::Eval { c: Rc::new(Cont::Prim { s: "define", to_go: cdr.car()?, c: nc }) };
}
Form::Symbol(s, _id) if s == "quote" => {
f = cdr.car()?;
ctx.trace_constant(&f);
c = (*nc).clone();
}
// (lambda (a b) body)
Form::Symbol(s, _id) if s == "lambda" => {
let mut params_vec = vec![];
let mut params = cdr.car()?;
while let Ok((ncar, ncdr)) = params.pair() {
params_vec.push(ncar.sym()?.to_string());
params = ncdr;
}
let body = cdr.cdr()?.car()?;
// Later on, the id of the closure should maybe be augmented
// or replaced with the id of the code it was made out of?
ctx.trace_lambda(&params_vec, &e, &body);
f = Form::new_closure(params_vec, Rc::clone(&e), body, &mut ctx);
c = (*nc).clone();
}
_ => {
f = Rc::clone(car);
c = Cont::Eval { c: Rc::new(Cont::Call { evaled: vec![], to_go: Rc::clone(cdr), c: nc }) };
}
}
},
_ => {
// value, no eval
f = tmp;
ctx.trace_constant(&f);
c = (*nc).clone();
}
}
}
}
}
}
// optimized as a function based off side table of id keyed -> opt
// that id might be nice for debugging too
// Symbol ID's could actually be used for environment lookups
// this is just interning
// todo, strings not symbols?
impl From<String> for Form { fn from(item: String) -> Self { Form::Symbol(item, RefCell::new(None)) } }
impl From<&str> for Form { fn from(item: &str) -> Self { Form::Symbol(item.to_owned(), RefCell::new(None)) } }
impl From<i32> for Form { fn from(item: i32) -> Self { Form::Int(item) } }
impl From<bool> for Form { fn from(item: bool) -> Self { Form::Bool(item) } }
impl<A: Into<Form>, B: Into<Form>> From<(A, B)> for Form {
fn from(item: (A, B)) -> Self {
Form::Pair(Rc::new(item.0.into()), Rc::new(item.1.into()), RefCell::new(None))
}
}
impl fmt::Display for Form {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Form::Nil => write!(f, "nil"),
Form::Int(i) => write!(f, "{i}"),
Form::Bool(b) => write!(f, "{b}"),
Form::Symbol(s, _id) => write!(f, "'{s}"),
Form::Pair(car, cdr, _id) => {
write!(f, "({}", car)?;
let mut traverse: Rc<Form> = Rc::clone(cdr);
loop {
match &*traverse {
Form::Pair(ref carp, ref cdrp, ref _id) => {
write!(f, " {}", carp)?;
traverse = Rc::clone(cdrp);
},
Form::Nil => {
write!(f, ")")?;
return Ok(());
},
x => {
write!(f, ". {x})")?;
return Ok(());
},
}
}
},
Form::Closure(params, inner_env, code, id) => {
write!(f, "<closure{} {:?}>", id, params)
}
Form::Prim(p) => {
match p {
Prim::Add => write!(f, "+"),
Prim::Sub => write!(f, "-"),
Prim::Mul => write!(f, "*"),
Prim::Div => write!(f, "/"),
Prim::Mod => write!(f, "%"),
Prim::Cons => write!(f, "cons"),
Prim::Car => write!(f, "car"),
Prim::Cdr => write!(f, "cdr"),
Prim::Eq => write!(f, "="),
}
}
}
}
}

View File

@@ -1,65 +0,0 @@
#[macro_use] extern crate lalrpop_util;
lalrpop_mod!(pub grammar);
use std::rc::Rc;
use anyhow::Result;
use sl::eval;
fn main() -> Result<()> {
let input = "
(begin
(debug 1)
;(debug (= 1 2))
;(debug (+ 2 3))
;(define a (+ 1 (* 3 4)))
;(define fact (lambda (n) (if (= n 1) 1 (* n (fact (- n 1))))))
;(debug 'gonna_fact_it)
;(debug fact)
;(debug (fact 400))
;(define fact2 (lambda (n a) (if (= n 1) a (fact2 (- n 1) (* n a)))))
;(debug 'gonna_fact2_it)
;(debug fact2)
;(debug (fact2 400 1))
(define faft (lambda (n) (if (= n 1) (debug 1) (+ n (faft (- n 1))))))
(debug 'gonna_faft_it)
(debug faft)
(debug (faft 6))
;(debug (faft 400))
;(define faft2 (lambda (n a) (if (= n 1) a (faft2 (- n 1) (+ n a)))))
;(debug 'gonna_faft2_it)
;(debug faft2)
;(debug (faft2 400 1))
;(define fib (lambda (n) (if (or (= n 0) (= n 1)) 1 (+ (fib (- n 1)) (fib (- n 2))))))
;(debug 'gonna_fib_it)
;(debug fib)
;(debug (fib 10))
;(debug a)
;(define b (cons 1 (cons 2 (cons 3 nil))))
;(debug b)
;(debug (car b))
;(debug (cdr b))
(if (= 1 2) (+ 2 3) (* 2 2))
)
";
let parsed_input = Rc::new(grammar::TermParser::new().parse(input)?);
//println!("Hello, world: {parsed_input:?}");
println!("Hello, world: {parsed_input}");
let evaled = eval(Rc::clone(&parsed_input))?;
println!("evaled: {evaled}");
Ok(())
}

View File

@@ -661,6 +661,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"cranelift",
"cranelift-codegen",
"cranelift-jit",
"cranelift-module",
"cranelift-native",

View File

@@ -13,10 +13,11 @@ lalrpop-util = {version="0.20", features=["lexer"]}
regex = "1"
once_cell = "1"
anyhow = "1"
cranelift = "0.101.4"
cranelift-module = "0.101.4"
cranelift-jit = "0.101.4"
cranelift-native = "0.101.4"
cranelift = "0.101.4"
cranelift-codegen = "0.101.4"
cranelift-module = "0.101.4"
cranelift-jit = "0.101.4"
cranelift-native = "0.101.4"
[build-dependencies]
lalrpop = "0.20"

34
slj/src/grammar.lalrpop Normal file
View File

@@ -0,0 +1,34 @@
use std::str::FromStr;
use sl::Form;
grammar;
pub Term: Form = {
"true" => Form::new_bool(true),
"false" => Form::new_bool(false),
NUM => Form::new_int(isize::from_str(<>).unwrap()),
SYM => Form::new_symbol(<>),
"(" <ListInside?> ")" => <>.unwrap_or(Form::new_nil()),
"'" <Term> => Form::new_pair(Form::new_symbol("quote"), Form::new_pair(<>, Form::new_nil())),
"!" <h: Term> <t: Term> => {
h.append(t).unwrap()
},
};
ListInside: Form = {
<Term> =>Form::new_pair(<>, Form::new_nil()),
<h: Term> <t: ListInside> => Form::new_pair(h, t),
<a: Term> "." <d: Term> => Form::new_pair(a, d),
}
match {
"true",
"false",
"(",
")",
".",
"'",
"!",
r"[0-9]+" => NUM,
r"[a-zA-Z+*/_=?%&|^<>-][\w+*/=_?%&|^<>-]*" => SYM,
r"(;[^\n]*\n)|\s+" => { }
}

View File

2034
slj/src/lib.rs Normal file

File diff suppressed because it is too large Load Diff

149
slj/src/main.rs Normal file
View File

@@ -0,0 +1,149 @@
#[macro_use] extern crate lalrpop_util;
lalrpop_mod!(pub grammar);
use std::mem;
use anyhow::Result;
use sl::{eval,Form,Crc,Cvec,Prim,ID,JIT};
fn main() -> Result<()> {
// our Form shennigins will only work on 64 bit platforms
assert!(std::mem::size_of::<usize>() == 8);
assert!(std::mem::size_of::<ID>() == 8);
assert!(std::mem::size_of::<Option<ID>>() == 8);
//let res = ptr_b();
//println!("sucessful run with result {res}");
//let res = ptr_a(23);
//println!("sucessful 2 run with result {res}");
//let res = ptr_b();
//println!("sucessful 2 run with result {res}");
//let res = ptr_c(Form::new_int(1337));
//println!("sucessful 3 run with result {res}");
//return Ok(());
fn alias(a: Crc<u64>, b: Crc<u64>) {
println!("a: {}, b: {}", *a, *b);
}
let x = Crc::new(1);
alias(Crc::clone(&x), x);
let rc_u64_size = std::mem::size_of::<Crc<u64>>();
assert!(rc_u64_size == 8);
println!("for our Crc, we have size {}", rc_u64_size);
let begn = Form::new_symbol("begin");
println!("this should be begin {begn}");
let i = Form::new_int(23);
let n = Form::new_nil();
let bf = Form::new_bool(false);
let bt = Form::new_bool(true);
let p = Form::new_pair(Form::new_int(50), Form::new_nil());
let pra = Form::new_prim(Prim::Add);
let pre = Form::new_prim(Prim::Eq);
let s = Form::new_symbol("woopwpp");
let mut params = Cvec::new();
params.push("a".to_owned());
params.push("b".to_owned());
println!("{i} {n} {bf} {bt} {p} {pra} {pre} {s}");
let mut my_vec: Cvec<Form> = Cvec::new();
my_vec.push(i);
my_vec.push(n);
my_vec.push(bf);
my_vec.push(bt);
my_vec.push(p);
my_vec.push(pra);
my_vec.push(pre);
my_vec.push(s);
my_vec.push(begn);
println!(" from vec {}", my_vec[3]);
for i in my_vec.iter() {
println!(" from vec {}", i);
}
println!("{my_vec}");
my_vec[3] = Form::new_symbol("replaced");
println!(" from vec {}", my_vec[3]);
for i in my_vec.iter() {
println!(" from vec {}", i);
}
println!("{my_vec}");
let input = "
(begin
(debug 1)
;(debug (= 1 2))
;(debug (+ 2 3))
;(define a (+ 1 (* 3 4)))
;(define fact (lambda (n) (if (= n 1) 1 (* n (fact (- n 1))))))
;(debug 'gonna_fact_it)
;(debug fact)
;(debug (fact 400))
;(define fact2 (lambda (n a) (if (= n 1) a (fact2 (- n 1) (* n a)))))
;(debug 'gonna_fact2_it)
;(debug fact2)
;(debug (fact2 400 1))
(define faft_h (lambda (faft_h n) (if (= n 1) (debug 1) (+ n (faft_h faft_h (- n 1))))))
(define faft (lambda (n) (faft_h faft_h n)))
(debug 'gonna_faft_it)
(debug faft)
(debug (faft 8))
(debug 'gonna_faft_it2)
(debug (faft 10))
;(debug (faft 400))
;(define faft2 (lambda (n a) (if (= n 1) a (faft2 (- n 1) (+ n a)))))
;(debug 'gonna_faft2_it)
;(debug faft2)
;(debug (faft2 6 1))
;(debug (faft2 400 1))
;(define fib (lambda (n) (if (or (= n 0) (= n 1)) 1 (+ (fib (- n 1)) (fib (- n 2))))))
;(debug 'gonna_fib_it)
;(debug fib)
;(debug (fib 10))
;(debug a)
;(define b (cons 1 (cons 2 (cons 3 nil))))
;(debug b)
;(debug (car b))
;(debug (cdr b))
;(if (= 1 2) (+ 2 3) (* 2 2))
(or false false )
)
";
let parsed_input = grammar::TermParser::new().parse(input)?;
//println!("Hello, world: {parsed_input:?}");
println!("Hello, world: {parsed_input}");
println!("Yep that was all?");
let evaled = eval(parsed_input.clone())?;
println!("evaled: {evaled}");
Ok(())
}

View File

@@ -69,8 +69,20 @@ var wordflick = function () {
offset++;
}
}
while (words[i][offset] == ' ') {
offset++;
}
} else {
offset = Math.max(offset-4, 0);
for (var j = 0; j < 4; j++) {
if (offset > 0) {
offset--;
if (words[i][offset] == '>') {
while (words[i][offset] != '<') {
offset--;
}
}
}
}
}
}
document.getElementsByClassName('word')[0].innerHTML = part;