From d04b4dfa993681060d363b5ef994c1a635f3c1f9 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Thu, 28 Dec 2023 17:12:54 -0800 Subject: Checkpoint --- Cargo.lock | 1030 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 + demo/build.sh | 5 + demo/test-1.hex | 64 ++++ src/ion.rs | 241 +++++++++++++ src/main.rs | 65 ++++ src/runtime.rs | 671 ++++++++++++++++++++++++++++++++++++ 7 files changed, 2088 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100755 demo/build.sh create mode 100644 demo/test-1.hex create mode 100644 src/ion.rs create mode 100644 src/main.rs create mode 100644 src/runtime.rs 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); + +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 + '_ { + self.0.iter().copied() + } + + pub fn reader(&self) -> IonReader + '_> { + IonReader::new(self.0.iter().copied(), 0) + } + + pub fn reader_at(&self, offset: usize) -> IonReader>> { + IonReader::new(self.0[offset..].iter().copied(), offset) + } + + pub fn struct_reader_at(&self, offset: usize) -> IonReader>> { + IonReader::new_struct(self.0[offset..].iter().copied(), offset) + } + + pub fn to_usize(&self) -> usize { + self.reader().next_usize() + } + +} + +impl From> for IonValue { + fn from(value: Vec) -> Self { + if value.len() > 0 { + IonValue(value) + } else { + IonValue(vec![0x0F]) + } + } +} + + +pub struct IonReader { + iter: T, + offset: usize, + is_struct: bool, + field_name: Option, +} + +impl IonReader + where T: Iterator +{ + pub fn new(iter: T, offset: usize) -> IonReader { + IonReader { + iter, + offset, + is_struct: false, + field_name: None, + } + } + + pub fn new_struct(iter: T, offset: usize) -> IonReader { + IonReader { + iter, + offset, + is_struct: true, + field_name: None, + } + } + + pub fn offset(&self) -> usize { + self.offset + } + + pub fn field_id(&self) -> Option { + 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, 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 for RelJsError { + fn from(value: io::Error) -> Self { + RelJsError::IoError(value) + } +} + +impl From 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, + functions: Vec>, +} + +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; + +struct Stack(Vec); + +pub struct StackFrame { + func: Arc, + pc: usize, + variables: Vec, + 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) -> 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) -> Vec { + 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, arguments: Vec) -> 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 + '_> { + 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 => (), + } + } + +} + -- cgit v1.2.3