Compare commits

...

27 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
56c6b3f5f7 Messing around with fancy splash page 2023-12-09 01:23:30 -05:00
82c38a32cf Basic tracing structure sketched with stubs in cases - need to add constant tracking and implement stubs. Still need some thought on tracing a closure vs tracing the code that created the closure 2023-12-01 21:36:37 -05:00
23 changed files with 2752 additions and 1534 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,495 +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
}
#[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>, RefCell<Option<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>) -> Rc<Form> {
Rc::new(Form::Closure(params, env, body, RefCell::new(None)))
}
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)]
struct Trace {
id: ID,
}
impl Trace {
fn new(id: ID) -> Self {
Trace { id }
}
}
#[derive(Debug)]
struct Ctx {
id_counter: i64,
func_calls: BTreeMap<ID, i64>,
tracing: Option<Trace>,
}
impl Ctx {
fn new() -> Ctx {
Ctx {
id_counter: 0,
func_calls: BTreeMap::new(),
tracing: None,
}
}
fn alloc_id(&mut self) -> ID {
self.id_counter += 1;
ID { id: self.id_counter }
}
fn trace_call_start(&mut self, id: &RefCell<Option<ID>>) {
// shenanigins for controlling the guard
{
if id.borrow().is_none() {
let new_id = self.alloc_id();
id.replace(Some(new_id));
}
}
let id = id.borrow().unwrap();
let entry = self.func_calls.entry(id).or_insert(0);
*entry += 1;
if *entry > 10 && self.tracing.is_none() {
self.tracing = Some(Trace::new(id));
}
}
fn trace_call_end(&mut self, id: &RefCell<Option<ID>>) {
let id = { *id.borrow() };
// associate with it or something
}
}
enum Cont {
MetaRet,
Ret { e: Rc<RefCell<Env>>, c: Box<Cont> },
Eval { c: Box<Cont> },
Prim { s: &'static str, to_go: Rc<Form>, c: Box<Cont> },
Call { evaled: Vec<Rc<Form>>, to_go: Rc<Form>, c: Box<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: Box::new(Cont::MetaRet) };
loop {
match c {
Cont::MetaRet => {
println!("Ctx were {ctx:?}");
return Ok(f);
}
Cont::Ret { e: ne, c: nc } => {
e = ne;
c = *nc;
},
Cont::Prim { s, to_go, c: nc } => {
match s {
"if" => {
if f.truthy() {
f = to_go.car()?;
} else {
f = to_go.cdr()?.car()?;
}
c = Cont::Eval { c: nc };
},
"or" => {
if !f.truthy() {
f = to_go.car()?;
c = Cont::Eval { c: nc };
} else {
c = *nc;
}
},
"and" => {
if f.truthy() {
f = to_go.car()?;
c = Cont::Eval { c: nc };
} else {
c = *nc;
}
},
"begin" => {
if to_go.is_nil() {
c = *nc;
} else {
f = to_go.car()?;
c = Cont::Eval { c: Box::new(Cont::Prim { s: "begin", to_go: to_go.cdr()?, c: nc }) };
}
},
"debug" => {
println!("Debug: {f}");
c = *nc;
},
"define" => {
e.borrow_mut().define(to_go.sym()?.to_string(), Rc::clone(&f));
c = *nc;
},
_ => {
panic!("bad prim {s}");
}
}
},
Cont::Call { mut evaled, to_go, c: nc } => {
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: Box::new(Cont::Ret { e: Rc::clone(&e), c: nc }) };
f = Rc::clone(&b);
e = new_env;
},
Form::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;
},
_ => {
bail!("tried to call a non-comb {}", comb)
},
}
} else {
f = to_go.car()?;
c = Cont::Eval { c: Box::new(Cont::Call { evaled, to_go: to_go.cdr()?, c: nc }) };
}
}
Cont::Eval { c: nc } => {
let tmp = f;
match &*tmp {
Form::Symbol(s, _id) => {
f = e.borrow().lookup(s)?;
c = *nc;
},
Form::Pair(car, cdr, _id) => {
match &**car {
Form::Symbol(s, _id) if s == "if" => {
f = cdr.car()?;
c = Cont::Eval { c: Box::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: Box::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: Box::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: Box::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: Box::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: Box::new(Cont::Prim { s: "define", to_go: cdr.car()?, c: nc }) };
}
Form::Symbol(s, _id) if s == "quote" => {
f = cdr.car()?;
c = *nc;
}
// (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()?;
f = Form::new_closure(params_vec, Rc::clone(&e), body);
c = *nc;
}
_ => {
f = Rc::clone(car);
c = Cont::Eval { c: Box::new(Cont::Call { evaled: vec![], to_go: Rc::clone(cdr), c: nc }) };
}
}
},
_ => {
// value, no eval
f = tmp;
c = *nc;
}
}
}
}
}
}
// 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 {:?}>", 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,64 +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) 1 (+ n (faft (- n 1))))))
;(debug 'gonna_faft_it)
;(debug faft)
;(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(())
}

167
website/index2.html Normal file
View File

@@ -0,0 +1,167 @@
<!doctype html>
<html lang="en-us">
<meta charset="UTF-8">
<head>
<!--<link id="theme" rel="stylesheet" type="text/css" href="slick.css"/>-->
<link id="theme" rel="stylesheet" type="text/css" href="recursive.css"/>
</head>
<body>
<!--<div class="top_spacer"></div>-->
<!--<div class="run_container">-->
<!--<div class="editor" id="hello_editor">; Of course-->
<!--(println "Hello World")-->
<!--; Just print 3-->
<!--(println "Math works:" (+ 1 2))-->
<!--</div>-->
<!--<textarea class="output" id="hello_output">Output will appear here</textarea>-->
<!--<button class="run_button" onclick="executeKraken(hello_editor_jar.toString(), 'hello_output')">Run</button> <br>-->
<!--</div>-->
<script>
// based on https://codepen.io/alvarotrigo/pen/ZEJgqLN
// Thank you!
var words = [
`; define control flow<pre><code>(vau de (a b)
(let ((temp (eval a de)))
(if temp
temp
(eval b de))))</code></pre>`,
'(println "Hello World")',
'; higher-order lazy fold<br>(fold or #f (list #t #f))',
//'Lorem ipsum dolor sit amet',
//' consectetur adipiscing elit',
//'sed do eiusmod tempor incididunt'
],
part,
i = 0,
offset = 0,
len = words.length,
forwards = true,
skip_count = 0,
skip_delay = 30,
speed = 70;
var wordflick = function () {
setInterval(function () {
if (forwards) {
if (offset >= words[i].length) {
++skip_count;
if (skip_count == skip_delay) {
forwards = false;
skip_count = 0;
}
}
} else {
if (offset == 0) {
forwards = true;
i++;
offset = 0;
if (i >= len) {
i = 0;
}
}
}
part = words[i].substr(0, offset);
if (skip_count == 0) {
if (forwards) {
offset++;
if (words[i][offset] == '<') {
while (words[i][offset] != '>') {
offset++;
}
}
while (words[i][offset] == ' ') {
offset++;
}
} else {
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;
},speed);
};
window.onload = function () {
wordflick();
};
</script>
<header><div class="logo_container">
<div class="word"></div>
<h1 class="logo">Kraken</h1>
</div></header>
<i>FOSS Fexprs: <a title="Kraken on GitHub" href="https://github.com/limvot/kraken">https://github.com/limvot/kraken</a></i>
<!--<button onclick="toggleTheme()" style="float: right;">Swap Theme</button>-->
<br>
<h3>Concept:</h3>
<ul>
<li> Minimal, purely functional Kernel/Scheme as core language, with Kernel/Vau calculus inspiration oblivating the need for non-reader macros (<a title="Kernel/Vau calculus thesis" href="https://web.wpi.edu/Pubs/ETD/Available/etd-090110-124904/unrestricted/jshutt.pdf">Kernel/Vau calculus thesis</a>)
<li> Partial evaluation (or now, maybe tracing JIT compilation) to make fexprs fast (my PhD research! First paper on <a href="https://arxiv.org/abs/2303.12254">arXiv</a>)
<li> Implement Type Systems as Macros (but using Fexprs instead of macros) (<a title="type systems as macros paper 1" href="http://www.ccs.neu.edu/home/stchang/pubs/ckg-popl2017.pdf">paper, up to System Fω</a>) (<a title="type systems as macros paper 2" href="https://www.ccs.neu.edu/home/stchang/pubs/cbtb-popl2020.pdf">second paper, up to dependent types</a>)
<li> Use above "type systems as fexprs" to add types and create a statically-typed language on top (with Algebraic Effects using the underlying delimited continuations, etc)
</ul>
<h3> About:</h3>
<p>This is my 4th run at this Lisp concept, with tracing JIT compilation to make fexprs fast forming the core of my current PhD research. <a href="https://miloignis.room409.xyz/">(tiny personal PhD website here)</a></p>
<h4>Vau/Kernel as simple core:</h4>
By constructing our core language on a very simple Vau/Kernel base, we can keep the base truely tiny, and build up normal Lisp functions and programming language features in the language itself. This should help implement other programming languages concisely, and will hopefully make optimization easier and more broadly applicable.
<br>
<h3>Next Steps</h3>
<ul>
<li> Implement persistent functional data structures
<ul>
<li> ✔ RB-Tree
<li> ☐ Hash Array-Mapped Trie (HAMT) / Relaxed Radix Balance Tree (RRB-Tree)
<li> ☐ Hash Map based on the above
<li> ☐ Hash Set based on the above
</ul>
<li> Sketch out Kraken language on top of core Lisp, includes basic Hindley-Milner type system
<li> Re-self-host using functional approach in above Kraken language
</ul>
<link rel="stylesheet" href="./default.min.css">
<script src="./highlight.min.js"></script>
<script type="module">
import {CodeJar} from './codejar.js'
document.querySelectorAll('.editor').forEach((editor_div) => {
window[editor_div.id + "_jar"] = CodeJar(editor_div, hljs.highlightElement)
});
</script>
<script>
var output_name = ""
var Module = {
noInitialRun: true,
onRuntimeInitialized: () => {
},
print: txt => {
document.getElementById(output_name).value += txt + "\n";
},
printErr: txt => {
document.getElementById(output_name).value += "STDERR:[" + txt + "]\n";
}
};
function executeKraken(code, new_output_name) {
output_name = new_output_name
document.getElementById(new_output_name).value = "running...\n";
Module.callMain(["-C", code]);
}
function toggleTheme() {
let theme = document.getElementById('theme')
if (theme.getAttribute("href") == "recursive.css") {
theme.setAttribute("href", "slick.css");
} else {
theme.setAttribute("href", "recursive.css");
}
}
</script>
<script type="text/javascript" src="k_prime.js"></script>
</body>
</html>

View File

@@ -27,7 +27,8 @@ body {
font: 1.2em/1.62 'Recursive', sans-serif;
}
//body, .remark-slide-content { background-color: #eff3f5; }
body, .remark-slide-content { background-color: #f5f3ef; }
//body, .remark-slide-content { background-color: #f5f3ef; }
body, .remark-slide-content { background-color: #f0f6f0; color: #222323; }
h1, h2, h3, h4 {
line-height:0.4;
--rec-wght: 900;
@@ -38,9 +39,53 @@ h1, h2, h3, h4 {
letter-spacing: -0.015em;
font-size: 4em;
}
h1 {
.top_spacer {
position: static;
height: 20vh;
}
.word {
/*height: 20vh;*/
/*font-size: 7cqw;*/
font-size: 6cqw;
font-family: 'Recursive', monospace;
--rec-mono: 1;
letter-spacing: normal;
tab-size: 4;
position: absolute;
top: 15%;
bottom: auto;
right: auto;
display: block;
}
.logo {
text-decoration: underline;
text-decoration-thickness: 0.4rem;
/*font-size: 13em;*/
/*font-size: 15vw;*/
font-size: 28cqw;
/*line-height:0.4;*/
--rec-wght: 900;
--rec-slnt: 0;
--rec-casl: 0.0;
--rec-crsv: 1;
--rec-mono: 0;
/*letter-spacing: -0.015em;*/
letter-spacing: 0em;
position: absolute;
top: auto;
bottom: 2%;
right: auto;
display: block;
/*overflow: hidden;*/
}
.logo_container {
position: static;
/*height: 100vh;*/
height: 100vh;
container-type: inline-size;
/*max-width: initial;*/
}
h2 { font-size: 3em; }
h3 { font-size: 1.5em; }