This commit is contained in:
2024-07-18 16:07:36 +02:00
parent 949b3758fd
commit cc3699bbe7
31 changed files with 1021 additions and 312 deletions

419
Cargo.lock generated
View File

@@ -2,6 +2,17 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 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]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.11" version = "0.8.11"
@@ -21,12 +32,30 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 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]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@@ -36,12 +65,70 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]] [[package]]
name = "const_panic" name = "const_panic"
version = "0.2.8" version = "0.2.8"
@@ -154,12 +241,24 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.7" version = "0.14.7"
@@ -181,13 +280,22 @@ dependencies = [
"wasi", "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]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.5" version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [ dependencies = [
"ahash", "ahash 0.8.11",
"allocator-api2", "allocator-api2",
] ]
@@ -197,6 +305,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 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]] [[package]]
name = "itertools" name = "itertools"
version = "0.13.0" version = "0.13.0"
@@ -206,6 +324,12 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]] [[package]]
name = "konst" name = "konst"
version = "0.3.9" version = "0.3.9"
@@ -245,6 +369,12 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "never" name = "never"
version = "0.1.0" version = "0.1.0"
@@ -302,7 +432,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"derive_destructure", "derive_destructure",
"dyn-clone", "dyn-clone",
"hashbrown", "hashbrown 0.14.5",
"itertools", "itertools",
"lazy_static", "lazy_static",
"never", "never",
@@ -311,6 +441,7 @@ dependencies = [
"orchid-api-traits", "orchid-api-traits",
"ordered-float", "ordered-float",
"rust-embed", "rust-embed",
"rust_decimal",
"substack", "substack",
"trait-set", "trait-set",
] ]
@@ -319,10 +450,10 @@ dependencies = [
name = "orchid-extension" name = "orchid-extension"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ahash", "ahash 0.8.11",
"derive_destructure", "derive_destructure",
"dyn-clone", "dyn-clone",
"hashbrown", "hashbrown 0.14.5",
"itertools", "itertools",
"konst", "konst",
"never", "never",
@@ -335,7 +466,6 @@ dependencies = [
"paste", "paste",
"substack", "substack",
"trait-set", "trait-set",
"typeid",
] ]
[[package]] [[package]]
@@ -343,7 +473,7 @@ name = "orchid-host"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"derive_destructure", "derive_destructure",
"hashbrown", "hashbrown 0.14.5",
"itertools", "itertools",
"lazy_static", "lazy_static",
"orchid-api", "orchid-api",
@@ -384,6 +514,44 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "0.4.30" version = "0.4.30"
@@ -402,6 +570,26 @@ dependencies = [
"unicode-ident", "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]] [[package]]
name = "quote" name = "quote"
version = "0.6.13" version = "0.6.13"
@@ -420,6 +608,80 @@ dependencies = [
"proc-macro2 1.0.78", "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]] [[package]]
name = "rust-embed" name = "rust-embed"
version = "8.3.0" version = "8.3.0"
@@ -454,6 +716,22 @@ dependencies = [
"walkdir", "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]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.4.0" version = "0.4.0"
@@ -463,6 +741,12 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.6" version = "1.0.6"
@@ -472,12 +756,49 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.22" version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" 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]] [[package]]
name = "sha2" name = "sha2"
version = "0.10.8" version = "0.10.8"
@@ -489,6 +810,12 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "simdutf8"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
[[package]] [[package]]
name = "stdio-perftest" name = "stdio-perftest"
version = "0.1.0" version = "0.1.0"
@@ -538,6 +865,56 @@ dependencies = [
"unicode-ident", "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]] [[package]]
name = "trait-set" name = "trait-set"
version = "0.3.0" version = "0.3.0"
@@ -549,12 +926,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "typeid"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.17.0" version = "1.17.0"
@@ -588,6 +959,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "uuid"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@@ -641,6 +1018,24 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 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]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.32" version = "0.7.32"

10
notes/comm_arch.md Normal file
View File

@@ -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`)

View File

@@ -5,7 +5,5 @@ mod relations;
pub use coding::{Coding, Decode, Encode}; pub use coding::{Coding, Decode, Encode};
pub use helpers::{encode_enum, read_exact, write_exact}; pub use helpers::{encode_enum, read_exact, write_exact};
pub use hierarchy::{ pub use hierarchy::{Extends, InHierarchy, TLBool, TLFalse, TLTrue, UnderRoot};
Extends, InHierarchy, TLBool, TLFalse, TLTrue, UnderRoot,
};
pub use relations::{Channel, MsgSet, Request}; pub use relations::{Channel, MsgSet, Request};

View File

@@ -7,6 +7,7 @@ use orchid_api_traits::Request;
use ordered_float::NotNan; use ordered_float::NotNan;
use crate::atom::LocalAtom; use crate::atom::LocalAtom;
use crate::error::ProjErrOrRef;
use crate::expr::Expr; use crate::expr::Expr;
use crate::interner::TStr; use crate::interner::TStr;
use crate::proto::HostExtReq; use crate::proto::HostExtReq;
@@ -38,7 +39,7 @@ pub enum Token {
Slot(TreeTicket), Slot(TreeTicket),
/// A static compile-time error returned by erroring lexers if /// A static compile-time error returned by erroring lexers if
/// the rest of the source is likely still meaningful /// the rest of the source is likely still meaningful
Bottom(String), Bottom(ProjErrOrRef),
} }
#[derive(Clone, Debug, Coding)] #[derive(Clone, Debug, Coding)]

View File

@@ -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" } orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
ordered-float = "4.2.0" ordered-float = "4.2.0"
rust-embed = "8.3.0" rust-embed = "8.3.0"
rust_decimal = "1.35.0"
substack = "1.1.0" substack = "1.1.0"
trait-set = "0.3.0" trait-set = "0.3.0"

10
orchid-base/src/as_api.rs Normal file
View File

@@ -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) }
}

View File

@@ -27,22 +27,26 @@ impl ErrorPosition {
location: self.position.to_api(), location: self.position.to_api(),
} }
} }
pub fn new(msg: &str, position: Pos) -> Self {
Self { message: Some(Arc::new(msg.to_string())), position }
}
} }
impl From<Pos> for ErrorPosition { impl From<Pos> for ErrorPosition {
fn from(origin: Pos) -> Self { Self { position: origin, message: None } } fn from(origin: Pos) -> Self { Self { position: origin, message: None } }
} }
pub struct ErrorDetails { #[derive(Clone)]
pub struct OwnedError {
pub description: Tok<String>, pub description: Tok<String>,
pub message: Arc<String>, pub message: Arc<String>,
pub locations: Vec<ErrorPosition>, pub positions: Vec<ErrorPosition>,
} }
impl ErrorDetails { impl OwnedError {
pub fn from_api(err: &ProjErr) -> Self { pub fn from_api(err: &ProjErr) -> Self {
Self { Self {
description: deintern(err.description), description: deintern(err.description),
message: err.message.clone(), message: err.message.clone(),
locations: err.locations.iter().map(ErrorPosition::from_api).collect(), positions: err.locations.iter().map(ErrorPosition::from_api).collect(),
} }
} }
} }

View File

@@ -5,6 +5,7 @@ pub mod event;
pub mod msg; pub mod msg;
// pub mod gen; // pub mod gen;
pub mod api_utils; pub mod api_utils;
pub mod as_api;
pub mod box_cow; pub mod box_cow;
pub mod char_filter; pub mod char_filter;
pub mod error; pub mod error;
@@ -13,7 +14,8 @@ pub mod interner;
pub mod join; pub mod join;
pub mod location; pub mod location;
pub mod name; pub mod name;
pub mod number;
pub mod reqnot; pub mod reqnot;
pub mod sequence; pub mod sequence;
pub mod tokens;
pub mod tree; pub mod tree;
// pub mod virt_fs;

150
orchid-base/src/number.rs Normal file
View File

@@ -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<f64>),
/// 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<usize>,
/// Reason
pub kind: NumErrorKind,
}
/// Parse a numbre literal out of text
pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
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<u64, NumError> {
let s = s.chars().filter(|c| *c != '_').collect::<String>();
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<f64>) -> 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));
}
}

15
orchid-base/src/tokens.rs Normal file
View File

@@ -0,0 +1,15 @@
use orchid_api::tree::{Placeholder, PlaceholderKind};
use crate::interner::{deintern, Tok};
#[derive(Clone)]
pub struct OwnedPh {
pub name: Tok<String>,
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 } }
}

View File

@@ -22,4 +22,3 @@ ordered-float = "4.2.0"
paste = "1.0.15" paste = "1.0.15"
substack = "1.1.0" substack = "1.1.0"
trait-set = "0.3.0" trait-set = "0.3.0"
typeid = "1.0.0"

View File

@@ -1,4 +1,4 @@
use std::any::{type_name, Any}; use std::any::{type_name, Any, TypeId};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::ops::Deref; use std::ops::Deref;
@@ -9,7 +9,6 @@ use orchid_api_traits::{Coding, Decode, Request};
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_base::reqnot::Requester; use orchid_base::reqnot::Requester;
use trait_set::trait_set; use trait_set::trait_set;
use typeid::ConstTypeId;
use crate::error::ProjectError; use crate::error::ProjectError;
use crate::expr::{ExprHandle, GenExpr}; use crate::expr::{ExprHandle, GenExpr};
@@ -33,19 +32,22 @@ impl<A: Atomic> AtomCard for A {
pub trait AtomicFeatures: Atomic { pub trait AtomicFeatures: Atomic {
fn factory(self) -> AtomFactory; fn factory(self) -> AtomFactory;
fn info() -> &'static AtomInfo; type Info: AtomDynfo;
const INFO: &'static Self::Info;
} }
pub trait AtomicFeaturesImpl<Variant: AtomicVariant> { pub trait AtomicFeaturesImpl<Variant: AtomicVariant> {
fn _factory(self) -> AtomFactory; fn _factory(self) -> AtomFactory;
fn _info() -> &'static AtomInfo; type _Info: AtomDynfo;
const _INFO: &'static Self::_Info;
} }
impl<A: Atomic + AtomicFeaturesImpl<A::Variant>> AtomicFeatures for A { impl<A: Atomic + AtomicFeaturesImpl<A::Variant>> AtomicFeatures for A {
fn factory(self) -> AtomFactory { self._factory() } fn factory(self) -> AtomFactory { self._factory() }
fn info() -> &'static AtomInfo { Self::_info() } type Info = <Self as AtomicFeaturesImpl<A::Variant>>::_Info;
const INFO: &'static Self::Info = Self::_INFO;
} }
pub fn get_info<A: AtomCard>(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &AtomInfo) { pub fn get_info<A: AtomCard>(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &'static dyn AtomDynfo) {
atom_info_for(sys, ConstTypeId::of::<A>()).unwrap_or_else(|| { atom_info_for(sys, TypeId::of::<A>()).unwrap_or_else(|| {
panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name()) panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name())
}) })
} }
@@ -75,14 +77,14 @@ impl<A: AtomCard> Deref for TypAtom<A> {
fn deref(&self) -> &Self::Target { &self.value } fn deref(&self) -> &Self::Target { &self.value }
} }
pub struct AtomInfo { pub trait AtomDynfo: Send + Sync + 'static {
pub tid: ConstTypeId, fn tid(&self) -> TypeId;
pub decode: fn(&[u8]) -> Box<dyn Any>, fn decode(&self, data: &[u8]) -> Box<dyn Any>;
pub call: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, fn call(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr;
pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, fn call_ref(&self, buf: &[u8], ctx: SysCtx, arg: ExprTicket) -> GenExpr;
pub same: fn(&[u8], SysCtx, &[u8]) -> bool, fn same(&self, buf: &[u8], ctx: SysCtx, buf2: &[u8]) -> bool;
pub handle_req: fn(&[u8], SysCtx, &mut dyn Read, &mut dyn Write), fn handle_req(&self, buf: &[u8], ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write);
pub drop: fn(&[u8], SysCtx), fn drop(&self, buf: &[u8], ctx: SysCtx);
} }
trait_set! { trait_set! {

View File

@@ -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_api_traits::{Decode, Encode};
use orchid_base::id_store::{IdRecord, IdStore}; 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; pub struct OwnedVariant;
impl AtomicVariant for OwnedVariant {} impl AtomicVariant for OwnedVariant {}
@@ -19,26 +27,37 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
LocalAtom { drop: true, data } LocalAtom { drop: true, data }
}) })
} }
fn _info() -> &'static AtomInfo { type _Info = OwnedAtomDynfo<A>;
const _INFO: &'static Self::_Info = &OwnedAtomDynfo(PhantomData);
}
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U { fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID")) f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID"))
} }
&const {
AtomInfo { pub struct OwnedAtomDynfo<T: OwnedAtom>(PhantomData<T>);
tid: ConstTypeId::of::<Self>(), impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
decode: |mut b| Box::new(<Self as Atomic>::Data::decode(&mut b)), fn tid(&self) -> TypeId { TypeId::of::<T>() }
call: |b, ctx, arg| with_atom(b, |a| a.remove().dyn_call(ctx, arg)), fn decode(&self, data: &[u8]) -> Box<dyn Any> {
call_ref: |b, ctx, arg| with_atom(b, |a| a.dyn_call_ref(ctx, arg)), Box::new(<T as AtomCard>::Data::decode(&mut &data[..]))
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)),
} }
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] /// Atoms that have a [Drop]
pub trait OwnedAtom: AtomCard + Send + Sync + Any + Clone + 'static { pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone + 'static {
fn val(&self) -> Cow<'_, Self::Data>; fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)] #[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) } 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) {} fn free(self, ctx: SysCtx) {}
} }
pub trait DynOwnedAtom: Send + Sync + 'static { pub trait DynOwnedAtom: Send + Sync + 'static {
fn atom_tid(&self) -> ConstTypeId; fn atom_tid(&self) -> TypeId;
fn as_any_ref(&self) -> &dyn Any; fn as_any_ref(&self) -> &dyn Any;
fn encode(&self, buffer: &mut dyn Write); fn encode(&self, buffer: &mut dyn Write);
fn dyn_call_ref(&self, ctx: SysCtx, arg: ExprTicket) -> GenExpr; 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<Self>, ctx: SysCtx); fn dyn_free(self: Box<Self>, ctx: SysCtx);
} }
impl<T: OwnedAtom> DynOwnedAtom for T { impl<T: OwnedAtom> DynOwnedAtom for T {
fn atom_tid(&self) -> ConstTypeId { ConstTypeId::of::<T>() } fn atom_tid(&self) -> TypeId { TypeId::of::<T>() }
fn as_any_ref(&self) -> &dyn Any { self } fn as_any_ref(&self) -> &dyn Any { self }
fn encode(&self, buffer: &mut dyn Write) { self.val().as_ref().encode(buffer) } fn encode(&self, buffer: &mut dyn Write) { self.val().as_ref().encode(buffer) }
fn dyn_call_ref(&self, ctx: SysCtx, arg: ExprTicket) -> GenExpr { fn dyn_call_ref(&self, ctx: SysCtx, arg: ExprTicket) -> GenExpr {
@@ -81,7 +100,7 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
self.call(ExprHandle::from_args(ctx, arg)) self.call(ExprHandle::from_args(ctx, arg))
} }
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool { fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
if ConstTypeId::of::<Self>() != other.as_any_ref().type_id() { if TypeId::of::<Self>() != other.as_any_ref().type_id() {
return false; return false;
} }
let other_self = other.as_any_ref().downcast_ref().expect("The type_ids are the same"); let other_self = other.as_any_ref().downcast_ref().expect("The type_ids are the same");

View File

@@ -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::atom::LocalAtom;
use orchid_api::expr::ExprTicket;
use orchid_api_traits::{Coding, Decode, Encode}; 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; pub struct ThinVariant;
impl AtomicVariant for ThinVariant {} impl AtomicVariant for ThinVariant {}
@@ -16,22 +24,32 @@ impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant
LocalAtom { drop: false, data: buf } LocalAtom { drop: false, data: buf }
}) })
} }
fn _info() -> &'static AtomInfo { type _Info = ThinAtomDynfo<Self>;
&const { const _INFO: &'static Self::_Info = &ThinAtomDynfo(PhantomData);
AtomInfo {
tid: ConstTypeId::of::<Self>(),
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)),
} }
pub struct ThinAtomDynfo<T: ThinAtom>(PhantomData<T>);
impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
fn tid(&self) -> TypeId { TypeId::of::<T>() }
fn decode(&self, mut data: &[u8]) -> Box<dyn Any> { 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<Data = Self> + Coding + fmt::Debug { pub trait ThinAtom: AtomCard<Data = Self> + Coding + fmt::Debug + Send + Sync + 'static {
#[allow(unused_variables)] #[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) } fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) }
#[allow(unused_variables)] #[allow(unused_variables)]

View File

@@ -1,6 +1,9 @@
use orchid_base::location::Pos; 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 { pub trait TryFromExpr: Sized {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self>; fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self>;
@@ -25,14 +28,14 @@ impl ProjectError for ErrorNotAtom {
pub struct ErrorUnexpectedType(Pos); pub struct ErrorUnexpectedType(Pos);
impl ProjectError for ErrorUnexpectedType { impl ProjectError for ErrorUnexpectedType {
const DESCRIPTION: &'static str = "Type error"; const DESCRIPTION: &'static str = "Type error";
fn one_position(&self) -> Pos { fn one_position(&self) -> Pos { self.0.clone() }
self.0.clone()
}
} }
impl<A: AtomicFeatures> TryFromExpr for TypAtom<A> { impl<A: AtomicFeatures> TryFromExpr for TypAtom<A> {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> { fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
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())) .and_then(|f| downcast_atom(f).map_err(|f| ErrorUnexpectedType(f.pos).pack()))
} }
} }

View File

@@ -19,7 +19,7 @@ use orchid_base::interner::{deintern, init_replica, sweep_replica};
use orchid_base::name::PathSlice; use orchid_base::name::PathSlice;
use orchid_base::reqnot::{ReqNot, Requester}; 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::error::{err_or_ref_to_api, unpack_err};
use crate::fs::VirtFS; use crate::fs::VirtFS;
use crate::lexer::LexContext; use crate::lexer::LexContext;
@@ -48,7 +48,7 @@ pub struct SystemRecord {
pub fn with_atom_record<T>( pub fn with_atom_record<T>(
systems: &Mutex<HashMap<SysId, SystemRecord>>, systems: &Mutex<HashMap<SysId, SystemRecord>>,
atom: &Atom, atom: &Atom,
cb: impl FnOnce(&AtomInfo, CtedObj, &[u8]) -> T, cb: impl FnOnce(&'static dyn AtomDynfo, CtedObj, &[u8]) -> T,
) -> T { ) -> T {
let mut data = &atom.data[..]; let mut data = &atom.data[..];
let systems_g = systems.lock().unwrap(); let systems_g = systems.lock().unwrap();
@@ -77,7 +77,7 @@ pub fn extension_main(data: ExtensionData) {
mem::drop(systems.lock().unwrap().remove(&sys_id)), mem::drop(systems.lock().unwrap().remove(&sys_id)),
HostExtNotif::AtomDrop(AtomDrop(atom)) => { HostExtNotif::AtomDrop(AtomDrop(atom)) => {
with_atom_record(&systems, &atom, |rec, cted, data| { 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 })
}) })
} }
}), }),

View File

@@ -10,7 +10,7 @@ use orchid_api::error::{GetErrorDetails, ProjErr, ProjErrId, ProjErrOrRef};
use orchid_api::proto::ExtMsgSet; use orchid_api::proto::ExtMsgSet;
use orchid_base::boxed_iter::{box_once, BoxedIter}; use orchid_base::boxed_iter::{box_once, BoxedIter};
use orchid_base::clone; 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::interner::{deintern, intern};
use orchid_base::location::{GetSrc, Pos}; use orchid_base::location::{GetSrc, Pos};
use orchid_base::reqnot::{ReqNot, Requester}; 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<ExtMsgSet>) -> ProjectErrorObj { pub fn err_from_api(err: &ProjErr, reqnot: ReqNot<ExtMsgSet>) -> 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<ExtMsgSet>) -> ProjectErrorObj { pub(crate) fn err_from_api_or_ref(
err: &ProjErrOrRef,
reqnot: ReqNot<ExtMsgSet>,
) -> ProjectErrorObj {
match err { 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), ProjErrOrRef::New(err) => err_from_api(err, reqnot),
} }
} }
@@ -303,18 +307,18 @@ pub(crate) fn err_from_api_or_ref(err: &ProjErrOrRef, reqnot: ReqNot<ExtMsgSet>)
struct RelayedError { struct RelayedError {
pub id: Option<ProjErrId>, pub id: Option<ProjErrId>,
pub reqnot: ReqNot<ExtMsgSet>, pub reqnot: ReqNot<ExtMsgSet>,
pub details: OnceLock<ErrorDetails>, pub details: OnceLock<OwnedError>,
} }
impl RelayedError { impl RelayedError {
fn details(&self) -> &ErrorDetails { fn details(&self) -> &OwnedError {
let Self { id, reqnot, details: data } = self; let Self { id, reqnot, details: data } = self;
data.get_or_init(clone!(reqnot; move || { data.get_or_init(clone!(reqnot; move || {
let id = id.expect("Either data or ID must be initialized"); let id = id.expect("Either data or ID must be initialized");
let projerr = reqnot.request(GetErrorDetails(id)); let projerr = reqnot.request(GetErrorDetails(id));
ErrorDetails { OwnedError {
description: deintern(projerr.description), description: deintern(projerr.description),
message: projerr.message, 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 as_any_ref(&self) -> &dyn std::any::Any { self }
fn into_packed(self: Arc<Self>) -> ProjectErrorObj { self } fn into_packed(self: Arc<Self>) -> ProjectErrorObj { self }
fn positions(&self) -> BoxedIter<'_, ErrorPosition> { fn positions(&self) -> BoxedIter<'_, ErrorPosition> {
Box::new(self.details().locations.iter().cloned()) Box::new(self.details().positions.iter().cloned())
} }
} }

View File

@@ -6,9 +6,9 @@ use trait_set::trait_set;
use crate::atom::Atomic; use crate::atom::Atomic;
use crate::atom_owned::{OwnedAtom, OwnedVariant}; use crate::atom_owned::{OwnedAtom, OwnedVariant};
use crate::conv::{ToExpr, TryFromExpr};
use crate::expr::{ExprHandle, GenExpr}; use crate::expr::{ExprHandle, GenExpr};
use crate::system::SysCtx; use crate::system::SysCtx;
use crate::conv::{ToExpr, TryFromExpr};
trait_set! { trait_set! {
trait FunCB = FnOnce(ExprHandle) -> GenExpr + DynClone + Send + Sync + 'static; trait FunCB = FnOnce(ExprHandle) -> GenExpr + DynClone + Send + Sync + 'static;
@@ -16,7 +16,9 @@ trait_set! {
pub struct Fun(Box<dyn FunCB>); pub struct Fun(Box<dyn FunCB>);
impl Fun { impl Fun {
pub fn new<I: TryFromExpr, O: ToExpr>(f: impl FnOnce(I) -> O + Clone + Send + Sync + 'static) -> Self { pub fn new<I: TryFromExpr, O: ToExpr>(
f: impl FnOnce(I) -> O + Clone + Send + Sync + 'static,
) -> Self {
Self(Box::new(|eh| I::try_from_expr(eh).map(f).to_expr())) Self(Box::new(|eh| I::try_from_expr(eh).map(f).to_expr()))
} }
} }

View File

@@ -10,7 +10,7 @@ use orchid_base::reqnot::{ReqNot, Requester};
use crate::error::{ use crate::error::{
err_from_api_or_ref, err_or_ref_to_api, pack_err, unpack_err, ProjectErrorObj, ProjectResult, 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 struct LexContext<'a> {
pub text: &'a Tok<String>, pub text: &'a Tok<String>,
@@ -20,13 +20,13 @@ pub struct LexContext<'a> {
pub reqnot: ReqNot<ExtMsgSet>, pub reqnot: ReqNot<ExtMsgSet>,
} }
impl<'a> LexContext<'a> { 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); let start = self.pos(tail);
self self
.reqnot .reqnot
.request(SubLex { pos: start, id: self.id }) .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_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 } 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>( fn lex<'a>(
tail: &'a str, tail: &'a str,
ctx: &'a LexContext<'a>, ctx: &'a LexContext<'a>,
) -> Option<ProjectResult<(&'a str, GenTokTree)>>; ) -> Option<ProjectResult<(&'a str, OwnedTokTree)>>;
} }
pub trait DynLexer: Send + Sync + 'static { pub trait DynLexer: Send + Sync + 'static {
@@ -56,7 +56,7 @@ pub trait DynLexer: Send + Sync + 'static {
&self, &self,
tail: &'a str, tail: &'a str,
ctx: &'a LexContext<'a>, ctx: &'a LexContext<'a>,
) -> Option<ProjectResult<(&'a str, GenTokTree)>>; ) -> Option<ProjectResult<(&'a str, OwnedTokTree)>>;
} }
impl<T: Lexer> DynLexer for T { impl<T: Lexer> DynLexer for T {
@@ -65,7 +65,7 @@ impl<T: Lexer> DynLexer for T {
&self, &self,
tail: &'a str, tail: &'a str,
ctx: &'a LexContext<'a>, ctx: &'a LexContext<'a>,
) -> Option<ProjectResult<(&'a str, GenTokTree)>> { ) -> Option<ProjectResult<(&'a str, OwnedTokTree)>> {
T::lex(tail, ctx) T::lex(tail, ctx)
} }
} }

View File

@@ -1,4 +1,7 @@
pub mod atom; pub mod atom;
pub mod atom_owned;
pub mod atom_thin;
pub mod conv;
pub mod entrypoint; pub mod entrypoint;
pub mod error; pub mod error;
pub mod expr; pub mod expr;
@@ -10,6 +13,3 @@ pub mod other_system;
pub mod system; pub mod system;
pub mod system_ctor; pub mod system_ctor;
pub mod tree; pub mod tree;
pub mod conv;
pub mod atom_thin;
pub mod atom_owned;

View File

@@ -1,11 +1,11 @@
use orchid_api_traits::Decode; use std::any::TypeId;
use orchid_api::proto::ExtMsgSet; use orchid_api::proto::ExtMsgSet;
use orchid_api::system::SysId; use orchid_api::system::SysId;
use orchid_api_traits::Decode;
use orchid_base::reqnot::ReqNot; 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::fs::DeclFs;
use crate::fun::Fun; use crate::fun::Fun;
use crate::lexer::LexerObj; use crate::lexer::LexerObj;
@@ -15,44 +15,45 @@ use crate::tree::GenTree;
/// System as consumed by foreign code /// System as consumed by foreign code
pub trait SystemCard: Default + Send + Sync + 'static { pub trait SystemCard: Default + Send + Sync + 'static {
type Ctor: SystemCtor; type Ctor: SystemCtor;
const ATOM_DEFS: &'static [Option<fn() -> &'static AtomInfo>]; const ATOM_DEFS: &'static [Option<&'static dyn AtomDynfo>];
} }
pub trait DynSystemCard: Send + Sync + 'static { pub trait DynSystemCard: Send + Sync + 'static {
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
/// Atoms explicitly defined by the system card. Do not rely on this for /// Atoms explicitly defined by the system card. Do not rely on this for
/// querying atoms as it doesn't include the general atom types /// querying atoms as it doesn't include the general atom types
fn atoms(&self) -> &'static [Option<fn() -> &'static AtomInfo>]; fn atoms(&self) -> &'static [Option<&'static dyn AtomDynfo>];
} }
/// Atoms supported by this package which may appear in all extensions. /// 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 /// 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) /// marks whether it belongs to this package (0) or the importer (1)
fn general_atoms() -> &'static [Option<fn () -> &'static AtomInfo>] { fn general_atoms() -> &'static [Option<&'static dyn AtomDynfo>] { &[Some(Fun::INFO)] }
&[Some(Fun::info)]
}
pub fn atom_info_for( pub fn atom_info_for(
sys: &(impl DynSystemCard + ?Sized), sys: &(impl DynSystemCard + ?Sized),
tid: ConstTypeId, tid: TypeId,
) -> Option<(u64, &AtomInfo)> { ) -> Option<(u64, &'static dyn AtomDynfo)> {
(sys.atoms().iter().enumerate().map(|(i, o)| (i as u64, o))) (sys.atoms().iter().enumerate().map(|(i, o)| (i as u64, o)))
.chain(general_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()))) .filter_map(|(i, o)| o.as_ref().map(|a| (i, *a)))
.find(|ent| ent.1.tid == tid) .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 { if (tid >> (u64::BITS - 1)) & 1 == 1 {
general_atoms()[!tid as usize].map(|f| f()) general_atoms()[!tid as usize]
} else { } else {
sys.atoms()[tid as usize].map(|f| f()) sys.atoms()[tid as usize]
} }
} }
impl<T: SystemCard> DynSystemCard for T { impl<T: SystemCard> DynSystemCard for T {
fn name(&self) -> &'static str { T::Ctor::NAME } fn name(&self) -> &'static str { T::Ctor::NAME }
fn atoms(&self) -> &'static [Option<fn() -> &'static AtomInfo>] { Self::ATOM_DEFS } fn atoms(&self) -> &'static [Option<&'static dyn AtomDynfo>] { Self::ATOM_DEFS }
} }
/// System as defined by author /// System as defined by author
@@ -85,7 +86,7 @@ pub fn downcast_atom<A: AtomCard>(foreign: ForeignAtom) -> Result<TypAtom<A>, Fo
match info_ent { match info_ent {
None => Err(foreign), None => Err(foreign),
Some((_, info)) => { Some((_, info)) => {
let val = (info.decode)(data); let val = info.decode(data);
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type"); let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
Ok(TypAtom { value, data: foreign }) Ok(TypAtom { value, data: foreign })
}, },

View File

@@ -4,38 +4,34 @@ use ahash::HashMap;
use dyn_clone::{clone_box, DynClone}; use dyn_clone::{clone_box, DynClone};
use itertools::Itertools; use itertools::Itertools;
use orchid_api::tree::{ use orchid_api::tree::{
MacroRule, Paren, Placeholder, PlaceholderKind, Token, TokenTree, Tree, TreeId, TreeModule, MacroRule, Paren, PlaceholderKind, Token, TokenTree, Tree, TreeId, TreeModule,
TreeTicket, TreeTicket,
}; };
use orchid_base::interner::{intern, Tok}; use orchid_base::interner::intern;
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_base::name::VName; use orchid_base::name::VName;
use orchid_base::tokens::OwnedPh;
use ordered_float::NotNan; use ordered_float::NotNan;
use trait_set::trait_set; use trait_set::trait_set;
use crate::atom::AtomFactory; use crate::atom::AtomFactory;
use crate::conv::ToExpr; use crate::conv::ToExpr;
use crate::error::{err_or_ref_to_api, ProjectErrorObj};
use crate::expr::GenExpr; use crate::expr::GenExpr;
use crate::system::DynSystem; use crate::system::DynSystem;
#[derive(Clone)] #[derive(Clone)]
pub struct GenPh { pub struct OwnedTokTree {
pub name: Tok<String>, pub tok: OwnedTok,
pub kind: PlaceholderKind,
}
#[derive(Clone)]
pub struct GenTokTree {
pub tok: GenTok,
pub range: Range<u32>, pub range: Range<u32>,
} }
impl GenTokTree { impl OwnedTokTree {
pub fn into_api(self, sys: &dyn DynSystem) -> TokenTree { pub fn into_api(self, sys: &dyn DynSystem) -> TokenTree {
TokenTree { token: self.tok.into_api(sys), range: self.range } 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("..") { match s.strip_prefix("..") {
Some(v_tail) => { Some(v_tail) => {
let (mid, priority) = match v_tail.split_once(':') { let (mid, priority) = match v_tail.split_once(':') {
@@ -49,29 +45,30 @@ pub fn ph(s: &str) -> GenPh {
if konst::string::starts_with(name, "_") { if konst::string::starts_with(name, "_") {
panic!("Names starting with an underscore indicate a single-name scalar placeholder") 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, "$_") { 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 => match konst::string::strip_prefix(s, "$") {
None => panic!("Invalid placeholder"), None => panic!("Invalid placeholder"),
Some(name) => GenPh { name: intern(name), kind: PlaceholderKind::Scalar }, Some(name) => OwnedPh { name: intern(name), kind: PlaceholderKind::Scalar },
}, },
}, },
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub enum GenTok { pub enum OwnedTok {
Lambda(Vec<GenTokTree>, Vec<GenTokTree>), Lambda(Vec<OwnedTokTree>, Vec<OwnedTokTree>),
Name(VName), Name(VName),
S(Paren, Vec<GenTokTree>), S(Paren, Vec<OwnedTokTree>),
Atom(AtomFactory), Atom(AtomFactory),
Slot(TreeTicket), Slot(TreeTicket),
Ph(GenPh), Ph(OwnedPh),
Bottom(ProjectErrorObj),
} }
impl GenTok { impl OwnedTok {
pub fn at(self, range: Range<u32>) -> GenTokTree { GenTokTree { tok: self, range } } pub fn at(self, range: Range<u32>) -> OwnedTokTree { OwnedTokTree { tok: self, range } }
pub fn into_api(self, sys: &dyn DynSystem) -> Token { pub fn into_api(self, sys: &dyn DynSystem) -> Token {
match self { match self {
Self::Lambda(x, body) => Token::Lambda( Self::Lambda(x, body) => Token::Lambda(
@@ -79,32 +76,33 @@ impl GenTok {
body.into_iter().map(|tt| tt.into_api(sys)).collect_vec(), 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::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::S(p, body) => Token::S(p, body.into_iter().map(|tt| tt.into_api(sys)).collect_vec()),
Self::Slot(tk) => Token::Slot(tk), Self::Slot(tk) => Token::Slot(tk),
Self::Atom(at) => Token::Atom(at.build(sys)), Self::Atom(at) => Token::Atom(at.build(sys)),
Self::Bottom(err) => Token::Bottom(err_or_ref_to_api(err)),
} }
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub struct GenMacro { pub struct GenMacro {
pub pattern: Vec<GenTokTree>, pub pattern: Vec<OwnedTokTree>,
pub priority: NotNan<f64>, pub priority: NotNan<f64>,
pub template: Vec<GenTokTree>, pub template: Vec<OwnedTokTree>,
} }
pub fn tokv_into_api( pub fn tokv_into_api(
tokv: impl IntoIterator<Item = GenTokTree>, tokv: impl IntoIterator<Item = OwnedTokTree>,
sys: &dyn DynSystem, sys: &dyn DynSystem,
) -> Vec<TokenTree> { ) -> Vec<TokenTree> {
tokv.into_iter().map(|tok| tok.into_api(sys)).collect_vec() tokv.into_iter().map(|tok| tok.into_api(sys)).collect_vec()
} }
pub fn wrap_tokv(items: Vec<GenTokTree>, range: Range<u32>) -> GenTokTree { pub fn wrap_tokv(items: Vec<OwnedTokTree>, range: Range<u32>) -> OwnedTokTree {
match items.len() { match items.len() {
1 => items.into_iter().next().unwrap(), 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( pub fn rule(
prio: f64, prio: f64,
pat: impl IntoIterator<Item = GenTokTree>, pat: impl IntoIterator<Item = OwnedTokTree>,
tpl: impl IntoIterator<Item = GenTokTree>, tpl: impl IntoIterator<Item = OwnedTokTree>,
) -> Self { ) -> Self {
GenItem::Rule(GenMacro { GenItem::Rule(GenMacro {
pattern: pat.into_iter().collect(), pattern: pat.into_iter().collect(),

View File

@@ -1,4 +1,5 @@
use std::io::Write as _; use std::io::Write as _;
use std::ops::Deref;
use std::sync::atomic::{AtomicU16, AtomicU32, Ordering}; use std::sync::atomic::{AtomicU16, AtomicU32, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex, RwLock, Weak}; 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::error::{ErrNotif, ProjErrOrRef, ProjResult, ReportError};
use orchid_api::expr::{Acquire, Expr, ExprNotif, ExprTicket, Release, Relocate}; use orchid_api::expr::{Acquire, Expr, ExprNotif, ExprTicket, Release, Relocate};
use orchid_api::interner::IntReq; use orchid_api::interner::IntReq;
use orchid_api::parser::CharFilter; use orchid_api::parser::{CharFilter, Lexed, SubLexed};
use orchid_api::proto::{ 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::system::{NewSystem, SysDeclId, SysId, SystemDecl, SystemDrop};
use orchid_api::tree::{GetConstTree, Tree, TreeId}; 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::char_filter::char_filter_match;
use orchid_base::clone; 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 orchid_base::reqnot::{ReqNot, Requester as _};
use ordered_float::NotNan; use ordered_float::NotNan;
@@ -230,24 +231,28 @@ impl System {
pub fn const_tree(&self) -> Tree { pub fn const_tree(&self) -> Tree {
self.0.ext.0.reqnot.request(GetConstTree(self.0.id, self.0.const_root_id)) self.0.ext.0.reqnot.request(GetConstTree(self.0.id, self.0.const_root_id))
} }
pub fn request<R: Coding>(&self, req: impl Request<Response = ProjResult<R>> + Into<HostExtReq>) -> ProjResult<R> { pub fn catch_err<R: Coding>(&self, cb: impl FnOnce() -> ProjResult<R>) -> ProjResult<R> {
let mut errors = Vec::new(); let mut errors = Vec::new();
if let Ok(err) = self.0.err_rec.lock().unwrap().try_recv() { if let Ok(err) = self.0.err_rec.lock().unwrap().try_recv() {
eprintln!("Errors left in queue"); eprintln!("Errors left in queue");
errors.push(err); 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() { while let Ok(err) = self.0.err_rec.lock().unwrap().try_recv() {
errors.push(err); errors.push(err);
} }
if !errors.is_empty() { if !errors.is_empty() { Err(errors) } else { value }
Err(errors)
} else {
value
}
} }
pub fn has_lexer(&self) -> bool { !self.0.lex_filter.0.is_empty() } 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 can_lex(&self, c: char) -> bool { char_filter_match(&self.0.lex_filter, c) }
pub fn lex(
&self,
source: Tok<String>,
pos: usize,
r: impl FnMut(usize) -> ProjResult<SubLexed>,
) -> ProjResult<Lexed> {
todo!()
}
} }
impl fmt::Debug for System { impl fmt::Debug for System {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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() }
}

118
orchid-host/src/lex.rs Normal file
View File

@@ -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<String>,
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<OwnedTokTree> {
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!()
}

View File

@@ -1,3 +1,6 @@
pub mod child; pub mod child;
pub mod expr; pub mod expr;
pub mod extension; pub mod extension;
pub mod lex;
pub mod results;
pub mod tree;

View File

@@ -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<T> = Result<T, Vec<OwnedError>>;
pub fn mk_err(
description: Tok<String>,
message: impl AsRef<str>,
posv: impl IntoIterator<Item = ErrorPosition>,
) -> 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()],
}
}

24
orchid-host/src/tree.rs Normal file
View File

@@ -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<u32>,
}
#[derive(Clone)]
pub enum OwnedTok {
Lambda(Vec<OwnedTokTree>, Vec<OwnedTokTree>),
Name(VName),
S(Paren, Vec<OwnedTokTree>),
Atom(AtomHand),
Ph(OwnedPh),
Bottom(OwnedError),
}

View File

@@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use orchid_extension::atom::AtomicFeatures; use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
use orchid_extension::fs::DeclFs; use orchid_extension::fs::DeclFs;
use orchid_extension::fun::Fun; use orchid_extension::fun::Fun;
use orchid_extension::system::{System, SystemCard}; use orchid_extension::system::{System, SystemCard};
@@ -22,16 +22,25 @@ impl SystemCtor for StdSystem {
} }
impl SystemCard for StdSystem { impl SystemCard for StdSystem {
type Ctor = Self; type Ctor = Self;
const ATOM_DEFS: &'static [Option<fn() -> &'static orchid_extension::atom::AtomInfo>] = &[ const ATOM_DEFS: &'static [Option<&'static dyn AtomDynfo>] = &[Some(StringAtom::INFO)];
Some(StringAtom::info)
];
} }
impl System for StdSystem { impl System for StdSystem {
fn lexers() -> Vec<orchid_extension::lexer::LexerObj> { vec![&StringLexer] } fn lexers() -> Vec<orchid_extension::lexer::LexerObj> { vec![&StringLexer] }
fn vfs() -> DeclFs { DeclFs::Mod(&[]) } fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
fn env() -> GenTree { fn env() -> GenTree {
GenTree::module([("std", GenTree::module([("string", GenTree::module([ 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())))))) "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()))
})
})),
)]),
)]),
)])
} }
} }

View File

@@ -10,10 +10,10 @@ use orchid_base::interner::{deintern, Tok};
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_extension::atom::{Atomic, TypAtom}; use orchid_extension::atom::{Atomic, TypAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant}; use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
use orchid_extension::conv::TryFromExpr;
use orchid_extension::error::{ProjectError, ProjectResult}; use orchid_extension::error::{ProjectError, ProjectResult};
use orchid_extension::expr::{ExprHandle, OwnedExpr}; use orchid_extension::expr::{ExprHandle, OwnedExpr};
use orchid_extension::system::{downcast_atom, SysCtx}; use orchid_extension::system::{downcast_atom, SysCtx};
use orchid_extension::conv::TryFromExpr;
pub static STR_REPO: IdStore<Arc<String>> = IdStore::new(); pub static STR_REPO: IdStore<Arc<String>> = IdStore::new();
@@ -59,10 +59,12 @@ impl StringAtom {
fn get_value(&self) -> Arc<String> { self.try_local_value().expect("no string found for ID") } fn get_value(&self) -> Arc<String> { self.try_local_value().expect("no string found for ID") }
} }
impl OwnedAtom for StringAtom { impl OwnedAtom for StringAtom {
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(match self { fn val(&self) -> Cow<'_, Self::Data> {
Cow::Owned(match self {
Self::Int(tok) => StringVal::Int(tok.marker()), Self::Int(tok) => StringVal::Int(tok.marker()),
Self::Val(id) => StringVal::Val(*id), Self::Val(id) => StringVal::Val(*id),
}) } })
}
fn same(&self, _ctx: SysCtx, other: &Self) -> bool { self.get_value() == other.get_value() } fn same(&self, _ctx: SysCtx, other: &Self) -> bool { self.get_value() == other.get_value() }
fn handle_req( fn handle_req(
&self, &self,
@@ -90,9 +92,7 @@ impl OrcString {
pub struct NotString(Pos); pub struct NotString(Pos);
impl ProjectError for NotString { impl ProjectError for NotString {
const DESCRIPTION: &'static str = "A string was expected"; const DESCRIPTION: &'static str = "A string was expected";
fn one_position(&self) -> Pos { fn one_position(&self) -> Pos { self.0.clone() }
self.0.clone()
}
} }
impl TryFromExpr for OrcString { impl TryFromExpr for OrcString {
fn try_from_expr(expr: ExprHandle) -> ProjectResult<OrcString> { fn try_from_expr(expr: ExprHandle) -> ProjectResult<OrcString> {

View File

@@ -6,7 +6,7 @@ use orchid_base::vname;
use orchid_extension::atom::AtomicFeatures; use orchid_extension::atom::AtomicFeatures;
use orchid_extension::error::{ErrorSansOrigin, ProjectErrorObj, ProjectResult}; use orchid_extension::error::{ErrorSansOrigin, ProjectErrorObj, ProjectResult};
use orchid_extension::lexer::{LexContext, Lexer}; 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; use super::str_atom::StringAtom;
@@ -119,15 +119,15 @@ impl Lexer for StringLexer {
fn lex<'a>( fn lex<'a>(
full_string: &'a str, full_string: &'a str,
ctx: &'a LexContext<'a>, ctx: &'a LexContext<'a>,
) -> Option<ProjectResult<(&'a str, GenTokTree)>> { ) -> Option<ProjectResult<(&'a str, OwnedTokTree)>> {
full_string.strip_prefix('"').map(|mut tail| { full_string.strip_prefix('"').map(|mut tail| {
let mut parts = vec![]; let mut parts = vec![];
let mut cur = String::new(); let mut cur = String::new();
let commit_str = |str: &mut String, tail: &str, parts: &mut Vec<GenTokTree>| { let commit_str = |str: &mut String, tail: &str, parts: &mut Vec<OwnedTokTree>| {
let str_val = parse_string(str) let str_val = parse_string(str)
.inspect_err(|e| ctx.report(e.clone().into_proj(ctx.pos(tail) - str.len() as u32))) .inspect_err(|e| ctx.report(e.clone().into_proj(ctx.pos(tail) - str.len() as u32)))
.unwrap_or_default(); .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))); parts.push(tok.at(ctx.tok_ran(str.len() as u32, tail)));
*str = String::new(); *str = String::new();
}; };
@@ -137,8 +137,8 @@ impl Lexer for StringLexer {
return Ok((rest, wrap_tokv(parts, ctx.pos(full_string)..ctx.pos(rest)))); return Ok((rest, wrap_tokv(parts, ctx.pos(full_string)..ctx.pos(rest))));
} else if let Some(rest) = tail.strip_prefix('$') { } else if let Some(rest) = tail.strip_prefix('$') {
commit_str(&mut cur, tail, &mut parts); commit_str(&mut cur, tail, &mut parts);
parts.push(GenTok::Name(VName::literal("++")).at(ctx.tok_ran(1, rest))); parts.push(OwnedTok::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!(std::string::convert)).at(ctx.tok_ran(1, rest)));
match ctx.recurse(rest) { match ctx.recurse(rest) {
Ok((new_tail, tree)) => { Ok((new_tail, tree)) => {
tail = new_tail; tail = new_tail;

View File

@@ -17,35 +17,6 @@ use crate::foreign::atom::AtomGenerator;
use crate::foreign::inert::Inert; use crate::foreign::inert::Inert;
use crate::libs::std::number::Numeric; 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<usize>,
/// Reason
pub kind: NumErrorKind,
}
impl NumError { impl NumError {
/// Convert into [ProjectErrorObj] /// Convert into [ProjectErrorObj]
pub fn into_proj( pub fn into_proj(
@@ -64,73 +35,7 @@ impl NumError {
} }
} }
/// Parse a numbre literal out of text
pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
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<usize, NumError> {
let s = s.chars().filter(|c| *c != '_').collect::<String>();
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<f64>) -> 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 /// [LexerPlugin] for a number literal
#[derive(Clone)] #[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);
}
}