From cc3699bbe7f13f87754e73fb9cd50faa029a9879 Mon Sep 17 00:00:00 2001 From: Lawrence Bethlenfalvy Date: Thu, 18 Jul 2024 16:07:36 +0200 Subject: [PATCH] bkp --- Cargo.lock | 419 ++++++++++++++++++++++++++++- notes/comm_arch.md | 10 + orchid-api-traits/src/lib.rs | 4 +- orchid-api/src/tree.rs | 3 +- orchid-base/Cargo.toml | 1 + orchid-base/src/as_api.rs | 10 + orchid-base/src/error.rs | 12 +- orchid-base/src/lib.rs | 4 +- orchid-base/src/number.rs | 150 +++++++++++ orchid-base/src/tokens.rs | 15 ++ orchid-extension/Cargo.toml | 1 - orchid-extension/src/atom.rs | 34 +-- orchid-extension/src/atom_owned.rs | 67 +++-- orchid-extension/src/atom_thin.rs | 50 ++-- orchid-extension/src/conv.rs | 23 +- orchid-extension/src/entrypoint.rs | 6 +- orchid-extension/src/error.rs | 22 +- orchid-extension/src/fun.rs | 6 +- orchid-extension/src/lexer.rs | 12 +- orchid-extension/src/lib.rs | 6 +- orchid-extension/src/system.rs | 35 +-- orchid-extension/src/tree.rs | 56 ++-- orchid-host/src/extension.rs | 31 ++- orchid-host/src/lex.rs | 118 ++++++++ orchid-host/src/lib.rs | 3 + orchid-host/src/results.rs | 36 +++ orchid-host/src/tree.rs | 24 ++ orchid-std/src/std.rs | 23 +- orchid-std/src/string/str_atom.rs | 18 +- orchid-std/src/string/str_leer.rs | 12 +- orchidlang/src/parse/numeric.rs | 122 --------- 31 files changed, 1021 insertions(+), 312 deletions(-) create mode 100644 notes/comm_arch.md create mode 100644 orchid-base/src/as_api.rs create mode 100644 orchid-base/src/number.rs create mode 100644 orchid-base/src/tokens.rs create mode 100644 orchid-host/src/lex.rs create mode 100644 orchid-host/src/results.rs create mode 100644 orchid-host/src/tree.rs diff --git a/Cargo.lock b/Cargo.lock index 638b5ae..c36c2a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.11" @@ -21,12 +32,30 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -36,12 +65,70 @@ dependencies = [ "generic-array", ] +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", + "syn_derive", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.109", +] + +[[package]] +name = "bytes" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "const_panic" version = "0.2.8" @@ -154,12 +241,24 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "generic-array" version = "0.14.7" @@ -181,13 +280,22 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash", + "ahash 0.8.11", "allocator-api2", ] @@ -197,6 +305,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + [[package]] name = "itertools" version = "0.13.0" @@ -206,6 +324,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "konst" version = "0.3.9" @@ -245,6 +369,12 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "never" version = "0.1.0" @@ -302,7 +432,7 @@ version = "0.1.0" dependencies = [ "derive_destructure", "dyn-clone", - "hashbrown", + "hashbrown 0.14.5", "itertools", "lazy_static", "never", @@ -311,6 +441,7 @@ dependencies = [ "orchid-api-traits", "ordered-float", "rust-embed", + "rust_decimal", "substack", "trait-set", ] @@ -319,10 +450,10 @@ dependencies = [ name = "orchid-extension" version = "0.1.0" dependencies = [ - "ahash", + "ahash 0.8.11", "derive_destructure", "dyn-clone", - "hashbrown", + "hashbrown 0.14.5", "itertools", "konst", "never", @@ -335,7 +466,6 @@ dependencies = [ "paste", "substack", "trait-set", - "typeid", ] [[package]] @@ -343,7 +473,7 @@ name = "orchid-host" version = "0.1.0" dependencies = [ "derive_destructure", - "hashbrown", + "hashbrown 0.14.5", "itertools", "lazy_static", "orchid-api", @@ -384,6 +514,44 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.78", + "quote 1.0.35", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.78", + "quote 1.0.35", + "version_check", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -402,6 +570,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.109", +] + [[package]] name = "quote" version = "0.6.13" @@ -420,6 +608,80 @@ dependencies = [ "proc-macro2 1.0.78", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +dependencies = [ + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 1.0.109", +] + [[package]] name = "rust-embed" version = "8.3.0" @@ -454,6 +716,22 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rust_decimal" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -463,6 +741,12 @@ dependencies = [ "semver", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "same-file" version = "1.0.6" @@ -472,12 +756,49 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "semver" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.10.8" @@ -489,6 +810,12 @@ dependencies = [ "digest", ] +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + [[package]] name = "stdio-perftest" version = "0.1.0" @@ -538,6 +865,56 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "trait-set" version = "0.3.0" @@ -549,12 +926,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "typeid" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" - [[package]] name = "typenum" version = "1.17.0" @@ -588,6 +959,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" + [[package]] name = "version_check" version = "0.9.4" @@ -641,6 +1018,24 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "zerocopy" version = "0.7.32" diff --git a/notes/comm_arch.md b/notes/comm_arch.md new file mode 100644 index 0000000..16b5e34 --- /dev/null +++ b/notes/comm_arch.md @@ -0,0 +1,10 @@ +# Communication Architecture + +- **Communication medium** 1-1 duplex ordered reliable and a request/reply notify protocol defined on top (`orchid-base` mostly) + +- **Protocol definition** plain objects that define nothing beside serialization/deserialization and English descriptions of invariants (`orchid-api`) + +- **Active objects** smart objects that represent resources and communicate their modification through the protocol, sorted into 3 categories for asymmetric communication: common/extension/host. Some ext/host logic is defined in `orchid-base` to ensure that other behaviour within it can rely on certain global functionality. ext/host also manage their respective connection state (`orchid-base`, `orchid-extension`, `orchid-host`) + +- **Application** (client, server) binaries that use active objects to implement actual application behaviour (`orcx`, `orchid-std`) + diff --git a/orchid-api-traits/src/lib.rs b/orchid-api-traits/src/lib.rs index 8444a33..d912d15 100644 --- a/orchid-api-traits/src/lib.rs +++ b/orchid-api-traits/src/lib.rs @@ -5,7 +5,5 @@ mod relations; pub use coding::{Coding, Decode, Encode}; pub use helpers::{encode_enum, read_exact, write_exact}; -pub use hierarchy::{ - Extends, InHierarchy, TLBool, TLFalse, TLTrue, UnderRoot, -}; +pub use hierarchy::{Extends, InHierarchy, TLBool, TLFalse, TLTrue, UnderRoot}; pub use relations::{Channel, MsgSet, Request}; diff --git a/orchid-api/src/tree.rs b/orchid-api/src/tree.rs index 87faf26..5136b0d 100644 --- a/orchid-api/src/tree.rs +++ b/orchid-api/src/tree.rs @@ -7,6 +7,7 @@ use orchid_api_traits::Request; use ordered_float::NotNan; use crate::atom::LocalAtom; +use crate::error::ProjErrOrRef; use crate::expr::Expr; use crate::interner::TStr; use crate::proto::HostExtReq; @@ -38,7 +39,7 @@ pub enum Token { Slot(TreeTicket), /// A static compile-time error returned by erroring lexers if /// the rest of the source is likely still meaningful - Bottom(String), + Bottom(ProjErrOrRef), } #[derive(Clone, Debug, Coding)] diff --git a/orchid-base/Cargo.toml b/orchid-base/Cargo.toml index c3d321a..caad402 100644 --- a/orchid-base/Cargo.toml +++ b/orchid-base/Cargo.toml @@ -17,5 +17,6 @@ orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" } orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" } ordered-float = "4.2.0" rust-embed = "8.3.0" +rust_decimal = "1.35.0" substack = "1.1.0" trait-set = "0.3.0" diff --git a/orchid-base/src/as_api.rs b/orchid-base/src/as_api.rs new file mode 100644 index 0000000..fc82fb4 --- /dev/null +++ b/orchid-base/src/as_api.rs @@ -0,0 +1,10 @@ +use orchid_api_traits::Coding; + +pub trait AsApi: Sized { + type Api: Sized; + type Ctx<'a>; + fn to_api(&self, ctx: Self::Ctx<'_>) -> Self::Api; + fn into_api(self, ctx: Self::Ctx<'_>) -> Self::Api { self.to_api(ctx) } + fn from_api_ref(api: &Self::Api, ctx: Self::Ctx<'_>) -> Self; + fn from_api(api: Self::Api, ctx: Self::Ctx<'_>) -> Self { Self::from_api_ref(&api, ctx) } +} diff --git a/orchid-base/src/error.rs b/orchid-base/src/error.rs index 1facd81..3e50802 100644 --- a/orchid-base/src/error.rs +++ b/orchid-base/src/error.rs @@ -27,22 +27,26 @@ impl ErrorPosition { location: self.position.to_api(), } } + pub fn new(msg: &str, position: Pos) -> Self { + Self { message: Some(Arc::new(msg.to_string())), position } + } } impl From for ErrorPosition { fn from(origin: Pos) -> Self { Self { position: origin, message: None } } } -pub struct ErrorDetails { +#[derive(Clone)] +pub struct OwnedError { pub description: Tok, pub message: Arc, - pub locations: Vec, + pub positions: Vec, } -impl ErrorDetails { +impl OwnedError { pub fn from_api(err: &ProjErr) -> Self { Self { description: deintern(err.description), message: err.message.clone(), - locations: err.locations.iter().map(ErrorPosition::from_api).collect(), + positions: err.locations.iter().map(ErrorPosition::from_api).collect(), } } } diff --git a/orchid-base/src/lib.rs b/orchid-base/src/lib.rs index 6f76239..2a3ff0b 100644 --- a/orchid-base/src/lib.rs +++ b/orchid-base/src/lib.rs @@ -5,6 +5,7 @@ pub mod event; pub mod msg; // pub mod gen; pub mod api_utils; +pub mod as_api; pub mod box_cow; pub mod char_filter; pub mod error; @@ -13,7 +14,8 @@ pub mod interner; pub mod join; pub mod location; pub mod name; +pub mod number; pub mod reqnot; pub mod sequence; +pub mod tokens; pub mod tree; -// pub mod virt_fs; diff --git a/orchid-base/src/number.rs b/orchid-base/src/number.rs new file mode 100644 index 0000000..9a55fe8 --- /dev/null +++ b/orchid-base/src/number.rs @@ -0,0 +1,150 @@ +use std::num::IntErrorKind; +use std::ops::Range; + +use ordered_float::NotNan; +use rust_decimal::Decimal; + +/// A number, either floating point or unsigned int, parsed by Orchid. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Numeric { + /// A nonnegative integer + Uint(u64), + /// A binary float other than NaN + Float(NotNan), + /// A decimal number + Decimal(Decimal), +} +impl Numeric { + pub fn decimal(num: i64, scale: u32) -> Self { Self::Decimal(Decimal::new(num, scale)) } + pub fn float(value: f64) -> Self { Self::Float(NotNan::new(value).unwrap()) } +} + +/// Rasons why [parse_num] might fail. See [NumError]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NumErrorKind { + /// The literal describes [f64::NAN] + NaN, + /// Some integer appearing in the literal overflows [usize] + Overflow, + /// A character that isn't a digit in the given base was found + InvalidDigit, +} +impl NumErrorKind { + fn from_int(kind: &IntErrorKind) -> Self { + match kind { + IntErrorKind::InvalidDigit => Self::InvalidDigit, + IntErrorKind::NegOverflow | IntErrorKind::PosOverflow => Self::Overflow, + _ => panic!("Impossible error condition"), + } + } +} + +/// Error produced by [parse_num] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NumError { + /// Location + pub range: Range, + /// Reason + pub kind: NumErrorKind, +} + +/// Parse a numbre literal out of text +pub fn parse_num(string: &str) -> Result { + let overflow_err = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow }; + let (radix, noprefix, pos) = (string.strip_prefix("0x").map(|s| (16u8, s, 2))) + .or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2))) + .or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2))) + .unwrap_or((10u8, string, 0)); + // identity + let (base, exponent) = match noprefix.split_once('p') { + Some((b, e)) => { + let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1)); + (b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32) + }, + None => (noprefix, 0), + }; + match base.split_once('.') { + None => { + let base_usize = int_parse(base, radix, pos)?; + if let Ok(pos_exp) = u32::try_from(exponent) { + if let Some(radical) = u64::from(radix).checked_pow(pos_exp) { + let number = base_usize.checked_mul(radical).ok_or(overflow_err)?; + return Ok(Numeric::Uint(number)); + } + } + let f = (base_usize as f64) * (radix as f64).powi(exponent); + let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN }; + Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?)) + }, + Some((whole, part)) => { + let whole_n = int_parse(whole, radix, pos)?; + let part_n = int_parse(part, radix, pos + whole.len() + 1)?; + let scale = part.chars().filter(|c| *c != '_').count() as u32; + if radix == 10 { + let mut scaled_unit = Decimal::ONE; + (scaled_unit.set_scale(scale)) + .map_err(|_| NumError { range: 0..string.len(), kind: NumErrorKind::Overflow })?; + Ok(Numeric::Decimal(Decimal::from(whole_n) + scaled_unit * Decimal::from(part_n))) + } else { + let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32)); + let f = real_val * (radix as f64).powi(exponent); + Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN"))) + } + }, + } +} + +fn int_parse(s: &str, radix: u8, start: usize) -> Result { + let s = s.chars().filter(|c| *c != '_').collect::(); + let range = start..(start + s.len()); + u64::from_str_radix(&s, radix as u32) + .map_err(|e| NumError { range, kind: NumErrorKind::from_int(e.kind()) }) +} + +/// Filter for characters that can appear in numbers +pub fn numchar(c: char) -> bool { c.is_alphanumeric() | "._-".contains(c) } +/// Filter for characters that can start numbers +pub fn numstart(c: char) -> bool { c.is_ascii_digit() } + +/// Print a number as a base-16 floating point literal +#[must_use] +pub fn print_nat16(num: NotNan) -> String { + if *num == 0.0 { + return "0x0".to_string(); + } else if num.is_infinite() { + return match num.is_sign_positive() { + true => "Infinity".to_string(), + false => "-Infinity".to_string(), + }; + } else if num.is_nan() { + return "NaN".to_string(); + } + let exp = num.log(16.0).floor(); + let man = *num / 16_f64.powf(exp); + format!("0x{man}p{exp:.0}") +} + +#[cfg(test)] +mod test { + use super::{parse_num, Numeric}; + + #[test] + fn just_ints() { + let test = |s, n| assert_eq!(parse_num(s), Ok(Numeric::Uint(n))); + test("12345", 12345); + test("0xcafebabe", 0xcafebabe); + test("0o751", 0o751); + test("0b111000111", 0b111000111); + } + + #[test] + fn decimals() { + let test = |s, n| assert_eq!(parse_num(s), Ok(n)); + test("3.1417", Numeric::decimal(31417, 4)); + test("0xf.cafe", Numeric::float(0xf as f64 + 0xcafe as f64 / 0x10000 as f64)); + test("34p3", Numeric::Uint(34000)); + test("0x2p3", Numeric::Uint(0x2 * 0x1000)); + test("1.5p3", Numeric::decimal(1500, 0)); + test("0x2.5p3", Numeric::float((0x25 * 0x100) as f64)); + } +} diff --git a/orchid-base/src/tokens.rs b/orchid-base/src/tokens.rs new file mode 100644 index 0000000..1ced2f0 --- /dev/null +++ b/orchid-base/src/tokens.rs @@ -0,0 +1,15 @@ +use orchid_api::tree::{Placeholder, PlaceholderKind}; + +use crate::interner::{deintern, Tok}; + +#[derive(Clone)] +pub struct OwnedPh { + pub name: Tok, + pub kind: PlaceholderKind, +} +impl OwnedPh { + pub fn to_api(&self) -> Placeholder { + Placeholder { name: self.name.marker(), kind: self.kind.clone() } + } + pub fn from_api(ph: Placeholder) -> Self { Self { name: deintern(ph.name), kind: ph.kind } } +} diff --git a/orchid-extension/Cargo.toml b/orchid-extension/Cargo.toml index 30e3cf3..9fd9de0 100644 --- a/orchid-extension/Cargo.toml +++ b/orchid-extension/Cargo.toml @@ -22,4 +22,3 @@ ordered-float = "4.2.0" paste = "1.0.15" substack = "1.1.0" trait-set = "0.3.0" -typeid = "1.0.0" diff --git a/orchid-extension/src/atom.rs b/orchid-extension/src/atom.rs index a7ffca7..d67cfb2 100644 --- a/orchid-extension/src/atom.rs +++ b/orchid-extension/src/atom.rs @@ -1,4 +1,4 @@ -use std::any::{type_name, Any}; +use std::any::{type_name, Any, TypeId}; use std::io::{Read, Write}; use std::ops::Deref; @@ -9,7 +9,6 @@ use orchid_api_traits::{Coding, Decode, Request}; use orchid_base::location::Pos; use orchid_base::reqnot::Requester; use trait_set::trait_set; -use typeid::ConstTypeId; use crate::error::ProjectError; use crate::expr::{ExprHandle, GenExpr}; @@ -33,19 +32,22 @@ impl AtomCard for A { pub trait AtomicFeatures: Atomic { fn factory(self) -> AtomFactory; - fn info() -> &'static AtomInfo; + type Info: AtomDynfo; + const INFO: &'static Self::Info; } pub trait AtomicFeaturesImpl { fn _factory(self) -> AtomFactory; - fn _info() -> &'static AtomInfo; + type _Info: AtomDynfo; + const _INFO: &'static Self::_Info; } impl> AtomicFeatures for A { fn factory(self) -> AtomFactory { self._factory() } - fn info() -> &'static AtomInfo { Self::_info() } + type Info = >::_Info; + const INFO: &'static Self::Info = Self::_INFO; } -pub fn get_info(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &AtomInfo) { - atom_info_for(sys, ConstTypeId::of::()).unwrap_or_else(|| { +pub fn get_info(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &'static dyn AtomDynfo) { + atom_info_for(sys, TypeId::of::()).unwrap_or_else(|| { panic!("Atom {} not associated with system {}", type_name::(), sys.name()) }) } @@ -75,14 +77,14 @@ impl Deref for TypAtom { fn deref(&self) -> &Self::Target { &self.value } } -pub struct AtomInfo { - pub tid: ConstTypeId, - pub decode: fn(&[u8]) -> Box, - pub call: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, - pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, - pub same: fn(&[u8], SysCtx, &[u8]) -> bool, - pub handle_req: fn(&[u8], SysCtx, &mut dyn Read, &mut dyn Write), - pub drop: fn(&[u8], SysCtx), +pub trait AtomDynfo: Send + Sync + 'static { + fn tid(&self) -> TypeId; + fn decode(&self, data: &[u8]) -> Box; + fn call(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr; + fn call_ref(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr; + fn same(&self, buf: &[u8], ctx: SysCtx, buf2: &[u8]) -> bool; + fn handle_req(&self, buf: &[u8], ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write); + fn drop(&self, buf: &[u8], ctx: SysCtx); } trait_set! { @@ -102,4 +104,4 @@ impl Clone for AtomFactory { pub struct ErrorNotCallable; impl ProjectError for ErrorNotCallable { const DESCRIPTION: &'static str = "This atom is not callable"; -} \ No newline at end of file +} diff --git a/orchid-extension/src/atom_owned.rs b/orchid-extension/src/atom_owned.rs index a8a90cb..b9d4685 100644 --- a/orchid-extension/src/atom_owned.rs +++ b/orchid-extension/src/atom_owned.rs @@ -1,11 +1,19 @@ -use std::{any::{type_name, Any}, borrow::Cow, io::{Read, Write}, num::NonZeroU64}; +use std::any::{type_name, Any, TypeId}; +use std::borrow::Cow; +use std::io::{Read, Write}; +use std::marker::PhantomData; +use std::num::NonZeroU64; -use orchid_api::{atom::LocalAtom, expr::ExprTicket}; +use orchid_api::atom::LocalAtom; +use orchid_api::expr::ExprTicket; use orchid_api_traits::{Decode, Encode}; use orchid_base::id_store::{IdRecord, IdStore}; -use typeid::ConstTypeId; -use crate::{atom::{AtomCard, AtomFactory, AtomInfo, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrorNotCallable}, expr::{bot, ExprHandle, GenExpr}, system::{atom_info_for, SysCtx}}; +use crate::atom::{ + AtomCard, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrorNotCallable, +}; +use crate::expr::{bot, ExprHandle, GenExpr}; +use crate::system::{atom_info_for, SysCtx}; pub struct OwnedVariant; impl AtomicVariant for OwnedVariant {} @@ -19,26 +27,37 @@ impl> AtomicFeaturesImpl &'static AtomInfo { - fn with_atom(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box>) -> U) -> U { - f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID")) - } - &const { - AtomInfo { - tid: ConstTypeId::of::(), - decode: |mut b| Box::new(::Data::decode(&mut b)), - call: |b, ctx, arg| with_atom(b, |a| a.remove().dyn_call(ctx, arg)), - call_ref: |b, ctx, arg| with_atom(b, |a| a.dyn_call_ref(ctx, arg)), - same: |b1, ctx, b2| with_atom(b1, |a1| with_atom(b2, |a2| a1.dyn_same(ctx, &**a2))), - handle_req: |b, ctx, req, rep| with_atom(b, |a| a.dyn_handle_req(ctx, req, rep)), - drop: |b, ctx| with_atom(b, |a| a.remove().dyn_free(ctx)), - } - } + type _Info = OwnedAtomDynfo; + const _INFO: &'static Self::_Info = &OwnedAtomDynfo(PhantomData); +} + +fn with_atom(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box>) -> U) -> U { + f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID")) +} + +pub struct OwnedAtomDynfo(PhantomData); +impl AtomDynfo for OwnedAtomDynfo { + fn tid(&self) -> TypeId { TypeId::of::() } + fn decode(&self, data: &[u8]) -> Box { + Box::new(::Data::decode(&mut &data[..])) } + fn call(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr { + with_atom(buf, |a| a.remove().dyn_call(ctx, arg)) + } + fn call_ref(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr { + with_atom(buf, |a| a.dyn_call_ref(ctx, arg)) + } + fn same(&self, buf: &[u8], ctx: SysCtx, buf2: &[u8]) -> bool { + with_atom(buf, |a1| with_atom(buf2, |a2| a1.dyn_same(ctx, &**a2))) + } + fn handle_req(&self, buf: &[u8], ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write) { + with_atom(buf, |a| a.dyn_handle_req(ctx, req, rep)) + } + fn drop(&self, buf: &[u8], ctx: SysCtx) { with_atom(buf, |a| a.remove().dyn_free(ctx)) } } /// Atoms that have a [Drop] -pub trait OwnedAtom: AtomCard + Send + Sync + Any + Clone + 'static { +pub trait OwnedAtom: Atomic + Send + Sync + Any + Clone + 'static { fn val(&self) -> Cow<'_, Self::Data>; #[allow(unused_variables)] fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) } @@ -61,7 +80,7 @@ pub trait OwnedAtom: AtomCard + Send + Sync + Any + Clone + 'static { fn free(self, ctx: SysCtx) {} } pub trait DynOwnedAtom: Send + Sync + 'static { - fn atom_tid(&self) -> ConstTypeId; + fn atom_tid(&self) -> TypeId; fn as_any_ref(&self) -> &dyn Any; fn encode(&self, buffer: &mut dyn Write); fn dyn_call_ref(&self, ctx: SysCtx, arg: ExprTicket) -> GenExpr; @@ -71,7 +90,7 @@ pub trait DynOwnedAtom: Send + Sync + 'static { fn dyn_free(self: Box, ctx: SysCtx); } impl DynOwnedAtom for T { - fn atom_tid(&self) -> ConstTypeId { ConstTypeId::of::() } + fn atom_tid(&self) -> TypeId { TypeId::of::() } fn as_any_ref(&self) -> &dyn Any { self } fn encode(&self, buffer: &mut dyn Write) { self.val().as_ref().encode(buffer) } fn dyn_call_ref(&self, ctx: SysCtx, arg: ExprTicket) -> GenExpr { @@ -81,7 +100,7 @@ impl DynOwnedAtom for T { self.call(ExprHandle::from_args(ctx, arg)) } fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool { - if ConstTypeId::of::() != other.as_any_ref().type_id() { + if TypeId::of::() != other.as_any_ref().type_id() { return false; } let other_self = other.as_any_ref().downcast_ref().expect("The type_ids are the same"); @@ -93,4 +112,4 @@ impl DynOwnedAtom for T { fn dyn_free(self: Box, ctx: SysCtx) { self.free(ctx) } } -pub(crate) static OBJ_STORE: IdStore> = IdStore::new(); \ No newline at end of file +pub(crate) static OBJ_STORE: IdStore> = IdStore::new(); diff --git a/orchid-extension/src/atom_thin.rs b/orchid-extension/src/atom_thin.rs index 4f6a109..ffdd4d7 100644 --- a/orchid-extension/src/atom_thin.rs +++ b/orchid-extension/src/atom_thin.rs @@ -1,10 +1,18 @@ -use std::{any::type_name, fmt, io::Write}; +use std::any::{type_name, Any, TypeId}; +use std::fmt; +use std::io::Write; +use std::marker::PhantomData; use orchid_api::atom::LocalAtom; +use orchid_api::expr::ExprTicket; use orchid_api_traits::{Coding, Decode, Encode}; -use typeid::ConstTypeId; -use crate::{atom::{get_info, AtomCard, AtomFactory, AtomInfo, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrorNotCallable}, expr::{bot, ExprHandle, GenExpr}, system::SysCtx}; +use crate::atom::{ + get_info, AtomCard, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, + ErrorNotCallable, +}; +use crate::expr::{bot, ExprHandle, GenExpr}; +use crate::system::SysCtx; pub struct ThinVariant; impl AtomicVariant for ThinVariant {} @@ -16,22 +24,32 @@ impl> AtomicFeaturesImpl &'static AtomInfo { - &const { - AtomInfo { - tid: ConstTypeId::of::(), - decode: |mut b| Box::new(Self::decode(&mut b)), - call: |mut b, ctx, extk| Self::decode(&mut b).call(ExprHandle::from_args(ctx, extk)), - call_ref: |mut b, ctx, extk| Self::decode(&mut b).call(ExprHandle::from_args(ctx, extk)), - handle_req: |mut b, ctx, req, rep| Self::decode(&mut b).handle_req(ctx, Decode::decode(req), rep), - same: |mut b1, ctx, mut b2| Self::decode(&mut b1).same(ctx, &Self::decode(&mut b2)), - drop: |mut b1, _| eprintln!("Received drop signal for non-drop atom {:?}", Self::decode(&mut b1)), - } - } + type _Info = ThinAtomDynfo; + const _INFO: &'static Self::_Info = &ThinAtomDynfo(PhantomData); +} + +pub struct ThinAtomDynfo(PhantomData); +impl AtomDynfo for ThinAtomDynfo { + fn tid(&self) -> TypeId { TypeId::of::() } + fn decode(&self, mut data: &[u8]) -> Box { Box::new(T::decode(&mut data)) } + fn call(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr { + T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)) + } + fn call_ref(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr { + T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)) + } + fn handle_req(&self, buf: &[u8], ctx: SysCtx, req: &mut dyn std::io::Read, rep: &mut dyn Write) { + T::decode(&mut &buf[..]).handle_req(ctx, Decode::decode(req), rep) + } + fn same(&self, buf: &[u8], ctx: SysCtx, buf2: &[u8]) -> bool { + T::decode(&mut &buf[..]).same(ctx, &T::decode(&mut &buf2[..])) + } + fn drop(&self, buf: &[u8], _ctx: SysCtx) { + eprintln!("Received drop signal for non-drop atom {:?}", T::decode(&mut &buf[..])) } } -pub trait ThinAtom: AtomCard + Coding + fmt::Debug { +pub trait ThinAtom: AtomCard + Coding + fmt::Debug + Send + Sync + 'static { #[allow(unused_variables)] fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) } #[allow(unused_variables)] diff --git a/orchid-extension/src/conv.rs b/orchid-extension/src/conv.rs index ef77360..b8feb87 100644 --- a/orchid-extension/src/conv.rs +++ b/orchid-extension/src/conv.rs @@ -1,6 +1,9 @@ use orchid_base::location::Pos; -use crate::{atom::{AtomicFeatures, TypAtom}, error::{ProjectError, ProjectResult}, expr::{atom, bot_obj, ExprHandle, GenExpr, OwnedExpr}, system::downcast_atom}; +use crate::atom::{AtomicFeatures, TypAtom}; +use crate::error::{ProjectError, ProjectResult}; +use crate::expr::{atom, bot_obj, ExprHandle, GenExpr, OwnedExpr}; +use crate::system::downcast_atom; pub trait TryFromExpr: Sized { fn try_from_expr(expr: ExprHandle) -> ProjectResult; @@ -25,14 +28,14 @@ impl ProjectError for ErrorNotAtom { pub struct ErrorUnexpectedType(Pos); impl ProjectError for ErrorUnexpectedType { const DESCRIPTION: &'static str = "Type error"; - fn one_position(&self) -> Pos { - self.0.clone() - } + fn one_position(&self) -> Pos { self.0.clone() } } impl TryFromExpr for TypAtom { fn try_from_expr(expr: ExprHandle) -> ProjectResult { - OwnedExpr::new(expr).foreign_atom().map_err(|ex| ErrorNotAtom(ex.pos.clone()).pack()) + OwnedExpr::new(expr) + .foreign_atom() + .map_err(|ex| ErrorNotAtom(ex.pos.clone()).pack()) .and_then(|f| downcast_atom(f).map_err(|f| ErrorUnexpectedType(f.pos).pack())) } } @@ -43,13 +46,13 @@ pub trait ToExpr { impl ToExpr for ProjectResult { fn to_expr(self) -> GenExpr { - match self { - Err(e) => bot_obj(e), - Ok(t) => t.to_expr(), - } + match self { + Err(e) => bot_obj(e), + Ok(t) => t.to_expr(), + } } } impl ToExpr for A { fn to_expr(self) -> GenExpr { atom(self) } -} \ No newline at end of file +} diff --git a/orchid-extension/src/entrypoint.rs b/orchid-extension/src/entrypoint.rs index 3317b82..13faf85 100644 --- a/orchid-extension/src/entrypoint.rs +++ b/orchid-extension/src/entrypoint.rs @@ -19,7 +19,7 @@ use orchid_base::interner::{deintern, init_replica, sweep_replica}; use orchid_base::name::PathSlice; use orchid_base::reqnot::{ReqNot, Requester}; -use crate::atom::AtomInfo; +use crate::atom::AtomDynfo; use crate::error::{err_or_ref_to_api, unpack_err}; use crate::fs::VirtFS; use crate::lexer::LexContext; @@ -48,7 +48,7 @@ pub struct SystemRecord { pub fn with_atom_record( systems: &Mutex>, atom: &Atom, - cb: impl FnOnce(&AtomInfo, CtedObj, &[u8]) -> T, + cb: impl FnOnce(&'static dyn AtomDynfo, CtedObj, &[u8]) -> T, ) -> T { let mut data = &atom.data[..]; let systems_g = systems.lock().unwrap(); @@ -77,7 +77,7 @@ pub fn extension_main(data: ExtensionData) { mem::drop(systems.lock().unwrap().remove(&sys_id)), HostExtNotif::AtomDrop(AtomDrop(atom)) => { with_atom_record(&systems, &atom, |rec, cted, data| { - (rec.drop)(data, SysCtx{ reqnot, id: atom.owner, cted }) + rec.drop(data, SysCtx{ reqnot, id: atom.owner, cted }) }) } }), diff --git a/orchid-extension/src/error.rs b/orchid-extension/src/error.rs index 1df7a88..0793b79 100644 --- a/orchid-extension/src/error.rs +++ b/orchid-extension/src/error.rs @@ -10,7 +10,7 @@ use orchid_api::error::{GetErrorDetails, ProjErr, ProjErrId, ProjErrOrRef}; use orchid_api::proto::ExtMsgSet; use orchid_base::boxed_iter::{box_once, BoxedIter}; use orchid_base::clone; -use orchid_base::error::{ErrorDetails, ErrorPosition}; +use orchid_base::error::{ErrorPosition, OwnedError}; use orchid_base::interner::{deintern, intern}; use orchid_base::location::{GetSrc, Pos}; use orchid_base::reqnot::{ReqNot, Requester}; @@ -290,12 +290,16 @@ pub(crate) fn err_or_ref_to_api(err: ProjectErrorObj) -> ProjErrOrRef { } pub fn err_from_api(err: &ProjErr, reqnot: ReqNot) -> ProjectErrorObj { - Arc::new(RelayedError { id: None, reqnot, details: ErrorDetails::from_api(err).into() }) + Arc::new(RelayedError { id: None, reqnot, details: OwnedError::from_api(err).into() }) } -pub(crate) fn err_from_api_or_ref(err: &ProjErrOrRef, reqnot: ReqNot) -> ProjectErrorObj { +pub(crate) fn err_from_api_or_ref( + err: &ProjErrOrRef, + reqnot: ReqNot, +) -> ProjectErrorObj { match err { - ProjErrOrRef::Known(id) => Arc::new(RelayedError { id: Some(*id), reqnot, details: OnceLock::default() }), + ProjErrOrRef::Known(id) => + Arc::new(RelayedError { id: Some(*id), reqnot, details: OnceLock::default() }), ProjErrOrRef::New(err) => err_from_api(err, reqnot), } } @@ -303,18 +307,18 @@ pub(crate) fn err_from_api_or_ref(err: &ProjErrOrRef, reqnot: ReqNot) struct RelayedError { pub id: Option, pub reqnot: ReqNot, - pub details: OnceLock, + pub details: OnceLock, } impl RelayedError { - fn details(&self) -> &ErrorDetails { + fn details(&self) -> &OwnedError { let Self { id, reqnot, details: data } = self; data.get_or_init(clone!(reqnot; move || { let id = id.expect("Either data or ID must be initialized"); let projerr = reqnot.request(GetErrorDetails(id)); - ErrorDetails { + OwnedError { description: deintern(projerr.description), message: projerr.message, - locations: projerr.locations.iter().map(ErrorPosition::from_api).collect_vec(), + positions: projerr.locations.iter().map(ErrorPosition::from_api).collect_vec(), } })) } @@ -325,6 +329,6 @@ impl DynProjectError for RelayedError { fn as_any_ref(&self) -> &dyn std::any::Any { self } fn into_packed(self: Arc) -> ProjectErrorObj { self } fn positions(&self) -> BoxedIter<'_, ErrorPosition> { - Box::new(self.details().locations.iter().cloned()) + Box::new(self.details().positions.iter().cloned()) } } diff --git a/orchid-extension/src/fun.rs b/orchid-extension/src/fun.rs index b64106c..8788593 100644 --- a/orchid-extension/src/fun.rs +++ b/orchid-extension/src/fun.rs @@ -6,9 +6,9 @@ use trait_set::trait_set; use crate::atom::Atomic; use crate::atom_owned::{OwnedAtom, OwnedVariant}; +use crate::conv::{ToExpr, TryFromExpr}; use crate::expr::{ExprHandle, GenExpr}; use crate::system::SysCtx; -use crate::conv::{ToExpr, TryFromExpr}; trait_set! { trait FunCB = FnOnce(ExprHandle) -> GenExpr + DynClone + Send + Sync + 'static; @@ -16,7 +16,9 @@ trait_set! { pub struct Fun(Box); impl Fun { - pub fn new(f: impl FnOnce(I) -> O + Clone + Send + Sync + 'static) -> Self { + pub fn new( + f: impl FnOnce(I) -> O + Clone + Send + Sync + 'static, + ) -> Self { Self(Box::new(|eh| I::try_from_expr(eh).map(f).to_expr())) } } diff --git a/orchid-extension/src/lexer.rs b/orchid-extension/src/lexer.rs index 91f8a4e..40e2da1 100644 --- a/orchid-extension/src/lexer.rs +++ b/orchid-extension/src/lexer.rs @@ -10,7 +10,7 @@ use orchid_base::reqnot::{ReqNot, Requester}; use crate::error::{ err_from_api_or_ref, err_or_ref_to_api, pack_err, unpack_err, ProjectErrorObj, ProjectResult, }; -use crate::tree::{GenTok, GenTokTree}; +use crate::tree::{OwnedTok, OwnedTokTree}; pub struct LexContext<'a> { pub text: &'a Tok, @@ -20,13 +20,13 @@ pub struct LexContext<'a> { pub reqnot: ReqNot, } impl<'a> LexContext<'a> { - pub fn recurse(&self, tail: &'a str) -> ProjectResult<(&'a str, GenTokTree)> { + pub fn recurse(&self, tail: &'a str) -> ProjectResult<(&'a str, OwnedTokTree)> { let start = self.pos(tail); self .reqnot .request(SubLex { pos: start, id: self.id }) .map_err(|e| pack_err(e.iter().map(|e| err_from_api_or_ref(e, self.reqnot.clone())))) - .map(|lx| (&self.text[lx.pos as usize..], GenTok::Slot(lx.ticket).at(start..lx.pos))) + .map(|lx| (&self.text[lx.pos as usize..], OwnedTok::Slot(lx.ticket).at(start..lx.pos))) } pub fn pos(&self, tail: &'a str) -> u32 { (self.text.len() - tail.len()) as u32 } @@ -47,7 +47,7 @@ pub trait Lexer: Send + Sync + Sized + Default + 'static { fn lex<'a>( tail: &'a str, ctx: &'a LexContext<'a>, - ) -> Option>; + ) -> Option>; } pub trait DynLexer: Send + Sync + 'static { @@ -56,7 +56,7 @@ pub trait DynLexer: Send + Sync + 'static { &self, tail: &'a str, ctx: &'a LexContext<'a>, - ) -> Option>; + ) -> Option>; } impl DynLexer for T { @@ -65,7 +65,7 @@ impl DynLexer for T { &self, tail: &'a str, ctx: &'a LexContext<'a>, - ) -> Option> { + ) -> Option> { T::lex(tail, ctx) } } diff --git a/orchid-extension/src/lib.rs b/orchid-extension/src/lib.rs index e2e23bf..dca8bcc 100644 --- a/orchid-extension/src/lib.rs +++ b/orchid-extension/src/lib.rs @@ -1,4 +1,7 @@ pub mod atom; +pub mod atom_owned; +pub mod atom_thin; +pub mod conv; pub mod entrypoint; pub mod error; pub mod expr; @@ -10,6 +13,3 @@ pub mod other_system; pub mod system; pub mod system_ctor; pub mod tree; -pub mod conv; -pub mod atom_thin; -pub mod atom_owned; diff --git a/orchid-extension/src/system.rs b/orchid-extension/src/system.rs index 0312259..0ff6182 100644 --- a/orchid-extension/src/system.rs +++ b/orchid-extension/src/system.rs @@ -1,11 +1,11 @@ -use orchid_api_traits::Decode; +use std::any::TypeId; use orchid_api::proto::ExtMsgSet; use orchid_api::system::SysId; +use orchid_api_traits::Decode; use orchid_base::reqnot::ReqNot; -use typeid::ConstTypeId; -use crate::atom::{get_info, AtomCard, AtomInfo, AtomicFeatures, ForeignAtom, TypAtom}; +use crate::atom::{get_info, AtomCard, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom}; use crate::fs::DeclFs; use crate::fun::Fun; use crate::lexer::LexerObj; @@ -15,44 +15,45 @@ use crate::tree::GenTree; /// System as consumed by foreign code pub trait SystemCard: Default + Send + Sync + 'static { type Ctor: SystemCtor; - const ATOM_DEFS: &'static [Option &'static AtomInfo>]; + const ATOM_DEFS: &'static [Option<&'static dyn AtomDynfo>]; } pub trait DynSystemCard: Send + Sync + 'static { fn name(&self) -> &'static str; /// Atoms explicitly defined by the system card. Do not rely on this for /// querying atoms as it doesn't include the general atom types - fn atoms(&self) -> &'static [Option &'static AtomInfo>]; + fn atoms(&self) -> &'static [Option<&'static dyn AtomDynfo>]; } /// Atoms supported by this package which may appear in all extensions. /// The indices of these are bitwise negated, such that the MSB of an atom index /// marks whether it belongs to this package (0) or the importer (1) -fn general_atoms() -> &'static [Option &'static AtomInfo>] { - &[Some(Fun::info)] -} +fn general_atoms() -> &'static [Option<&'static dyn AtomDynfo>] { &[Some(Fun::INFO)] } pub fn atom_info_for( sys: &(impl DynSystemCard + ?Sized), - tid: ConstTypeId, -) -> Option<(u64, &AtomInfo)> { + tid: TypeId, +) -> Option<(u64, &'static dyn AtomDynfo)> { (sys.atoms().iter().enumerate().map(|(i, o)| (i as u64, o))) .chain(general_atoms().iter().enumerate().map(|(i, o)| (!(i as u64), o))) - .filter_map(|(i, o)| o.as_ref().map(|a| (i, a()))) - .find(|ent| ent.1.tid == tid) + .filter_map(|(i, o)| o.as_ref().map(|a| (i, *a))) + .find(|ent| ent.1.tid() == tid) } -pub fn atom_by_idx(sys: &(impl DynSystemCard + ?Sized), tid: u64) -> Option<&'static AtomInfo> { +pub fn atom_by_idx( + sys: &(impl DynSystemCard + ?Sized), + tid: u64, +) -> Option<&'static dyn AtomDynfo> { if (tid >> (u64::BITS - 1)) & 1 == 1 { - general_atoms()[!tid as usize].map(|f| f()) + general_atoms()[!tid as usize] } else { - sys.atoms()[tid as usize].map(|f| f()) + sys.atoms()[tid as usize] } } impl DynSystemCard for T { fn name(&self) -> &'static str { T::Ctor::NAME } - fn atoms(&self) -> &'static [Option &'static AtomInfo>] { Self::ATOM_DEFS } + fn atoms(&self) -> &'static [Option<&'static dyn AtomDynfo>] { Self::ATOM_DEFS } } /// System as defined by author @@ -85,7 +86,7 @@ pub fn downcast_atom(foreign: ForeignAtom) -> Result, Fo match info_ent { None => Err(foreign), Some((_, info)) => { - let val = (info.decode)(data); + let val = info.decode(data); let value = *val.downcast::().expect("atom decode returned wrong type"); Ok(TypAtom { value, data: foreign }) }, diff --git a/orchid-extension/src/tree.rs b/orchid-extension/src/tree.rs index 4afa4ea..2f85317 100644 --- a/orchid-extension/src/tree.rs +++ b/orchid-extension/src/tree.rs @@ -4,38 +4,34 @@ use ahash::HashMap; use dyn_clone::{clone_box, DynClone}; use itertools::Itertools; use orchid_api::tree::{ - MacroRule, Paren, Placeholder, PlaceholderKind, Token, TokenTree, Tree, TreeId, TreeModule, + MacroRule, Paren, PlaceholderKind, Token, TokenTree, Tree, TreeId, TreeModule, TreeTicket, }; -use orchid_base::interner::{intern, Tok}; +use orchid_base::interner::intern; use orchid_base::location::Pos; use orchid_base::name::VName; +use orchid_base::tokens::OwnedPh; use ordered_float::NotNan; use trait_set::trait_set; use crate::atom::AtomFactory; use crate::conv::ToExpr; +use crate::error::{err_or_ref_to_api, ProjectErrorObj}; use crate::expr::GenExpr; use crate::system::DynSystem; #[derive(Clone)] -pub struct GenPh { - pub name: Tok, - pub kind: PlaceholderKind, -} - -#[derive(Clone)] -pub struct GenTokTree { - pub tok: GenTok, +pub struct OwnedTokTree { + pub tok: OwnedTok, pub range: Range, } -impl GenTokTree { +impl OwnedTokTree { pub fn into_api(self, sys: &dyn DynSystem) -> TokenTree { TokenTree { token: self.tok.into_api(sys), range: self.range } } } -pub fn ph(s: &str) -> GenPh { +pub fn ph(s: &str) -> OwnedPh { match s.strip_prefix("..") { Some(v_tail) => { let (mid, priority) = match v_tail.split_once(':') { @@ -49,29 +45,30 @@ pub fn ph(s: &str) -> GenPh { if konst::string::starts_with(name, "_") { panic!("Names starting with an underscore indicate a single-name scalar placeholder") } - GenPh { name: intern(name), kind: PlaceholderKind::Vector { nonzero, priority } } + OwnedPh { name: intern(name), kind: PlaceholderKind::Vector { nonzero, priority } } }, None => match konst::string::strip_prefix(s, "$_") { - Some(name) => GenPh { name: intern(name), kind: PlaceholderKind::Name }, + Some(name) => OwnedPh { name: intern(name), kind: PlaceholderKind::Name }, None => match konst::string::strip_prefix(s, "$") { None => panic!("Invalid placeholder"), - Some(name) => GenPh { name: intern(name), kind: PlaceholderKind::Scalar }, + Some(name) => OwnedPh { name: intern(name), kind: PlaceholderKind::Scalar }, }, }, } } #[derive(Clone)] -pub enum GenTok { - Lambda(Vec, Vec), +pub enum OwnedTok { + Lambda(Vec, Vec), Name(VName), - S(Paren, Vec), + S(Paren, Vec), Atom(AtomFactory), Slot(TreeTicket), - Ph(GenPh), + Ph(OwnedPh), + Bottom(ProjectErrorObj), } -impl GenTok { - pub fn at(self, range: Range) -> GenTokTree { GenTokTree { tok: self, range } } +impl OwnedTok { + pub fn at(self, range: Range) -> OwnedTokTree { OwnedTokTree { tok: self, range } } pub fn into_api(self, sys: &dyn DynSystem) -> Token { match self { Self::Lambda(x, body) => Token::Lambda( @@ -79,32 +76,33 @@ impl GenTok { body.into_iter().map(|tt| tt.into_api(sys)).collect_vec(), ), Self::Name(n) => Token::Name(n.into_iter().map(|t| t.marker()).collect_vec()), - Self::Ph(GenPh { name, kind }) => Token::Ph(Placeholder { name: name.marker(), kind }), + Self::Ph(ph) => Token::Ph(ph.to_api()), Self::S(p, body) => Token::S(p, body.into_iter().map(|tt| tt.into_api(sys)).collect_vec()), Self::Slot(tk) => Token::Slot(tk), Self::Atom(at) => Token::Atom(at.build(sys)), + Self::Bottom(err) => Token::Bottom(err_or_ref_to_api(err)), } } } #[derive(Clone)] pub struct GenMacro { - pub pattern: Vec, + pub pattern: Vec, pub priority: NotNan, - pub template: Vec, + pub template: Vec, } pub fn tokv_into_api( - tokv: impl IntoIterator, + tokv: impl IntoIterator, sys: &dyn DynSystem, ) -> Vec { tokv.into_iter().map(|tok| tok.into_api(sys)).collect_vec() } -pub fn wrap_tokv(items: Vec, range: Range) -> GenTokTree { +pub fn wrap_tokv(items: Vec, range: Range) -> OwnedTokTree { match items.len() { 1 => items.into_iter().next().unwrap(), - _ => GenTok::S(Paren::Round, items).at(range), + _ => OwnedTok::S(Paren::Round, items).at(range), } } @@ -120,8 +118,8 @@ impl GenTree { } pub fn rule( prio: f64, - pat: impl IntoIterator, - tpl: impl IntoIterator, + pat: impl IntoIterator, + tpl: impl IntoIterator, ) -> Self { GenItem::Rule(GenMacro { pattern: pat.into_iter().collect(), diff --git a/orchid-host/src/extension.rs b/orchid-host/src/extension.rs index ccd68a4..3b29baa 100644 --- a/orchid-host/src/extension.rs +++ b/orchid-host/src/extension.rs @@ -1,4 +1,5 @@ use std::io::Write as _; +use std::ops::Deref; use std::sync::atomic::{AtomicU16, AtomicU32, Ordering}; use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::{Arc, Mutex, RwLock, Weak}; @@ -12,16 +13,16 @@ use orchid_api::atom::{Atom, AtomDrop, AtomSame, CallRef, FinalCall, Fwd, Fwded} use orchid_api::error::{ErrNotif, ProjErrOrRef, ProjResult, ReportError}; use orchid_api::expr::{Acquire, Expr, ExprNotif, ExprTicket, Release, Relocate}; use orchid_api::interner::IntReq; -use orchid_api::parser::CharFilter; +use orchid_api::parser::{CharFilter, Lexed, SubLexed}; use orchid_api::proto::{ - ExtHostNotif, ExtHostReq, ExtensionHeader, HostExtNotif, HostExtReq, HostHeader, HostMsgSet + ExtHostNotif, ExtHostReq, ExtensionHeader, HostExtNotif, HostHeader, HostMsgSet, }; use orchid_api::system::{NewSystem, SysDeclId, SysId, SystemDecl, SystemDrop}; use orchid_api::tree::{GetConstTree, Tree, TreeId}; -use orchid_api_traits::{Coding, Decode, Encode, Request}; +use orchid_api_traits::{Coding, Decode, Encode}; use orchid_base::char_filter::char_filter_match; use orchid_base::clone; -use orchid_base::interner::{deintern, intern}; +use orchid_base::interner::{deintern, intern, Tok}; use orchid_base::reqnot::{ReqNot, Requester as _}; use ordered_float::NotNan; @@ -230,24 +231,28 @@ impl System { pub fn const_tree(&self) -> Tree { self.0.ext.0.reqnot.request(GetConstTree(self.0.id, self.0.const_root_id)) } - pub fn request(&self, req: impl Request> + Into) -> ProjResult { + pub fn catch_err(&self, cb: impl FnOnce() -> ProjResult) -> ProjResult { let mut errors = Vec::new(); if let Ok(err) = self.0.err_rec.lock().unwrap().try_recv() { eprintln!("Errors left in queue"); errors.push(err); } - let value = self.0.ext.0.reqnot.request(req).inspect_err(|e| errors.extend(e.iter().cloned())); + let value = cb().inspect_err(|e| errors.extend(e.iter().cloned())); while let Ok(err) = self.0.err_rec.lock().unwrap().try_recv() { errors.push(err); } - if !errors.is_empty() { - Err(errors) - } else { - value - } + if !errors.is_empty() { Err(errors) } else { value } } pub fn has_lexer(&self) -> bool { !self.0.lex_filter.0.is_empty() } pub fn can_lex(&self, c: char) -> bool { char_filter_match(&self.0.lex_filter, c) } + pub fn lex( + &self, + source: Tok, + pos: usize, + r: impl FnMut(usize) -> ProjResult, + ) -> ProjResult { + todo!() + } } impl fmt::Debug for System { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -263,3 +268,7 @@ impl fmt::Debug for System { } } } +impl Deref for System { + type Target = SystemInstData; + fn deref(&self) -> &Self::Target { self.0.as_ref() } +} diff --git a/orchid-host/src/lex.rs b/orchid-host/src/lex.rs new file mode 100644 index 0000000..8956138 --- /dev/null +++ b/orchid-host/src/lex.rs @@ -0,0 +1,118 @@ +use orchid_api::tree::Paren; +use orchid_base::intern; +use orchid_base::interner::Tok; +use orchid_base::location::Pos; +use orchid_base::number::parse_num; + +use crate::extension::System; +use crate::results::{mk_err, num_to_err, OwnedResult}; +use crate::tree::{OwnedTok, OwnedTokTree}; + +pub struct LexCtx<'a> { + pub systems: &'a [System], + pub source: Tok, + pub src: &'a str, +} +impl<'a> LexCtx<'a> { + pub fn get_pos(&self) -> u32 { self.source.len() as u32 - self.src.len() as u32 } + pub fn strip_prefix(&mut self, tgt: &str) -> bool { + if let Some(src) = self.src.strip_prefix(tgt) { + self.src = src; + return true; + } + false + } + pub fn strip_char(&mut self, tgt: char) -> bool { + if let Some(src) = self.src.strip_prefix(tgt) { + self.src = src; + return true; + } + false + } + pub fn trim(&mut self, filter: impl Fn(char) -> bool) { + self.src = self.src.trim_start_matches(filter); + } + pub fn trim_ws(&mut self, br: bool) { + self.trim(|c| c.is_whitespace() && br || !"\r\n".contains(c)) + } + pub fn get_start_matches(&mut self, filter: impl Fn(char) -> bool) -> &'a str { + let rest = self.src.trim_start_matches(filter); + let matches = &self.src[..self.src.len() - rest.len()]; + self.src = rest; + matches + } +} + +const PARENS: &[(char, char, Paren)] = + &[('(', ')', Paren::Round), ('[', ']', Paren::Square), ('{', '}', Paren::Curly)]; + +pub fn lex_tok(ctx: &mut LexCtx, br: bool) -> OwnedResult { + assert!( + !ctx.src.is_empty() && !ctx.src.starts_with(char::is_whitespace), + "Lexing empty string or whitespace to token! Invocations of lex_tok should check for empty string" + ); + for (open, close, paren) in PARENS { + let paren_pos = ctx.get_pos(); + if ctx.strip_char(*open) { + let mut body = Vec::new(); + return loop { + ctx.trim_ws(true); + if ctx.strip_char(*close) { + break Ok(OwnedTokTree { + tok: OwnedTok::S(paren.clone(), body), + range: paren_pos..ctx.get_pos(), + }); + } else if ctx.src.is_empty() { + return Err(vec![mk_err( + intern!(str: "unclosed paren"), + format!("this {open} has no matching {close}"), + [Pos::Range(paren_pos..paren_pos + 1).into()], + )]); + } + body.push(lex_tok(ctx, true)?); + }; + } + } + if ctx.strip_char('\\') { + let bs_pos = ctx.get_pos() - 1; + let mut arg = Vec::new(); + loop { + ctx.trim_ws(true); + if ctx.strip_char('.') { + break; + } else if ctx.src.is_empty() { + return Err(vec![mk_err( + intern!(str: "Unclosed lambda"), + "Lambdae started with \\ should separate arguments from body with .", + [Pos::Range(bs_pos..bs_pos + 1).into()], + )]); + } + arg.push(lex_tok(ctx, true)?); + } + let mut body = Vec::new(); + return loop { + ctx.trim_ws(br); + let pos_before_end = ctx.get_pos(); + if !br && ctx.strip_char('\n') + || PARENS.iter().any(|(_, e, _)| ctx.strip_char(*e)) + || ctx.src.is_empty() + { + break Ok(OwnedTokTree { tok: OwnedTok::Lambda(arg, body), range: bs_pos..pos_before_end }); + } + body.push(lex_tok(ctx, br)?); + }; + } + if ctx.src.starts_with(char::is_numeric) { + let num_pos = ctx.get_pos(); + let num_str = ctx.get_start_matches(|c| c.is_alphanumeric() || "._".contains(c)); + return Ok(OwnedTokTree { + range: num_pos..ctx.get_pos(), + tok: match parse_num(num_str) { + Err(e) => OwnedTok::Bottom(num_to_err(e, num_pos)), + Ok(v) => todo!(), + }, + }); + } + for sys in ctx.systems {} + todo!() +} diff --git a/orchid-host/src/lib.rs b/orchid-host/src/lib.rs index a706912..2bdefb5 100644 --- a/orchid-host/src/lib.rs +++ b/orchid-host/src/lib.rs @@ -1,3 +1,6 @@ pub mod child; pub mod expr; pub mod extension; +pub mod lex; +pub mod results; +pub mod tree; diff --git a/orchid-host/src/results.rs b/orchid-host/src/results.rs new file mode 100644 index 0000000..9cf1b16 --- /dev/null +++ b/orchid-host/src/results.rs @@ -0,0 +1,36 @@ +use std::sync::Arc; + +use orchid_base::error::{ErrorPosition, OwnedError}; +use orchid_base::intern; +use orchid_base::interner::Tok; +use orchid_base::location::Pos; +use orchid_base::number::{NumError, NumErrorKind}; + +pub type OwnedResult = Result>; + +pub fn mk_err( + description: Tok, + message: impl AsRef, + posv: impl IntoIterator, +) -> OwnedError { + OwnedError { + description, + message: Arc::new(message.as_ref().to_string()), + positions: posv.into_iter().collect(), + } +} + +pub fn num_to_err(NumError { kind, range }: NumError, offset: u32) -> OwnedError { + OwnedError { + description: intern!(str: "Failed to parse number"), + message: Arc::new( + match kind { + NumErrorKind::NaN => "NaN emerged during parsing", + NumErrorKind::InvalidDigit => "non-digit character encountered", + NumErrorKind::Overflow => "The number being described is too large or too accurate", + } + .to_string(), + ), + positions: vec![Pos::Range(offset + range.start as u32..offset + range.end as u32).into()], + } +} diff --git a/orchid-host/src/tree.rs b/orchid-host/src/tree.rs new file mode 100644 index 0000000..373971d --- /dev/null +++ b/orchid-host/src/tree.rs @@ -0,0 +1,24 @@ +use std::ops::Range; + +use orchid_api::tree::Paren; +use orchid_base::error::OwnedError; +use orchid_base::name::VName; +use orchid_base::tokens::OwnedPh; + +use crate::extension::AtomHand; + +#[derive(Clone)] +pub struct OwnedTokTree { + pub tok: OwnedTok, + pub range: Range, +} + +#[derive(Clone)] +pub enum OwnedTok { + Lambda(Vec, Vec), + Name(VName), + S(Paren, Vec), + Atom(AtomHand), + Ph(OwnedPh), + Bottom(OwnedError), +} diff --git a/orchid-std/src/std.rs b/orchid-std/src/std.rs index 4ac65b1..c9ea65a 100644 --- a/orchid-std/src/std.rs +++ b/orchid-std/src/std.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use orchid_extension::atom::AtomicFeatures; +use orchid_extension::atom::{AtomDynfo, AtomicFeatures}; use orchid_extension::fs::DeclFs; use orchid_extension::fun::Fun; use orchid_extension::system::{System, SystemCard}; @@ -22,16 +22,25 @@ impl SystemCtor for StdSystem { } impl SystemCard for StdSystem { type Ctor = Self; - const ATOM_DEFS: &'static [Option &'static orchid_extension::atom::AtomInfo>] = &[ - Some(StringAtom::info) - ]; + const ATOM_DEFS: &'static [Option<&'static dyn AtomDynfo>] = &[Some(StringAtom::INFO)]; } impl System for StdSystem { fn lexers() -> Vec { vec![&StringLexer] } fn vfs() -> DeclFs { DeclFs::Mod(&[]) } fn env() -> GenTree { - GenTree::module([("std", GenTree::module([("string", GenTree::module([ - ("concat", GenTree::cnst(Fun::new(|left: OrcString| Fun::new(move |right: OrcString| StringAtom::new(Arc::new(left.get_string().to_string() + &right.get_string())))))) - ]))]))]) + GenTree::module([( + "std", + GenTree::module([( + "string", + GenTree::module([( + "concat", + GenTree::cnst(Fun::new(|left: OrcString| { + Fun::new(move |right: OrcString| { + StringAtom::new(Arc::new(left.get_string().to_string() + &right.get_string())) + }) + })), + )]), + )]), + )]) } } diff --git a/orchid-std/src/string/str_atom.rs b/orchid-std/src/string/str_atom.rs index 26d17ac..059a4a8 100644 --- a/orchid-std/src/string/str_atom.rs +++ b/orchid-std/src/string/str_atom.rs @@ -10,10 +10,10 @@ use orchid_base::interner::{deintern, Tok}; use orchid_base::location::Pos; use orchid_extension::atom::{Atomic, TypAtom}; use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant}; +use orchid_extension::conv::TryFromExpr; use orchid_extension::error::{ProjectError, ProjectResult}; use orchid_extension::expr::{ExprHandle, OwnedExpr}; use orchid_extension::system::{downcast_atom, SysCtx}; -use orchid_extension::conv::TryFromExpr; pub static STR_REPO: IdStore> = IdStore::new(); @@ -59,10 +59,12 @@ impl StringAtom { fn get_value(&self) -> Arc { self.try_local_value().expect("no string found for ID") } } impl OwnedAtom for StringAtom { - fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(match self { - Self::Int(tok) => StringVal::Int(tok.marker()), - Self::Val(id) => StringVal::Val(*id), - }) } + fn val(&self) -> Cow<'_, Self::Data> { + Cow::Owned(match self { + Self::Int(tok) => StringVal::Int(tok.marker()), + Self::Val(id) => StringVal::Val(*id), + }) + } fn same(&self, _ctx: SysCtx, other: &Self) -> bool { self.get_value() == other.get_value() } fn handle_req( &self, @@ -90,9 +92,7 @@ impl OrcString { pub struct NotString(Pos); impl ProjectError for NotString { const DESCRIPTION: &'static str = "A string was expected"; - fn one_position(&self) -> Pos { - self.0.clone() - } + fn one_position(&self) -> Pos { self.0.clone() } } impl TryFromExpr for OrcString { fn try_from_expr(expr: ExprHandle) -> ProjectResult { @@ -101,4 +101,4 @@ impl TryFromExpr for OrcString { .map_err(|p| NotString(p).pack()) .map(OrcString) } -} \ No newline at end of file +} diff --git a/orchid-std/src/string/str_leer.rs b/orchid-std/src/string/str_leer.rs index b6e7e8f..58d4b3e 100644 --- a/orchid-std/src/string/str_leer.rs +++ b/orchid-std/src/string/str_leer.rs @@ -6,7 +6,7 @@ use orchid_base::vname; use orchid_extension::atom::AtomicFeatures; use orchid_extension::error::{ErrorSansOrigin, ProjectErrorObj, ProjectResult}; use orchid_extension::lexer::{LexContext, Lexer}; -use orchid_extension::tree::{wrap_tokv, GenTok, GenTokTree}; +use orchid_extension::tree::{wrap_tokv, OwnedTok, OwnedTokTree}; use super::str_atom::StringAtom; @@ -119,15 +119,15 @@ impl Lexer for StringLexer { fn lex<'a>( full_string: &'a str, ctx: &'a LexContext<'a>, - ) -> Option> { + ) -> Option> { full_string.strip_prefix('"').map(|mut tail| { let mut parts = vec![]; let mut cur = String::new(); - let commit_str = |str: &mut String, tail: &str, parts: &mut Vec| { + let commit_str = |str: &mut String, tail: &str, parts: &mut Vec| { let str_val = parse_string(str) .inspect_err(|e| ctx.report(e.clone().into_proj(ctx.pos(tail) - str.len() as u32))) .unwrap_or_default(); - let tok = GenTok::Atom(StringAtom::new_int(intern(&str_val)).factory()); + let tok = OwnedTok::Atom(StringAtom::new_int(intern(&str_val)).factory()); parts.push(tok.at(ctx.tok_ran(str.len() as u32, tail))); *str = String::new(); }; @@ -137,8 +137,8 @@ impl Lexer for StringLexer { return Ok((rest, wrap_tokv(parts, ctx.pos(full_string)..ctx.pos(rest)))); } else if let Some(rest) = tail.strip_prefix('$') { commit_str(&mut cur, tail, &mut parts); - parts.push(GenTok::Name(VName::literal("++")).at(ctx.tok_ran(1, rest))); - parts.push(GenTok::Name(vname!(std::string::convert)).at(ctx.tok_ran(1, rest))); + parts.push(OwnedTok::Name(VName::literal("++")).at(ctx.tok_ran(1, rest))); + parts.push(OwnedTok::Name(vname!(std::string::convert)).at(ctx.tok_ran(1, rest))); match ctx.recurse(rest) { Ok((new_tail, tree)) => { tail = new_tail; diff --git a/orchidlang/src/parse/numeric.rs b/orchidlang/src/parse/numeric.rs index 8769212..2627425 100644 --- a/orchidlang/src/parse/numeric.rs +++ b/orchidlang/src/parse/numeric.rs @@ -17,35 +17,6 @@ use crate::foreign::atom::AtomGenerator; use crate::foreign::inert::Inert; use crate::libs::std::number::Numeric; -/// Rasons why [parse_num] might fail. See [NumError]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum NumErrorKind { - /// The literal describes [f64::NAN] - NaN, - /// Some integer appearing in the literal overflows [usize] - Overflow, - /// A character that isn't a digit in the given base was found - InvalidDigit, -} -impl NumErrorKind { - fn from_int(kind: &IntErrorKind) -> Self { - match kind { - IntErrorKind::InvalidDigit => Self::InvalidDigit, - IntErrorKind::NegOverflow | IntErrorKind::PosOverflow => Self::Overflow, - _ => panic!("Impossible error condition"), - } - } -} - -/// Error produced by [parse_num] -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct NumError { - /// Location - pub range: Range, - /// Reason - pub kind: NumErrorKind, -} - impl NumError { /// Convert into [ProjectErrorObj] pub fn into_proj( @@ -64,73 +35,7 @@ impl NumError { } } -/// Parse a numbre literal out of text -pub fn parse_num(string: &str) -> Result { - let overflow_err = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow }; - let (radix, noprefix, pos) = (string.strip_prefix("0x").map(|s| (16u8, s, 2))) - .or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2))) - .or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2))) - .unwrap_or((10u8, string, 0)); - // identity - let (base, exponent) = match noprefix.split_once('p') { - Some((b, e)) => { - let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1)); - (b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32) - }, - None => (noprefix, 0), - }; - match base.split_once('.') { - None => { - let base_usize = int_parse(base, radix, pos)?; - if let Ok(pos_exp) = u32::try_from(exponent) { - if let Some(radical) = usize::from(radix).checked_pow(pos_exp) { - let number = base_usize.checked_mul(radical).ok_or(overflow_err)?; - return Ok(Numeric::Uint(number)); - } - } - let f = (base_usize as f64) * (radix as f64).powi(exponent); - let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN }; - Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?)) - }, - Some((whole, part)) => { - let whole_n = int_parse(whole, radix, pos)? as f64; - let part_n = int_parse(part, radix, pos + whole.len() + 1)? as f64; - let real_val = whole_n + (part_n / (radix as f64).powi(part.len() as i32)); - let f = real_val * (radix as f64).powi(exponent); - Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN"))) - }, - } -} -fn int_parse(s: &str, radix: u8, start: usize) -> Result { - let s = s.chars().filter(|c| *c != '_').collect::(); - let range = start..(start + s.len()); - usize::from_str_radix(&s, radix as u32) - .map_err(|e| NumError { range, kind: NumErrorKind::from_int(e.kind()) }) -} - -/// Filter for characters that can appear in numbers -pub fn numchar(c: char) -> bool { c.is_alphanumeric() | "._-".contains(c) } -/// Filter for characters that can start numbers -pub fn numstart(c: char) -> bool { c.is_ascii_digit() } - -/// Print a number as a base-16 floating point literal -#[must_use] -pub fn print_nat16(num: NotNan) -> String { - if *num == 0.0 { - return "0x0".to_string(); - } else if num.is_infinite() { - return match num.is_sign_positive() { - true => "Infinity".to_string(), - false => "-Infinity".to_string(), - }; - } else if num.is_nan() { - return "NaN".to_string(); - } - let exp = num.log(16.0).floor(); - let man = *num / 16_f64.powf(exp); - format!("0x{man}p{exp:.0}") -} /// [LexerPlugin] for a number literal #[derive(Clone)] @@ -150,30 +55,3 @@ impl LexerPlugin for NumericLexer { }) } } - -#[cfg(test)] -mod test { - use crate::libs::std::number::Numeric; - use crate::parse::numeric::parse_num; - - #[test] - fn just_ints() { - let test = |s, n| assert_eq!(parse_num(s), Ok(Numeric::Uint(n))); - test("12345", 12345); - test("0xcafebabe", 0xcafebabe); - test("0o751", 0o751); - test("0b111000111", 0b111000111); - } - - #[test] - fn decimals() { - let test = |s, n| assert_eq!(parse_num(s).map(|n| n.as_f64()), Ok(n)); - test("3.1417", 3.1417); - test("3.1417", 3_f64 + 1417_f64 / 10000_f64); - test("0xf.cafe", 0xf as f64 + 0xcafe as f64 / 0x10000 as f64); - test("34p3", 34000f64); - test("0x2p3", (0x2 * 0x1000) as f64); - test("1.5p3", 1500f64); - test("0x2.5p3", (0x25 * 0x100) as f64); - } -}