summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1030
-rw-r--r--Cargo.toml12
-rwxr-xr-xdemo/build.sh5
-rw-r--r--demo/test-1.hex64
-rw-r--r--src/ion.rs241
-rw-r--r--src/main.rs65
-rw-r--r--src/runtime.rs671
7 files changed, 2088 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..dd9753d
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,1030 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "ahash"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[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 = "base64"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+
+[[package]]
+name = "bigdecimal"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa"
+dependencies = [
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+
+[[package]]
+name = "boa_ast"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73498e9b2f0aa7db74977afa4d594657611e90587abf0dd564c0b55b4a130163"
+dependencies = [
+ "bitflags",
+ "boa_interner",
+ "boa_macros",
+ "indexmap",
+ "num-bigint",
+ "rustc-hash",
+]
+
+[[package]]
+name = "boa_gc"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c97b44beaef9d4452342d117d94607fdfa8d474280f1ba0fd97853834e3a49b2"
+dependencies = [
+ "boa_macros",
+ "boa_profiler",
+]
+
+[[package]]
+name = "boa_icu_provider"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b30e52e34e451dd0bfc2c654a9a43ed34b0073dbd4ae3394b40313edda8627aa"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer",
+ "icu_properties",
+ "icu_provider",
+ "icu_provider_adapters",
+ "icu_provider_blob",
+ "once_cell",
+]
+
+[[package]]
+name = "boa_interner"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3e5afa991908cfbe79bd3109b824e473a1dc5f74f31fab91bb44c9e245daa77"
+dependencies = [
+ "boa_gc",
+ "boa_macros",
+ "hashbrown 0.14.3",
+ "indexmap",
+ "once_cell",
+ "phf",
+ "rustc-hash",
+ "static_assertions",
+]
+
+[[package]]
+name = "boa_macros"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "005fa0c5bd20805466dda55eb34cd709bb31a2592bb26927b47714eeed6914d8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "synstructure",
+]
+
+[[package]]
+name = "boa_parser"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e09afb035377a9044443b598187a7d34cd13164617182a4d7c348522ee3f052"
+dependencies = [
+ "bitflags",
+ "boa_ast",
+ "boa_icu_provider",
+ "boa_interner",
+ "boa_macros",
+ "boa_profiler",
+ "fast-float",
+ "icu_locid",
+ "icu_properties",
+ "icu_provider",
+ "icu_provider_macros",
+ "num-bigint",
+ "num-traits",
+ "once_cell",
+ "regress",
+ "rustc-hash",
+ "tinystr",
+]
+
+[[package]]
+name = "boa_profiler"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190f92dfe48224adc92881c620f08ccf37ff62b91a094bb357fe53bd5e84647"
+
+[[package]]
+name = "bumpalo"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
+dependencies = [
+ "byteorder",
+ "iovec",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-targets",
+]
+
+[[package]]
+name = "cobs"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "critical-section"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
+
+[[package]]
+name = "delegate"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d358e0ec5c59a5e1603b933def447096886121660fc680dc1e64a0753981fe3c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "embedded-io"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "fast-float"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c"
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "icu_collections"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef8302d8dfd6044d3ddb3f807a5ef3d7bbca9a574959c6d6e4dc39aa7012d0d5"
+dependencies = [
+ "displaydoc",
+ "serde",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3003f85dccfc0e238ff567693248c59153a46f4e6125ba4020b973cef4d1d335"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "serde",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "652869735c9fb9f5a64ba180ee16f2c848390469c116deef517ecc53f4343598"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce0e1aa26851f16c9e04412a5911c86b7f8768dac8f8d4c5f1c568a7e5d7a434"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_provider",
+ "serde",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dc312a7b6148f7dfe098047ae2494d12d4034f48ade58d4f353000db376e305"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "postcard",
+ "serde",
+ "stable_deref_trait",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_adapters"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ae1e2bd0c41728b77e7c46e9afdec5e2127d1eedacc684724667d50c126bd3"
+dependencies = [
+ "icu_locid",
+ "icu_provider",
+ "serde",
+ "tinystr",
+ "yoke",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_blob"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd364c9a01f791a4bc04a74cf2a1d01d9f6926a40fd5ae1c28004e1e70d8338b"
+dependencies = [
+ "icu_provider",
+ "postcard",
+ "serde",
+ "writeable",
+ "yoke",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b728b9421e93eff1d9f8681101b78fa745e0748c95c655c83f337044a7e10"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.3",
+]
+
+[[package]]
+name = "ion-rs"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7434986c985887a9da57b80429e02225cc561d0a9351fcd39aa309f08abea7db"
+dependencies = [
+ "arrayvec",
+ "base64",
+ "bigdecimal",
+ "bytes",
+ "chrono",
+ "delegate",
+ "nom",
+ "num-bigint",
+ "num-integer",
+ "num-traits",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "iovec"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.151"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+
+[[package]]
+name = "litemap"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9d642685b028806386b2b6e75685faadd3eb65a85fff7df711ce18446a422da"
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+dependencies = [
+ "critical-section",
+ "portable-atomic",
+]
+
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_macros",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+dependencies = [
+ "phf_shared",
+ "rand",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+
+[[package]]
+name = "postcard"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8"
+dependencies = [
+ "cobs",
+ "embedded-io",
+ "serde",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+
+[[package]]
+name = "regress"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82a9ecfa0cb04d0b04dddb99b8ccf4f66bc8dfd23df694b398570bd8ae3a50fb"
+dependencies = [
+ "hashbrown 0.13.2",
+ "memchr",
+]
+
+[[package]]
+name = "reljs"
+version = "0.1.0"
+dependencies = [
+ "boa_ast",
+ "boa_interner",
+ "boa_parser",
+ "ion-rs",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "serde"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "smallvec"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "unicode-xid",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8faa444297615a4e020acb64146b0603c9c395c03a97c17fd9028816d3b4d63e"
+dependencies = [
+ "displaydoc",
+ "serde",
+ "zerovec",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
+
+[[package]]
+name = "windows-core"
+version = "0.51.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dad7bb64b8ef9c0aa27b6da38b452b0ee9fd82beaf276a87dd796fb55cbae14e"
+
+[[package]]
+name = "yoke"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+ "synstructure",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "591691014119b87047ead4dcf3e6adfbf73cb7c38ab6980d4f18a32138f35d46"
+dependencies = [
+ "serde",
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a4a1638a1934450809c2266a70362bfc96cd90550c073f5b8a55014d1010157"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.42",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..0108c5a
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "reljs"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+boa_ast = "0.17"
+boa_interner = "0.17"
+boa_parser = "0.17"
+ion-rs = "0.18"
diff --git a/demo/build.sh b/demo/build.sh
new file mode 100755
index 0000000..b2e370e
--- /dev/null
+++ b/demo/build.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+IN=$1
+
+cat $IN | sed 's/;.*$//' | xxd -r -p - ${IN%.*}.bin
diff --git a/demo/test-1.hex b/demo/test-1.hex
new file mode 100644
index 0000000..e7f7c6e
--- /dev/null
+++ b/demo/test-1.hex
@@ -0,0 +1,64 @@
+; Function header (3 args, 3 variables)
+00 03 00 03
+
+; Store the listing
+10 BE 91 D8 8A 21 02 8B 53 C2 01 2B D7 8A 21 01 8B 52 C2 C8
+13 80
+
+; Store the min price
+10 0F
+13 81
+
+; Store the best offer
+10 0F
+13 82
+
+; Iterate the offers
+19 80
+
+; offersloop: (34)
+03 ; DUP2
+38 F7 ; IFGE2 end
+1B 80 ; STEPIN 1
+
+; structloop: (39)
+03 ; DUP2
+38 D1 ; IFGE2 missingprice
+1E 80 ; SFIELD 1
+10 71 0B ; PUSH price
+36 B3 ; IFEQ2 endstructloop
+1A 80 ; NEXT 1
+01 A5 ; JMP structloop
+
+; endstructloop: (53)
+1D 80 ; LOADVALUE 1
+
+12 81 ; LOAD 2
+10 0F ; PUSH null
+36 C1 ; IFEQ2 saveprice
+
+12 81 ; LOAD 2
+3B CE ; IFLT2 skipoffer
+
+; saveprice: (65)
+1D 80 ; SVALUE 1 ; Save the lowest price in var2.
+13 81 ; STORE 2
+1C ; STEPOUT
+1D 80 ; VALUE 1 ; Save the whole struct in var3.
+13 82 ; STORE 3
+1A 80 ; NEXT 1
+01 A0 ; JMP offersloop
+
+; skipoffer: (78)
+1C ; STEPOUT
+1A 80 ; NEXT 1
+01 A0 ; JMP offersloop
+
+; missingprice: (83)
+10 8E 9F 65 72 72 6F 72 3A 20 6D 69 73 73 69 6E 67 20 70 72 69 63 65 20 69 6E 20 6C 69 73 74 69 6E 67 ; PUSH "error: missing price in listing"
+13 82 ; STORE 3
+
+; end: (119)
+11
+11
+11
diff --git a/src/ion.rs b/src/ion.rs
new file mode 100644
index 0000000..6773539
--- /dev/null
+++ b/src/ion.rs
@@ -0,0 +1,241 @@
+use std::iter::Copied;
+
+pub enum IonType {
+ Null = 0x00,
+ Bool = 0x01,
+ IntPos = 0x02,
+ IntNeg= 0x03,
+ Float = 0x04,
+ Decimal = 0x05,
+ Timestamp = 0x06,
+ Symbol = 0x07,
+ String = 0x08,
+ Clob = 0x09,
+ Blob = 0x0a,
+ List = 0x0b,
+ Sexp = 0x0c,
+ Struct = 0x0d,
+ Annotations = 0x0e,
+}
+
+#[derive(PartialOrd, PartialEq)]
+pub struct IonValue(Vec<u8>);
+
+impl IonValue {
+ pub fn new_null() -> IonValue {
+ IonValue(vec![0x0F])
+ }
+
+ pub fn ion_type(&self) -> u8 {
+ self.0[0] >> 4
+ }
+
+ pub fn len(&self) -> usize {
+ // TODO: Should this read the type length?
+ self.0.len()
+ }
+
+ pub fn repr_offset(&self) -> usize {
+ let mut reader = self.reader();
+ let tl = reader.next_byte();
+ let _len = reader.extract_length(tl);
+ reader.offset()
+ }
+
+ pub fn bytes(&self) -> impl DoubleEndedIterator<Item = u8> + '_ {
+ self.0.iter().copied()
+ }
+
+ pub fn reader(&self) -> IonReader<impl DoubleEndedIterator<Item = u8> + '_> {
+ IonReader::new(self.0.iter().copied(), 0)
+ }
+
+ pub fn reader_at(&self, offset: usize) -> IonReader<Copied<std::slice::Iter<'_, u8>>> {
+ IonReader::new(self.0[offset..].iter().copied(), offset)
+ }
+
+ pub fn struct_reader_at(&self, offset: usize) -> IonReader<Copied<std::slice::Iter<'_, u8>>> {
+ IonReader::new_struct(self.0[offset..].iter().copied(), offset)
+ }
+
+ pub fn to_usize(&self) -> usize {
+ self.reader().next_usize()
+ }
+
+}
+
+impl From<Vec<u8>> for IonValue {
+ fn from(value: Vec<u8>) -> Self {
+ if value.len() > 0 {
+ IonValue(value)
+ } else {
+ IonValue(vec![0x0F])
+ }
+ }
+}
+
+
+pub struct IonReader<T> {
+ iter: T,
+ offset: usize,
+ is_struct: bool,
+ field_name: Option<usize>,
+}
+
+impl <T> IonReader<T>
+ where T: Iterator<Item = u8>
+{
+ pub fn new(iter: T, offset: usize) -> IonReader<T> {
+ IonReader {
+ iter,
+ offset,
+ is_struct: false,
+ field_name: None,
+ }
+ }
+
+ pub fn new_struct(iter: T, offset: usize) -> IonReader<T> {
+ IonReader {
+ iter,
+ offset,
+ is_struct: true,
+ field_name: None,
+ }
+ }
+
+ pub fn offset(&self) -> usize {
+ self.offset
+ }
+
+ pub fn field_id(&self) -> Option<usize> {
+ self.field_name
+ }
+
+ /// Move the iterator to the first nested value.
+ pub fn step_in(&mut self) -> (u8, usize) {
+ self.prepare_next();
+ let tl = self.next_byte();
+ let len = self.extract_length(tl);
+ if (tl & 0xF0) == 0xD0 {
+ self.is_struct = true;
+ }
+ (tl >> 4, self.offset + len)
+ }
+
+ fn prepare_next(&mut self) {
+ if self.is_struct {
+ // TODO: symbol length can be greater than max usize.
+ self.field_name = Some(self.next_varuint());
+ }
+ }
+
+ pub fn skip_value(&mut self) {
+ self.prepare_next();
+ let tl = self.next_byte();
+ let len = self.extract_length(tl);
+ for _ in 0..len {
+ self.next_byte();
+ }
+ }
+
+ pub fn next_value(&mut self) -> IonValue {
+ self.prepare_next();
+ let tl = self.next_byte();
+ let (mut buf, len) = match tl & 0x0F {
+ 0 | 15 => (vec![tl], 0),
+ 14 => {
+ let l = self.next_varuint();
+ let mut v = Vec::with_capacity(5 + l);
+ v.push(tl);
+ push_varuint(&mut v, l);
+ (v, l)
+ },
+ len => {
+ let l = len.into();
+ let mut v = Vec::with_capacity(5 + l);
+ v.push(tl);
+ (v, l)
+ }
+ };
+ for _ in 0..len {
+ let b = self.next_byte();
+ buf.push(b);
+ }
+ buf.into()
+ }
+
+ pub fn next_usize(&mut self) -> usize {
+ self.prepare_next();
+ let tl = self.next_byte();
+ if tl & 0xF0 != 0x20 {
+ panic!("Not a positive integer");
+ }
+
+ let len = self.extract_length(tl);
+ if len * 8 > usize::BITS as usize {
+ panic!("Integer too large for usize");
+ }
+
+ let mut value = 0;
+ for _ in 0..len {
+ let b = self.next_byte();
+ value <<= 8;
+ value |= b as usize;
+ }
+ value
+ }
+
+ fn next_byte(&mut self) -> u8 {
+ self.offset += 1;
+ self.iter.next().expect("Missing data")
+ }
+
+ fn extract_length(&mut self, tl: u8) -> usize {
+ match tl & 0x0F {
+ 0 | 15 => 0,
+ 14 => self.next_varuint(),
+ len => len.into(),
+ }
+ }
+
+ fn next_varuint(&mut self) -> usize {
+ let mut v: usize = 0;
+ while let Some(b) = self.iter.next() {
+ self.offset += 1;
+ v <<= 7;
+ v |= (b & 0x7f) as usize;
+ if b & 0x80 != 0 {
+ return v;
+ }
+ }
+ panic!("Truncated varuint");
+ }
+}
+
+fn push_varuint(v: &mut Vec<u8>, mut value: usize) {
+ let mut buf = [0; (usize::BITS / 7 + 1) as usize];
+ let mut pos = 0;
+ while value != 0 {
+ buf[pos] = (value & 0x7F) as u8;
+ value >>= 7;
+ pos += 1;
+ }
+ buf[0] |= 0x80;
+ pos = pos.max(1);
+
+ for i in (0..pos).rev() {
+ v.push(buf[i]);
+ }
+}
+
+fn parse_varuint(buf: &[u8]) -> usize {
+ let mut value: usize = 0;
+ for b in buf {
+ value <<= 7;
+ value |= (b & 0x7F) as usize;
+ if b & 0x80 != 0 {
+ break;
+ }
+ }
+ value
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..78d1822
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,65 @@
+use std::fs::File;
+use std::io;
+use std::io::prelude::*;
+use std::path::Path;
+
+use boa_interner::Interner;
+use boa_parser::Parser;
+use boa_parser::Source;
+use ion::IonValue;
+use runtime::Runtime;
+
+mod ion;
+mod runtime;
+
+#[derive(Debug)]
+pub enum RelJsError {
+ IoError(io::Error),
+ JsParseError(boa_parser::Error),
+ BytecodeEOF,
+}
+
+impl From<io::Error> for RelJsError {
+ fn from(value: io::Error) -> Self {
+ RelJsError::IoError(value)
+ }
+}
+
+impl From<boa_parser::Error> for RelJsError {
+ fn from(value: boa_parser::Error) -> Self {
+ RelJsError::JsParseError(value)
+ }
+}
+
+
+
+fn main() -> Result<(), RelJsError> {
+ //let src = Source::from_filepath(Path::new("script.js"))?;
+ //let mut parser = Parser::new(src);
+ //let mut interner = Interner::new();
+ //let script = parser.parse_script(&mut interner)?;
+
+ let mut bin = File::open("demo/test-1.bin")?;
+ let mut data = Vec::new();
+ bin.read_to_end(&mut data)?;
+
+ let mut runtime = Runtime::new();
+ let fnref = runtime.load_bytecode(data);
+
+ let mut args = Vec::with_capacity(3);
+ args.push(IonValue::new_null());
+ args.push(IonValue::new_null());
+ args.push(IonValue::new_null());
+
+ let result = runtime.invoke(fnref, args);
+
+ for (i, v) in result.iter().enumerate() {
+ println!("Result {i}:");
+ for b in v.bytes() {
+ print!("{b:02x} ");
+ }
+ println!("\n");
+ }
+
+ Ok(())
+}
diff --git a/src/runtime.rs b/src/runtime.rs
new file mode 100644
index 0000000..3954a80
--- /dev/null
+++ b/src/runtime.rs
@@ -0,0 +1,671 @@
+use std::{collections::LinkedList, cmp::Ordering, sync::Arc};
+
+use ion_rs::SymbolTable;
+
+use crate::ion::{IonReader, IonValue};
+
+
+
+
+#[repr(u8)]
+pub enum OpCode {
+
+ Jump = 0x01,
+
+ Dup2 = 0x03,
+
+ /// Push a typed Ion value onto the stack.
+ /// operands: T and L
+ /// length
+ /// repr
+ /// stack: [] -> [representation, length, T and L]
+ /// Note: lengths are reversed on the stack.
+ /// representations are not reversed.
+ TypePush = 0x10,
+
+ /// Pop a typed Ion value from the stack.
+ /// operands:
+ /// stack: [repr, length, T and L] -> []
+ TypePop = 0x11,
+
+ /// Load a typed Ion value from a variable onto the stack.
+ /// operands: variableId (VarUInt)
+ /// stack: [] -> [repr, length, T and L]
+ TypeLoad = 0x12,
+
+ /// Save a typed Ion value from the stack into a variable.
+ /// operands: variableId (VarUInt)
+ /// stack: [repr, length, T and L] -> []
+ TypeStore = 0x13,
+
+ /// Push the length of the type.
+ /// operands: variableId (VarUInt)
+ /// stack: [repr, length, T+L] -> [Int]
+ TypeLength = 0x14,
+
+ /// Append bytes onto the end of a typed sequence of bytes.
+ /// This operation is valid with string, clob, and blob types.
+ /// operands: variableId (VarUInt)
+ /// number of octets to push
+ /// stack: [repr, length, T+L, bytes] -> [repr, bytes, length', T+L']
+ BytesAppend = 0x15,
+
+ /// Append a typed value onto the end of a list or sexp.
+ /// operands: variableId (VarUInt)
+ /// stack: [repr, length, T+L] -> []
+ ListAppend = 0x16,
+
+ /// Push the element from a list or sexp onto the stack.
+ /// operands: variableId (VarUInt)
+ /// stack: [offset (Int)] -> [{next offset}, {value}]
+ ListLoad = 0x17,
+
+ /// Append a typed value onto the end of a struct.
+ /// operands: variableId (VarUInt)
+ /// stack: [{value}, {symbol}] -> []
+ FieldAppend = 0x18,
+
+ /// Prepare an iterator an iterator over the variable.
+ /// operands: variableId (VarUInt)
+ /// stack: [{offset (UInt)}] -> [{next offset}]
+ Iterator = 0x19,
+
+ /// Move an iterator to the next value.
+ /// operands: variableId (VarUInt)
+ /// stack: [{offset (UInt)}] -> [{next offset}]
+ Next = 0x1A,
+
+ /// Move an iterator to a nested value.
+ /// operands: variableId (VarUInt)
+ /// stack: [{offset (UInt)}] -> [{offset}, {next end}, {next offset}]
+ StepIn = 0x1B,
+
+ /// Move an iterator out of a nested value.
+ /// operands: variableId (VarUInt)
+ /// stack: [{offset (UInt)}] -> [{next offset}]
+ /// stack: [{{end}, {offset}] -> []
+ StepOut = 0x1C,
+
+ /// Copy a value onto the stack
+ /// operands: variableId (VarUInt)
+ /// stack: [{offset (UInt)}] -> [{offset}, {value}]
+ LoadValue = 0x1D,
+
+ /// Copy a struct field symbol onto the stack
+ /// operands: variableId (VarUInt)
+ /// stack: [{offset (UInt)}] -> [{offset}, {value}]
+ StructField = 0x1E,
+
+
+ /// Add two ints.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ IntAdd = 0x21,
+
+ /// Subtract value2 from value1.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ IntSub = 0x22,
+
+ /// Multiply value1 and value2.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ IntMul = 0x23,
+
+ /// Divide value2 by value1.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ IntDiv = 0x24,
+
+
+ /// Add two floats.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ FloatAdd = 0x41,
+
+ /// Subtract value2 from value1.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ FloatSub = 0x42,
+
+ /// Multiply value1 and value2.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ FloatMul = 0x43,
+
+ /// Divide value2 by value1.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ FloatDiv = 0x44,
+
+
+ /// Add two decimals.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ DecimalAdd = 0x51,
+
+ /// Subtract value2 from value1.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ DecimalSub = 0x52,
+
+ /// Multiply value1 and value2.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ DecimalMul = 0x53,
+
+ /// Divide value2 by value1.
+ /// operands:
+ /// stack -> [{value1}, {value2} -> {result}]
+ DecimalDiv = 0x54,
+
+
+ /// Jump to the given instruction if value == 0.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value}] -> []
+ IfEq = 0x30,
+
+ /// Jump to the given instruction if values != 0.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value}] -> []
+ IfNe = 0x31,
+
+ /// Jump to the given instruction if value >= 0
+ /// operands: instruction (VarUInt)
+ /// stack: [{value}] -> []
+ IfGe = 0x32,
+
+ /// Jump to the given instruction if value > 0.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value}] -> []
+ IfGt = 0x33,
+
+ /// Jump to the given instruction if value <= 0.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value}] -> []
+ IfLe = 0x34,
+
+ /// Jump to the given instruction if value < 0.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value}] -> []
+ IfLt = 0x35,
+
+
+ /// Jump to the given instruction if two values are equal.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value1}, {value2}] -> []
+ IfEq2 = 0x36,
+
+ /// Jump to the given instruction if two values are not equal.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value1}, {value2}] -> []
+ IfNe2 = 0x37,
+
+ /// Jump to the given instruction if value2 >= value1.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value1}, {value2}] -> []
+ IfGe2 = 0x38,
+
+ /// Jump to the given instruction if value2 > value1.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value1}, {value2}] -> []
+ IfGt2 = 0x39,
+
+ /// Jump to the given instruction if value2 <= value1.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value1}, {value2}] -> []
+ IfLe2 = 0x3a,
+
+ /// Jump to the given instruction if value2 < value1.
+ /// operands: instruction (VarUInt)
+ /// stack: [{value1}, {value2}] -> []
+ IfLt2 = 0x3b,
+
+}
+
+impl OpCode {
+ pub fn as_u8(&self) -> u8 {
+ unsafe { *(self as *const Self as *const u8) }
+ }
+}
+
+pub struct Runtime {
+ symbols: SymbolTable,
+ stacks: LinkedList<StackFrame>,
+ functions: Vec<Arc<Function>>,
+}
+
+pub enum ExecutionState {
+ Continue,
+ Halt,
+}
+
+pub struct Function {
+ bytecode: ByteCode,
+ arguments: u16,
+ variables: u16,
+ expected_stack_depth: usize,
+}
+
+pub type FnRef = usize;
+pub type ByteCode = Vec<u8>;
+
+struct Stack(Vec<u8>);
+
+pub struct StackFrame {
+ func: Arc<Function>,
+ pc: usize,
+ variables: Vec<IonValue>,
+ stack: Stack,
+}
+
+impl Runtime {
+ pub fn new() -> Runtime {
+ Runtime {
+ symbols: SymbolTable::new(),
+ stacks: LinkedList::new(),
+ functions: Vec::new(),
+ }
+ }
+
+ pub fn load_bytecode(&mut self, data: Vec<u8>) -> FnRef {
+ let arguments = (data[0] as u16) << 8 | (data[1] as u16);
+ let variables = (data[2] as u16) << 8 | (data[3] as u16);
+ let func = Function {
+ bytecode: data.into_iter().skip(4).collect(),
+ arguments,
+ variables,
+ expected_stack_depth: 32,
+ };
+ self.functions.push(func.into());
+ self.functions.len() - 1
+ }
+
+ pub fn invoke(&mut self, fnref: FnRef, arguments: Vec<IonValue>) -> Vec<IonValue> {
+ let func = self.functions.get(fnref).expect("Undefined function").clone();
+ let mut frame = StackFrame::new(func.clone(), arguments);
+ loop {
+ match self.execute(&mut frame) {
+ ExecutionState::Continue => (),
+ ExecutionState::Halt => {
+ frame.variables.truncate(func.arguments.into());
+ return frame.variables;
+ },
+ }
+ }
+ }
+
+ fn execute(&mut self, frame: &mut StackFrame) -> ExecutionState {
+ if frame.eof() {
+ return ExecutionState::Halt;
+ }
+
+ let op = frame.next_byte();
+ println!("PC: {:02X}, OP: {:02X}, Stack: {:02X}", frame.pc, op, frame.stack.0.len());
+ for x in &frame.stack.0 {
+ print!(" {x:02X}");
+ }
+ println!();
+
+ match op {
+ 0x01 => { // OpType::Jump
+ let pc = frame.next_varuint();
+ frame.jump(pc);
+ },
+ 0x03 => { // OpType::Dup2
+ let value1 = frame.stack.pop_value();
+ let value2 = frame.stack.pop_value();
+ frame.stack.push_value(&value2);
+ frame.stack.push_value(&value1);
+ frame.stack.push_value(&value2);
+ frame.stack.push_value(&value1);
+ },
+ 0x10 => { // OpType::Push
+ let buf = &frame.func.bytecode[frame.pc..];
+ let mut reader = IonReader::new(buf.iter().copied(), 0);
+ let value = reader.next_value();
+ frame.pc += reader.offset();
+ frame.stack.push_value(&value);
+ },
+ 0x11 => { // OpCode::TypePop
+ frame.stack.drop_value();
+ },
+ 0x12 => { // OpCode::TypeLoad
+ let var = frame.next_varuint();
+ frame.stack.push_value(&frame.variables[var]);
+ },
+ 0x13 => { // OpCode::TypeStore
+ let var = frame.next_varuint();
+ frame.variables[var] = frame.stack.pop_value();
+ },
+ 0x14 => { // OpCode::TypeLength
+ let var = frame.next_varuint();
+ let buf = frame.variables.get(var).expect("Undefined variable");
+ let len = buf.len();
+ frame.stack.push_usize(len);
+ },
+ 0x15 => todo!(), // OpCode::BytesAppend
+ 0x16 => todo!(), // OpCode::ListAppend
+ 0x17 => todo!(), // OpCode::ListLoad
+ 0x18 => todo!(), // OpCode::FieldAppend
+ 0x19 => { // OpCode::Iterate
+ let varid = frame.next_varuint();
+ let value = frame.variables
+ .get(varid)
+ .expect("Undefined variable");
+
+ let mut reader = value.reader();
+ let (ion_type, end) = reader.step_in();
+ let pos = reader.offset();
+
+ frame.stack.push_usize(ion_type as usize);
+ frame.stack.push_usize(end);
+ frame.stack.push_usize(pos);
+
+ },
+ 0x1A => { // OpCode::Next
+ let pos = frame.stack.pop_value().to_usize();
+ let len = frame.stack.pop_value().to_usize();
+ let ion_type = frame.stack.pop_value().to_usize();
+
+ let varid = frame.next_varuint();
+ let mut value = if ion_type == 0x0D {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .struct_reader_at(pos)
+ } else {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .reader_at(pos)
+ };
+ value.skip_value();
+ let next = value.offset();
+ frame.stack.push_usize(ion_type); // TODO peek
+ frame.stack.push_usize(len); // TODO peek
+ frame.stack.push_usize(next);
+ },
+ 0x1B => { // OpCode::StepIn
+ let pos = frame.stack.pop_value().to_usize();
+ let len = frame.stack.pop_value().to_usize();
+ let ion_type = frame.stack.pop_value().to_usize();
+
+ frame.stack.push_usize(ion_type); // TODO peek
+ frame.stack.push_usize(len); // TODO peek
+ frame.stack.push_usize(pos); // TODO peek
+
+ let varid = frame.next_varuint();
+ let mut value = if ion_type == 0x0D {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .struct_reader_at(pos)
+ } else {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .reader_at(pos)
+ };
+
+ let (next_type, next_end) = value.step_in();
+ let next_pos = value.offset();
+
+ frame.stack.push_usize(next_type as usize);
+ frame.stack.push_usize(next_end);
+ frame.stack.push_usize(next_pos);
+ },
+ 0x1C => { // OpCode::StepOut
+ frame.stack.drop_value();
+ frame.stack.drop_value();
+ frame.stack.drop_value();
+ },
+ 0x1D => { // OpCode::LoadValue
+ let pos = frame.stack.pop_value().to_usize();
+ let len = frame.stack.pop_value().to_usize();
+ let ion_type = frame.stack.pop_value().to_usize();
+
+ frame.stack.push_usize(ion_type); // TODO peek
+ frame.stack.push_usize(len); // TODO peek
+ frame.stack.push_usize(pos); // TODO peek
+
+ let varid = frame.next_varuint();
+ let mut value = if ion_type == 0x0D {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .struct_reader_at(pos)
+ } else {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .reader_at(pos)
+ };
+
+ let next_value = value.next_value();
+ frame.stack.push_value(&next_value);
+ },
+ 0x1E => { // OpCode::StructField
+ let pos = frame.stack.pop_value().to_usize();
+ let len = frame.stack.pop_value().to_usize();
+ let ion_type = frame.stack.pop_value().to_usize();
+
+ frame.stack.push_usize(ion_type); // TODO peek
+ frame.stack.push_usize(len); // TODO peek
+ frame.stack.push_usize(pos); // TODO peek
+
+ let varid = frame.next_varuint();
+ let mut value = if ion_type == 0x0D {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .struct_reader_at(pos)
+ } else {
+ frame.variables
+ .get(varid)
+ .expect("Undefined variable")
+ .reader_at(pos)
+ };
+
+ value.skip_value();
+ if let Some(field_id) = value.field_id() {
+ frame.stack.push_symbol(field_id);
+ } else {
+ panic!("Not a struct");
+ }
+ },
+ 0x21 => self.int_add(frame), // OpCode::IntAdd
+ 0x22 => todo!(), // OpCode::IntSub
+ 0x23 => todo!(), // OpCode::IntMul
+ 0x24 => todo!(), // OpCode::IntDiv
+ 0x41 => todo!(), // OpCode::FloatAdd
+ 0x42 => todo!(), // OpCode::FloatSub
+ 0x43 => todo!(), // OpCode::FloatMul
+ 0x44 => todo!(), // OpCode::FloatDiv
+ 0x51 => todo!(), // OpCode::DecimalAdd
+ 0x52 => todo!(), // OpCode::DecimalSub
+ 0x53 => todo!(), // OpCode::DecimalMul
+ 0x54 => todo!(), // OpCode::DecimalDiv
+ 0x30 => todo!(), // OpCode::IfEq
+ 0x31 => todo!(), // OpCode::IfNe
+ 0x32 => todo!(), // OpCode::IfGe
+ 0x33 => todo!(), // OpCode::IfGt
+ 0x34 => todo!(), // OpCode::IfLe
+ 0x35 => todo!(), // OpCode::IfLt
+ 0x36 => { // OpCode::IfEq2
+ let next_pc = frame.next_varuint();
+ let value1 = frame.stack.pop_value();
+ let value2 = frame.stack.pop_value();
+ if value1 == value2 {
+ frame.pc = next_pc;
+ }
+ },
+ 0x37 => { // OpCode::IfNe2
+ let next_pc = frame.next_varuint();
+ let value1 = frame.stack.pop_value();
+ let value2 = frame.stack.pop_value();
+ if value1 != value2 {
+ frame.pc = next_pc;
+ }
+ },
+ 0x38 => { // OpCode::IfGe2
+ let next_pc = frame.next_varuint();
+ let value1 = frame.stack.pop_value();
+ let value2 = frame.stack.pop_value();
+ if value1 >= value2 {
+ frame.pc = next_pc;
+ }
+ },
+ 0x39 => { // OpCode::IfGt2
+ let next_pc = frame.next_varuint();
+ let value1 = frame.stack.pop_value();
+ let value2 = frame.stack.pop_value();
+ if value1 > value2 {
+ frame.pc = next_pc;
+ }
+ },
+ 0x3A => { // OpCode::IfLe2
+ let next_pc = frame.next_varuint();
+ let value1 = frame.stack.pop_value();
+ let value2 = frame.stack.pop_value();
+ if value1 <= value2 {
+ frame.pc = next_pc;
+ }
+ },
+ 0x3B => { // OpCode::IfLt2
+ let next_pc = frame.next_varuint();
+ let value1 = frame.stack.pop_value();
+ let value2 = frame.stack.pop_value();
+ if value1 < value2 {
+ frame.pc = next_pc;
+ }
+ },
+ _ => panic!("Invalid opcode {:02x} at {}", op, frame.pc),
+ }
+
+ ExecutionState::Continue
+ }
+
+ fn int_add(&self, frame: &mut StackFrame) {
+ todo!()
+ }
+}
+
+impl StackFrame {
+ pub fn new(func: Arc<Function>, arguments: Vec<IonValue>) -> StackFrame {
+ let stack = Stack::new(func.expected_stack_depth);
+ let mut frame = StackFrame {
+ func,
+ pc: 0,
+ variables: arguments,
+ stack,
+ };
+
+ for _ in frame.func.arguments..frame.func.variables {
+ frame.variables.push(IonValue::new_null());
+ }
+
+ frame
+ }
+
+ fn jump(&mut self, pc: usize) {
+ self.pc = pc;
+ }
+
+ fn eof(&self) -> bool {
+ self.pc >= self.func.bytecode.len()
+ }
+
+ fn next_byte(&mut self) -> u8 {
+ let b = self.func.bytecode[self.pc];
+ self.pc += 1;
+ b
+ }
+
+ fn next_bytes(&mut self, len: usize) -> &[u8] {
+ let end = self.pc + len;
+ let bytes = &self.func.bytecode[self.pc..end];
+ self.pc = end;
+ bytes
+ }
+
+ fn next_varuint(&mut self) -> usize {
+ let mut b: usize = self.next_byte().into();
+ let mut v = b & 0x7f;
+ while (b & 0x80) == 0 {
+ b = self.next_byte().into();
+ v <<= 7;
+ v |= b & 0x7f;
+ }
+ v
+ }
+}
+
+impl Stack {
+ pub fn new(expected_depth: usize) -> Stack {
+ Stack(Vec::with_capacity(expected_depth))
+ }
+
+ pub fn peak_reader(&self) -> IonReader<impl DoubleEndedIterator<Item = u8> + '_> {
+ IonReader::new(self.0.iter().copied().rev(), 0)
+ }
+
+ pub fn drop_value(&mut self) {
+ let mut it = IonReader::new(self.0.iter().copied().rev(), 0);
+ it.skip_value();
+ let offset = it.offset();
+ self.0.truncate(self.0.len() - offset);
+ }
+
+ pub fn pop_value(&mut self) -> IonValue {
+ let mut it = IonReader::new(self.0.iter().copied().rev(), 0);
+ let value = it.next_value();
+ let offset = it.offset();
+ self.0.truncate(self.0.len() - offset);
+ value
+ }
+
+ pub fn push_value(&mut self, value: &IonValue) {
+ for byte in value.bytes().rev() {
+ self.0.push(byte);
+ }
+ }
+
+ pub fn push_symbol(&mut self, value: usize) {
+ match value.cmp(&0) {
+ Ordering::Equal => self.0.push(0x70),
+ Ordering::Greater => {
+ let mut v = value;
+ let mut octets = 0;
+ while v != 0 {
+ self.0.push((v & 0xFF) as u8);
+ octets += 1;
+ v >>= 8;
+ }
+ let tl = 0x70 | octets;
+ self.0.push(tl);
+ },
+ Ordering::Less => (),
+ }
+ }
+
+ pub fn push_usize(&mut self, value: usize) {
+ match value.cmp(&0) {
+ Ordering::Equal => self.0.push(0x20),
+ Ordering::Greater => {
+ let mut v = value;
+ let mut octets = 0;
+ while v != 0 {
+ self.0.push((v & 0xFF) as u8);
+ octets += 1;
+ v >>= 8;
+ }
+ let tl = 0x20 | octets;
+ self.0.push(tl);
+ },
+ Ordering::Less => (),
+ }
+ }
+
+}
+