summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock86
-rw-r--r--Cargo.toml2
-rw-r--r--matrix-bin/Cargo.lock385
-rw-r--r--matrix-bin/Cargo.toml4
-rw-r--r--matrix-bin/src/helper.rs8
-rw-r--r--matrix-bin/src/main.rs119
-rw-r--r--matrix-bin/src/repl.rs53
-rw-r--r--matrix-lang/Cargo.lock (renamed from matrix/Cargo.lock)0
-rw-r--r--matrix-lang/Cargo.toml (renamed from matrix/Cargo.toml)2
-rw-r--r--matrix-lang/src/ast.rs (renamed from matrix/src/ast.rs)100
-rw-r--r--matrix-lang/src/binary/deserialize.rs160
-rw-r--r--matrix-lang/src/binary/mod.rs154
-rw-r--r--matrix-lang/src/binary/prim.rs109
-rw-r--r--matrix-lang/src/binary/serialize.rs283
-rw-r--r--matrix-lang/src/chunk.rs (renamed from matrix/src/chunk.rs)71
-rw-r--r--matrix-lang/src/compiler.rs (renamed from matrix/src/compiler.rs)160
-rw-r--r--matrix-lang/src/lex.rs (renamed from matrix/src/lex.rs)177
-rw-r--r--matrix-lang/src/lib.rs42
-rw-r--r--matrix-lang/src/parse.rs (renamed from matrix/src/parse.rs)94
-rw-r--r--matrix-lang/src/prelude.rs60
-rw-r--r--matrix-lang/src/value/clone.rs54
-rw-r--r--matrix-lang/src/value/comp.rs373
-rw-r--r--matrix-lang/src/value/exception.rs78
-rw-r--r--matrix-lang/src/value/fmt.rs186
-rw-r--r--matrix-lang/src/value/function.rs43
-rw-r--r--matrix-lang/src/value/gc.rs (renamed from matrix/src/gc.rs)22
-rw-r--r--matrix-lang/src/value/hash.rs240
-rw-r--r--matrix-lang/src/value/index.rs230
-rw-r--r--matrix-lang/src/value/matrix.rs337
-rw-r--r--matrix-lang/src/value/mod.rs42
-rw-r--r--matrix-lang/src/value/value.rs522
-rw-r--r--matrix-lang/src/vm.rs (renamed from matrix/src/vm.rs)85
-rw-r--r--matrix-macros/Cargo.toml2
-rw-r--r--matrix-macros/src/lib.rs6
-rw-r--r--matrix-std/Cargo.toml (renamed from matrix-stdlib/Cargo.toml)4
-rw-r--r--matrix-std/src/core.rs (renamed from matrix-stdlib/src/core.rs)21
-rw-r--r--matrix-std/src/io.rs (renamed from matrix-stdlib/src/io.rs)5
-rw-r--r--matrix-std/src/iter.rs (renamed from matrix-stdlib/src/iter.rs)32
-rw-r--r--matrix-std/src/lib.rs50
-rw-r--r--matrix-std/src/math.rs (renamed from matrix-stdlib/src/math.rs)13
-rw-r--r--matrix-std/src/sys.rs (renamed from matrix-stdlib/src/sys.rs)4
-rw-r--r--matrix-stdlib/src/lib.rs32
-rw-r--r--matrix/src/lib.rs122
-rw-r--r--matrix/src/value.rs1223
44 files changed, 3523 insertions, 2272 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9a015a1..91b87c7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -13,9 +13,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.12"
+version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540"
+checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -114,7 +114,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.52",
]
[[package]]
@@ -125,9 +125,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "clipboard-win"
-version = "5.1.0"
+version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ec832972fefb8cf9313b45a0d1945e29c9c251f1d4c6eafc5fe2124c02d2e81"
+checksum = "12f9a0700e0127ba15d1d52dd742097f821cd9c65939303a44d970465040a297"
dependencies = [
"error-code",
]
@@ -166,9 +166,9 @@ dependencies = [
[[package]]
name = "error-code"
-version = "3.0.0"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "281e452d3bad4005426416cdba5ccfd4f5c1280e10099e21db27f7c1c28347fc"
+checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b"
[[package]]
name = "fd-lock"
@@ -221,46 +221,46 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "log"
-version = "0.4.20"
+version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
-name = "matrix"
+name = "matrix-bin"
version = "0.1.0"
dependencies = [
- "anyhow",
- "num-complex",
- "num-rational",
- "regex",
+ "clap",
+ "ctrlc",
+ "matrix-lang",
+ "matrix-std",
+ "rustyline",
]
[[package]]
-name = "matrix-bin"
+name = "matrix-lang"
version = "0.1.0"
dependencies = [
- "clap",
- "ctrlc",
- "matrix",
- "matrix-stdlib",
- "rustyline",
+ "anyhow",
+ "num-complex",
+ "num-rational",
+ "regex",
]
[[package]]
name = "matrix-macros"
version = "0.1.0"
dependencies = [
- "matrix",
+ "matrix-lang",
"quote",
"syn 1.0.109",
]
[[package]]
-name = "matrix-stdlib"
+name = "matrix-std"
version = "0.1.0"
dependencies = [
"anyhow",
- "matrix",
+ "matrix-lang",
"matrix-macros",
"os_info",
"rand",
@@ -490,7 +490,7 @@ checksum = "e5af959c8bf6af1aff6d2b463a57f71aae53d1332da58419e30ad8dc7011d951"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.52",
]
[[package]]
@@ -510,7 +510,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.48",
+ "syn 2.0.52",
]
[[package]]
@@ -538,9 +538,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.48"
+version = "2.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
+checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
dependencies = [
"proc-macro2",
"quote",
@@ -610,9 +610,9 @@ dependencies = [
[[package]]
name = "windows-targets"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
@@ -625,42 +625,42 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
diff --git a/Cargo.toml b/Cargo.toml
index 7e1bcac..9375d89 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,3 @@
[workspace]
resolver = "2"
-members = [ "matrix", "matrix-bin" , "matrix-macros", "matrix-stdlib"]
+members = [ "matrix-lang", "matrix-bin" , "matrix-macros", "matrix-std"]
diff --git a/matrix-bin/Cargo.lock b/matrix-bin/Cargo.lock
deleted file mode 100644
index f61fea6..0000000
--- a/matrix-bin/Cargo.lock
+++ /dev/null
@@ -1,385 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "bitflags"
-version = "2.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "clipboard-win"
-version = "5.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ec832972fefb8cf9313b45a0d1945e29c9c251f1d4c6eafc5fe2124c02d2e81"
-dependencies = [
- "error-code",
-]
-
-[[package]]
-name = "endian-type"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
-
-[[package]]
-name = "errno"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
-dependencies = [
- "libc",
- "windows-sys",
-]
-
-[[package]]
-name = "error-code"
-version = "3.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "281e452d3bad4005426416cdba5ccfd4f5c1280e10099e21db27f7c1c28347fc"
-
-[[package]]
-name = "fd-lock"
-version = "4.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947"
-dependencies = [
- "cfg-if",
- "rustix",
- "windows-sys",
-]
-
-[[package]]
-name = "home"
-version = "0.5.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-dependencies = [
- "windows-sys",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.153"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
-
-[[package]]
-name = "log"
-version = "0.4.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
-
-[[package]]
-name = "matrix"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "num-complex",
- "num-rational",
- "regex",
-]
-
-[[package]]
-name = "matrix-repl"
-version = "0.1.0"
-dependencies = [
- "matrix",
- "rustyline",
-]
-
-[[package]]
-name = "memchr"
-version = "2.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
-
-[[package]]
-name = "nibble_vec"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "nix"
-version = "0.27.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
-dependencies = [
- "bitflags",
- "cfg-if",
- "libc",
-]
-
-[[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-complex"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
-dependencies = [
- "autocfg",
- "num-bigint",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "radix_trie"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
-dependencies = [
- "endian-type",
- "nibble_vec",
-]
-
-[[package]]
-name = "regex"
-version = "1.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
-
-[[package]]
-name = "rustix"
-version = "0.38.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
-dependencies = [
- "bitflags",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys",
-]
-
-[[package]]
-name = "rustyline"
-version = "13.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02a2d683a4ac90aeef5b1013933f6d977bd37d51ff3f4dad829d4931a7e6be86"
-dependencies = [
- "bitflags",
- "cfg-if",
- "clipboard-win",
- "fd-lock",
- "home",
- "libc",
- "log",
- "memchr",
- "nix",
- "radix_trie",
- "unicode-segmentation",
- "unicode-width",
- "utf8parse",
- "winapi",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
-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.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
diff --git a/matrix-bin/Cargo.toml b/matrix-bin/Cargo.toml
index bdb8fb8..10c537e 100644
--- a/matrix-bin/Cargo.toml
+++ b/matrix-bin/Cargo.toml
@@ -10,6 +10,6 @@ path = "src/main.rs"
[dependencies]
clap = { version = "4", features = [ "derive" ] }
ctrlc = "3"
-matrix = { path = "../matrix" }
-matrix-stdlib = { path = "../matrix-stdlib" }
+matrix-lang = { path = "../matrix-lang" }
+matrix-std = { path = "../matrix-std" }
rustyline = { version = "13", features = [ "derive" ] }
diff --git a/matrix-bin/src/helper.rs b/matrix-bin/src/helper.rs
index 95e0848..df40946 100644
--- a/matrix-bin/src/helper.rs
+++ b/matrix-bin/src/helper.rs
@@ -1,7 +1,6 @@
use std::{borrow::Cow, rc::Rc, cell::RefCell};
-
-use matrix::{lex::{Lexer, TokenData, Token}, vm::Vm};
use rustyline::{validate::{Validator, ValidationResult, ValidationContext}, highlight::Highlighter, Helper, Hinter, completion::Completer};
+use matrix_lang::prelude::*;
#[derive(Helper, Hinter)]
pub struct MatrixHelper {
@@ -205,6 +204,7 @@ impl Highlighter for MatrixHelper {
T::Else |
T::While |
T::Let |
+ T::Const |
T::Function |
T::Continue |
T::Break |
@@ -290,12 +290,12 @@ impl Completer for MatrixHelper {
}
let _ = (line, pos, ctx);
- let globals = self.vm.borrow().global_names();
+ let globals = self.vm.borrow().globals();
let names: Vec<Rc<str>> = globals
.borrow()
.clone()
.into_iter()
- .filter(|n| n.starts_with(&buf))
+ .filter_map(|n| if n.name.starts_with(&buf) { Some(n.name.clone()) } else { None })
.collect();
if buf.is_empty() {
diff --git a/matrix-bin/src/main.rs b/matrix-bin/src/main.rs
index 225b353..64d1b3f 100644
--- a/matrix-bin/src/main.rs
+++ b/matrix-bin/src/main.rs
@@ -1,6 +1,6 @@
use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs, cell::RefCell, rc::Rc};
use clap::{Parser as ArgParser, ColorChoice};
-use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}, value::Value};
+use matrix_lang::prelude::*;
use repl::Repl;
mod repl;
@@ -12,16 +12,20 @@ pub struct Args {
/// A path to a input program. Uses stdin if not specified.
file: Option<PathBuf>,
- /// Runs a repl, loading the provided program first
+ /// Compiles the given program
#[arg(short, long)]
- repl: bool,
+ compile: bool,
+
+ /// Optional output for compiled output
+ #[arg(short, long)]
+ output: Option<PathBuf>,
/// Print out debug information
#[arg(short, long)]
debug: bool,
/// Choses color
- #[arg(short, long)]
+ #[arg(long)]
color: Option<ColorChoice>,
/// Disables optimizations
@@ -29,18 +33,21 @@ pub struct Args {
disable_optimizations: bool,
}
+pub enum Mode {
+ Repl,
+ Execute(String),
+ Compile(String, PathBuf),
+}
+
pub struct State<'a> {
parser: Parser,
compiler: Compiler<'a>,
vm: Rc<RefCell<Vm>>,
- repl: bool,
color: bool,
- #[allow(unused)]
- debug: bool,
}
impl<'a> State<'a> {
- pub fn new (args: Args) -> (Self, Option<String>) {
+ pub fn new (args: Args) -> (Self, Mode) {
let stdin = read_stdin();
@@ -53,20 +60,43 @@ impl<'a> State<'a> {
file = None;
}
- let repl = args.repl || file.is_none();
+ let mode;
+ let repl;
+ if args.compile {
+ let path = match (args.output, args.file) {
+ (Some(path), _) => path,
+ (None, Some(path)) => {
+ let mut path = path.clone();
+ path.set_extension("matc");
+ path
+ },
+ (None, None) => {
+ PathBuf::from("matc.out")
+ }
+ };
+ let file = file.unwrap_or(String::new());
+ mode = Mode::Compile(file, path);
+ repl = false;
+ } else if let Some(file) = file {
+ mode = Mode::Execute(file);
+ repl = false;
+ } else {
+ mode = Mode::Repl;
+ repl = true;
+ }
+ let mut vm = Vm::new();
let parser = ParserBuilder::new()
.optimize(!args.disable_optimizations)
.build();
- let mut vm = Vm::new();
let compiler = CompilerBuilder::new()
.repl(repl)
.debug(args.debug)
.names(vm.names())
- .globals(vm.global_names())
+ .globals(vm.globals())
.build();
- matrix_stdlib::load(&mut vm);
+ matrix_std::load(&mut vm);
let color = match args.color {
Some(ColorChoice::Auto) | None => {
@@ -76,21 +106,40 @@ impl<'a> State<'a> {
Some(ColorChoice::Never) => false,
};
- (Self { parser, vm: Rc::new(RefCell::new(vm)), compiler, repl, debug: args.debug, color }, file)
+ (Self {
+ parser,
+ vm: Rc::new(RefCell::new(vm)),
+ compiler,
+ color,
+ }, mode)
}
- pub fn execute(&mut self, code: String) -> matrix::Result<Value> {
- let ast = self.parser.parse(code)?;
- let fun = self.compiler.compile(&ast)?;
+ pub fn execute(&mut self, fun: Rc<Function>) -> Result<Value> {
let val = self.vm.try_borrow_mut().unwrap().run(fun)?;
Ok(val)
}
+ pub fn compile(&mut self, code: String) -> Result<Rc<Function>> {
+ let ast = self.parser.parse(code)?;
+ let fun = self.compiler.compile(&ast)?;
+ Ok(fun)
+ }
+
+ pub fn load_program(&mut self, body: String) -> Result<Rc<Function>> {
+ match Program::load(&body)? {
+ Some(fun) => {
+ Ok(fun)
+ },
+ None => {
+ self.compile(body)
+ },
+ }
+ }
}
-pub fn error(err: matrix::Error, state: &State) {
+pub fn error(err: Exception, state: &State) {
if state.color {
- println!("\x1b[31m\x1b[1mError:\x1b[0m {err}");
+ println!("\x1b[31mError:\x1b[0m {err}");
} else {
println!("Error: {err}");
}
@@ -106,19 +155,33 @@ fn read_stdin() -> String {
buffer
}
+fn handle_mode(state: &mut State, mode: Mode) -> Result<()> {
+ match mode {
+ Mode::Repl => {
+ let mut repl = Repl::new(state);
+ repl.run();
+ },
+ Mode::Execute(body) => {
+ let fun = state.load_program(body)?;
+ state.execute(fun)?;
+ },
+ Mode::Compile(body, path) => {
+ let fun = state.compile(body)?;
+ let mut file = File::create(path).map_err(|e|
+ exception!(IO_EXCEPTION, "{e}")
+ )?;
+ Program::save(fun, &mut file)?;
+ }
+ };
+ Ok(())
+}
+
fn main() {
let args = Args::parse();
- let (mut state, file) = State::new(args);
+ let (mut state, mode) = State::new(args);
- if let Some(file) = file {
- if let Err(err) = state.execute(file) {
- error(err, &state);
- }
+ if let Err(e) = handle_mode(&mut state, mode) {
+ error(e, &state);
}
-
- if state.repl {
- Repl::new(state).run();
- }
-
}
diff --git a/matrix-bin/src/repl.rs b/matrix-bin/src/repl.rs
index f2964d4..fe9975f 100644
--- a/matrix-bin/src/repl.rs
+++ b/matrix-bin/src/repl.rs
@@ -1,21 +1,26 @@
use std::{io::Write, sync::atomic::Ordering};
-
-use matrix::{value::Value, vm::Interupt};
-use rustyline::{Config, EditMode, ColorMode, Editor, CompletionType};
+use rustyline::{Config, EditMode, ColorMode, Editor, CompletionType, error::ReadlineError};
+use matrix_lang::prelude::*;
use crate::{State, helper::MatrixHelper};
-pub struct Repl<'a> {
- state: State<'a>
+pub struct Repl<'s, 'a> {
+ state: &'s mut State<'a>
}
-impl<'a> Repl<'a> {
+impl<'s, 'a> Repl<'s, 'a> {
- pub fn new(state: State<'a>) -> Self {
+ pub fn new(state: &'s mut State<'a>) -> Self {
Self { state }
}
- pub fn run(&mut self) {
+ fn execute(&mut self, line: String) -> Result<Value> {
+ let fun = self.state.compile(line)?;
+ let val = self.state.execute(fun)?;
+ Ok(val)
+ }
+
+ pub fn run(&mut self) {
let interupt = self.state.vm.borrow().interupt();
ctrlc::set_handler(move || {
@@ -23,26 +28,33 @@ impl<'a> Repl<'a> {
}).unwrap();
let config = Config::builder()
+ .indent_size(4)
+ .edit_mode(EditMode::Emacs)
.check_cursor_position(true)
.completion_type(CompletionType::List)
- .edit_mode(EditMode::Emacs)
.color_mode(if self.state.color { ColorMode::Enabled } else { ColorMode::Disabled })
.build();
let helper = MatrixHelper::new(self.state.vm.clone());
+ let histfile = std::env::var("MATRIX_HISTORY").ok();
+
let mut rl = Editor::with_config(config).unwrap();
rl.set_helper(Some(helper));
+ if let Some(hf) = &histfile {
+ rl.load_history(hf).ok();
+ }
loop {
- let Ok(line) = rl.readline(">> ") else {
- break;
- };
- if let Err(_) = rl.add_history_entry(&line) {
- break;
+ let line = match rl.readline(">> ") {
+ Ok(line) => line,
+ Err(ReadlineError::Eof) => break,
+ Err(_) => continue,
};
- match self.state.execute(line) {
- Err(err) => crate::error(err, &self.state),
+
+ rl.add_history_entry(&line).ok();
+
+ match self.execute(line) {
Ok(val) => {
if val != Value::Nil {
if self.state.color {
@@ -52,8 +64,13 @@ impl<'a> Repl<'a> {
}
}
}
- }
- let _ = std::io::stdout().flush();
+ Err(err) => crate::error(err, &self.state),
+ };
+ std::io::stdout().flush().ok();
+ }
+
+ if let Some(hf) = &histfile {
+ rl.save_history(hf).ok();
}
}
diff --git a/matrix/Cargo.lock b/matrix-lang/Cargo.lock
index ed6e714..ed6e714 100644
--- a/matrix/Cargo.lock
+++ b/matrix-lang/Cargo.lock
diff --git a/matrix/Cargo.toml b/matrix-lang/Cargo.toml
index 64e9210..067f77c 100644
--- a/matrix/Cargo.toml
+++ b/matrix-lang/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "matrix"
+name = "matrix-lang"
version = "0.1.0"
edition = "2021"
diff --git a/matrix/src/ast.rs b/matrix-lang/src/ast.rs
index de63630..5720f76 100644
--- a/matrix/src/ast.rs
+++ b/matrix-lang/src/ast.rs
@@ -1,42 +1,70 @@
-use std::{rc::Rc, ops::{Neg, Not}, fmt::Debug};
-use crate::{lex::{Position, TokenData}, value::{Value, InlineList, InlineMatrix, InlineTable}, Result};
+use std::{ops::{Neg, Not}, fmt::{Debug, Display}};
+
+use crate::prelude::*;
+
+pub type AstName = (Rc<str>, Position);
+pub type InlineList = Vec<Expr>;
+pub type InlineMatrix = (usize, usize, Vec<Expr>);
+pub type InlineTable = Vec<(Expr, Expr)>;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum UnaryOp {
// normal math
- Negate,
+ Negate = 1,
// equality
- Not,
+ Not = 2,
+}
+
+impl TryFrom<u8> for UnaryOp {
+ type Error = Exception;
+
+ fn try_from(value: u8) -> std::prelude::v1::Result<Self, Self::Error> {
+ if value < 1 || value > 2 {
+ Err(exception!(BINARY_EXCEPTION, "cannot convert {value} to UnaryOp"))
+ } else {
+ unsafe { Ok(std::mem::transmute(value)) }
+ }
+ }
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum BinaryOp {
// normal math
- Add,
- Subtract,
- Multiply,
- Divide,
- Modulo,
- Power,
+ Add = 1,
+ Subtract = 2,
+ Multiply = 3,
+ Divide = 4,
+ Modulo = 5,
+ Power = 6,
// binary math
- BitwiseAnd,
- BitwiseOr,
- BitwiseXor,
- BitwiseShiftLeft,
- BitwiseShiftRight,
+ BitwiseAnd = 7,
+ BitwiseOr = 8,
+ BitwiseXor = 9,
+ BitwiseShiftLeft = 10,
+ BitwiseShiftRight = 11,
// equality
- Equals,
- NotEquals,
- GreaterEquals,
- LessEquals,
- GreaterThan,
- LessThan,
+ Equals = 12,
+ NotEquals = 13,
+ GreaterEquals = 14,
+ LessEquals = 15,
+ GreaterThan = 16,
+ LessThan = 17,
// iter
- Range,
- RangeEq
+ Range = 18,
+ RangeEq = 19
}
-pub type AstName = (Rc<str>, Position);
+impl TryFrom<u8> for BinaryOp {
+ type Error = Exception;
+
+ fn try_from(value: u8) -> std::prelude::v1::Result<Self, Self::Error> {
+ if value < 1 || value > 19 {
+ Err(exception!(BINARY_EXCEPTION, "cannot convert {value} to BinaryOp"))
+ } else {
+ unsafe { Ok(std::mem::transmute(value)) }
+ }
+ }
+}
#[derive(Debug, Clone, PartialEq)]
pub enum ExprData {
@@ -75,6 +103,7 @@ pub enum ExprData {
Try(Box<Expr>, AstName, Box<Expr>),
Let(AstName, Box<Expr>),
+ Const(AstName, Box<Expr>),
Pipeline(Box<Expr>, Box<Expr>),
@@ -83,22 +112,24 @@ pub enum ExprData {
Return(Box<Expr>),
}
-#[derive(Clone, PartialEq)]
-pub struct Expr {
- pub data: ExprData,
- pub pos: Position
+impl Display for Expr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{self:?}")
+ }
}
impl Debug for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- if f.alternate() {
- write!(f, "{:#?}", self.data)
- } else {
- write!(f, "{:?}", self.data)
- }
+ write!(f, "{:?}", self.data)
}
}
+#[derive(Clone, PartialEq)]
+pub struct Expr {
+ pub data: ExprData,
+ pub pos: Position
+}
+
impl From<(ExprData, Position)> for Expr {
fn from(value: (ExprData, Position)) -> Self {
Self { data: value.0, pos: value.1 }
@@ -377,6 +408,9 @@ pub fn optimize(mut expr: Expr) -> Result<Expr> {
E::Let(ident, expr) => {
E::Let(ident, Box::new(optimize(*expr)?))
},
+ E::Const(ident, expr) => {
+ E::Const(ident, Box::new(optimize(*expr)?))
+ },
E::Assign(lhs, rhs) => {
let lhs = Box::new(optimize(*lhs)?);
let rhs = Box::new(optimize(*rhs)?);
diff --git a/matrix-lang/src/binary/deserialize.rs b/matrix-lang/src/binary/deserialize.rs
new file mode 100644
index 0000000..679f6e5
--- /dev/null
+++ b/matrix-lang/src/binary/deserialize.rs
@@ -0,0 +1,160 @@
+use crate::prelude::*;
+
+use super::{prim::VarInt, Deserialize, Deserializer};
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(BINARY_EXCEPTION, $($arg)*)
+ };
+}
+
+impl Deserialize for Program {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ for _ in 0..5 { s.read::<u8>()?; } // skip header
+ let version: u8 = s.read()?;
+ if version != 0 {
+ return Err(error!("invalid program version {version}"))
+ }
+ let fun = <Rc<Function>>::deserialize(s)?;
+ Ok(Self { version, fun })
+ }
+}
+
+impl Deserialize for Instruction {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ use Instruction as I;
+ let ins: u8 = s.read()?;
+ let ins = match ins {
+ 0 => I::NoOp,
+ 1 => I::CreateLocal,
+ 2 => I::LoadLocal(s.read()?),
+ 3 => I::StoreLocal(s.read()?),
+ 4 => I::DiscardLocals(s.read()?),
+ 5 => I::LoadGlobal(s.read()?),
+ 6 => I::StoreGlobal(s.read()?),
+ 7 => I::Const(s.read()?),
+ 8 => I::Int(s.read()?),
+ 9 => I::True,
+ 10 => I::False,
+ 11 => I::Nil,
+ 12 => I::Dup,
+ 13 => I::Discard(s.read()?),
+ 14 => I::UnaryOp(UnaryOp::try_from(s.read::<u8>()?)?),
+ 15 => I::BinaryOp(BinaryOp::try_from(s.read::<u8>()?)?),
+ 16 => I::NewList(s.read()?),
+ 17 => I::NewTable(s.read()?),
+ 18 => I::NewMatrix(s.read()?, s.read()?),
+ 19 => I::Field(s.read()?),
+ 20 => I::StoreField(s.read()?),
+ 21 => I::Index(s.read()?),
+ 22 => I::StoreIndex(s.read()?),
+ 23 => I::Jump(s.read()?),
+ 24 => I::JumpTrue(s.read()?),
+ 25 => I::JumpFalse(s.read()?),
+ 26 => I::JumpNil(s.read()?),
+ 27 => I::IterCreate,
+ 28 => I::IterNext,
+ 29 => I::Try(s.read()?),
+ 30 => I::TryEnd,
+ 31 => I::Call(s.read()?),
+ 32 => I::Return,
+ n => return Err(error!("invalid instruction op code {n}"))
+ };
+ Ok(ins)
+ }
+}
+
+impl<T: Deserialize> Deserialize for Vec<T> {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ let len = s.read::<VarInt>()?.0;
+ let mut vec = Vec::with_capacity(len);
+ for _ in 0..len {
+ let v = T::deserialize(s)?;
+ vec.push(v);
+ }
+ Ok(vec)
+ }
+}
+
+impl<T: Deserialize> Deserialize for Gc<T> {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ Ok(Gc::new(T::deserialize(s)?))
+ }
+}
+
+impl<T: Deserialize> Deserialize for Rc<T> {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ Ok(Rc::new(T::deserialize(s)?))
+ }
+}
+
+impl Deserialize for Position {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ let row = s.read::<VarInt>()?.0;
+ let col = s.read::<VarInt>()?.0;
+ Ok(Self { row, col })
+ }
+}
+
+impl Deserialize for Chunk {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ let constants = <Vec<Value>>::deserialize(s)?;
+ let code = <Vec<Instruction>>::deserialize(s)?;
+ let pos = <Vec<Position>>::deserialize(s)?;
+ Ok(Self { constants, code, pos })
+ }
+}
+
+impl Deserialize for Value {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ use Value as V;
+ let ty = s.read::<u8>()?;
+ let value = match ty {
+ 0 => V::Nil,
+ 1 => V::Bool(s.read()?),
+ 2 => V::Int(s.read()?),
+ 3 => V::Float(s.read()?),
+ 4 => V::Ratio(Rational64::new(s.read()?, s.read()?)),
+ 5 => V::Complex(Complex64::new(s.read()?, s.read()?)),
+ 6 => V::to_regex(s.read::<String>()?.as_str())?,
+ 7 => V::String(s.read::<String>()?.into()),
+ 8 => V::List(<Vec<Value>>::deserialize(s)?.into()),
+ 9 => {
+ let domain = s.read()?;
+ let codomain = s.read()?;
+ let values = <Vec<Value>>::deserialize(s)?;
+ V::Matrix(Matrix::new(domain, codomain, values).into())
+ },
+ 10 => {
+ let len = s.read::<VarInt>()?.0;
+ let mut table = ValueMap::new();
+ for _ in 0..len {
+ let key = <Value>::deserialize(s)?;
+ let value = <Value>::deserialize(s)?;
+ table.insert(key, value)?;
+ }
+ V::Table(table.into())
+ },
+ 11 => V::Function(<Rc<Function>>::deserialize(s)?),
+ 12 => V::Range((s.read()?, s.read()?, s.read()?).into()),
+ 13 => V::Iter(<Rc<Function>>::deserialize(s)?),
+ n => return Err(error!("invalid value code {n}"))
+ };
+ Ok(value)
+ }
+}
+
+impl Deserialize for Function {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> {
+ let name = s.read::<String>()?;
+ let arity = s.read()?;
+ let variadic = s.read()?;
+ let chunk = <Chunk>::deserialize(s)?;
+ Ok(Function {
+ name: Rc::from(name.as_str()),
+ arity,
+ variadic,
+ fun: InnerFunction::Compiled(chunk.into())
+ })
+ }
+}
diff --git a/matrix-lang/src/binary/mod.rs b/matrix-lang/src/binary/mod.rs
new file mode 100644
index 0000000..53b3fe5
--- /dev/null
+++ b/matrix-lang/src/binary/mod.rs
@@ -0,0 +1,154 @@
+use crate::prelude::*;
+use std::io::{self, Read, Write};
+
+mod serialize;
+mod deserialize;
+mod prim;
+
+pub struct Program {
+ version: u8,
+ fun: Rc<Function>
+}
+
+const PROGRAM_HEADER: [u8; 5] = [0x00, 0x4d, 0x41, 0x54, 0x0a];
+
+impl Program {
+ pub fn load(body: &str) -> Result<Option<Rc<Function>>> {
+ let mut bytes = body.as_bytes();
+ if bytes.len() < 6 {
+ return Ok(None)
+ }
+ let header = &bytes[0..5];
+ if header != &PROGRAM_HEADER {
+ return Ok(None)
+ }
+ let mut s = ProgramDeserializer::from(&mut bytes);
+ let program = <Self>::deserialize(&mut s)?;
+ s.finish()?;
+ Ok(Some(program.fun.clone()))
+ }
+
+ pub fn save<W: Write>(fun: Rc<Function>, w: &mut W) -> Result<()> {
+ let mut s = ProgramSerializer::from(w);
+ let p = Program {
+ version: 0,
+ fun
+ };
+ s.serialize(&p)?;
+ s.finish()?;
+ Ok(())
+ }
+}
+
+pub trait Primitive : Sized {
+ fn write<W: Write>(&self, w: &mut W) -> io::Result<()>;
+ fn read<R: Read>(r: &mut R) -> io::Result<Self>;
+}
+
+pub trait Serialize : Sized {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()>;
+}
+
+pub trait Serializer : Sized {
+ fn serialize<S: Serialize>(&mut self, val: &S) -> Result<()> {
+ val.serialize(self)
+ }
+ fn write<P: Primitive>(&mut self, val: P) -> Result<()>;
+}
+
+pub trait Deserialize : Sized {
+ fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self>;
+}
+
+pub trait Deserializer : Sized {
+ fn deserialize<D: Deserialize>(&mut self) -> Result<D> {
+ D::deserialize(self)
+ }
+ fn read<P: Primitive>(&mut self) -> Result<P>;
+}
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(BINARY_EXCEPTION, $($arg)*)
+ };
+}
+
+pub struct ProgramSerializer<'w, W: Write> {
+ writer: &'w mut W,
+ checksum: u64,
+}
+
+impl<'w, W: Write> ProgramSerializer<'w, W> {
+ fn finish(self) -> Result<()> {
+ let bytes = self.checksum.to_le_bytes();
+ self.writer.write(&bytes).map_err(|e| error!("{e}"))?;
+ Ok(())
+ }
+}
+
+impl<'w, W: Write> Serializer for ProgramSerializer<'w, W> {
+ fn write<P: Primitive>(&mut self, val: P) -> Result<()> {
+ val.write(self).map_err(|e| error!("{e}"))
+ }
+}
+
+impl<'w, W: Write> Write for ProgramSerializer<'w, W> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ for b in buf {
+ self.checksum %= 0xf1e3beef;
+ self.checksum += *b as u64;
+ }
+ self.writer.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.writer.flush()
+ }
+}
+
+impl<'w, W: Write> From<&'w mut W> for ProgramSerializer<'w, W> {
+ fn from(writer: &'w mut W) -> Self {
+ Self { writer, checksum: 0xfe }
+ }
+}
+
+pub struct ProgramDeserializer<'r, R: Read> {
+ reader: &'r mut R,
+ checksum: u64,
+}
+
+impl<'r, R: Read> ProgramDeserializer<'r, R> {
+ fn finish(self) -> Result<()> {
+ let mut bytes = [0u8; 8];
+ self.reader.read_exact(&mut bytes).map_err(|e| error!("{e}"))?;
+ let checksum = u64::from_le_bytes(bytes);
+ if self.checksum != checksum {
+ return Err(error!("checksum doesnt match"))
+ }
+ Ok(())
+ }
+}
+
+impl<'r, R: Read> Deserializer for ProgramDeserializer<'r, R> {
+ fn read<P: Primitive>(&mut self) -> Result<P> {
+ P::read(self).map_err(|e| error!("{e}"))
+ }
+}
+
+impl<'r, R: Read> Read for ProgramDeserializer<'r, R> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let c = self.reader.read(buf)?;
+ for i in 0..c {
+ let b = buf[i];
+ self.checksum %= 0xf1e3beef;
+ self.checksum += b as u64;
+ }
+ Ok(c)
+ }
+}
+
+impl<'r, R: Read> From<&'r mut R> for ProgramDeserializer<'r, R> {
+ fn from(reader: &'r mut R) -> Self {
+ Self { reader, checksum: 0xfe }
+ }
+}
diff --git a/matrix-lang/src/binary/prim.rs b/matrix-lang/src/binary/prim.rs
new file mode 100644
index 0000000..44e6898
--- /dev/null
+++ b/matrix-lang/src/binary/prim.rs
@@ -0,0 +1,109 @@
+use super::Primitive;
+use std::io::{self, Read, Write};
+
+macro_rules! marshal_number {
+ ($type:ident, $byte:expr) => {
+ impl Primitive for $type {
+ fn write<W: Write>(&self, write: &mut W) -> io::Result<()> {
+ write.write(&self.to_le_bytes())?;
+ Ok(())
+ }
+
+ fn read<R: Read>(read: &mut R) -> io::Result<Self> {
+ let mut bytes = [0u8; $byte];
+ read.read_exact(&mut bytes)?;
+ Ok(Self::from_le_bytes(bytes))
+ }
+ }
+ };
+}
+
+marshal_number!(u8, 1);
+marshal_number!(u16, 2);
+marshal_number!(i16, 2);
+marshal_number!(u32, 4);
+marshal_number!(i64, 8);
+marshal_number!(f64, 8);
+
+impl Primitive for bool {
+ fn write<W: Write>(&self, write: &mut W) -> io::Result<()> {
+ if *self {
+ write.write(&[1u8; 1])?;
+ } else {
+ write.write(&[0u8; 1])?;
+ }
+ Ok(())
+ }
+
+ fn read<R: Read>(read: &mut R) -> io::Result<Self> {
+ let mut bytes = [0u8; 1];
+ read.read_exact(&mut bytes)?;
+ if bytes[0] == 1 {
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+}
+
+impl Primitive for String {
+ fn write<W: Write>(&self, write: &mut W) -> io::Result<()> {
+ let bytes = self.as_bytes();
+ let len = bytes.len();
+ write.write(&(len as u32).to_le_bytes())?;
+ write.write(&bytes)?;
+ Ok(())
+ }
+
+ fn read<R: Read>(read: &mut R) -> io::Result<Self> {
+ let len = usize::read(read)?;
+ let mut bytes = vec![0u8; len];
+ read.read_exact(&mut bytes)?;
+ Ok(String::from_utf8_lossy(bytes.as_slice()).to_string())
+ }
+}
+
+impl Primitive for usize {
+ fn write<W: Write>(&self, write: &mut W) -> io::Result<()> {
+ (*self as u32).write(write)
+ }
+
+ fn read<R: Read>(read: &mut R) -> io::Result<Self> {
+ Ok(u32::read(read)? as usize)
+ }
+}
+
+pub struct VarInt(pub usize);
+
+impl Primitive for VarInt {
+ fn write<W: Write>(&self, write: &mut W) -> io::Result<()> {
+ let mut data = self.0;
+ loop {
+ let mut byte = (data & 0x7F) as u8;
+ data >>= 7;
+ if data != 0 {
+ byte += 0x80;
+ }
+ write.write(&[byte; 1])?;
+ if data == 0 {
+ return Ok(())
+ }
+ }
+ }
+
+ fn read<R: Read>(read: &mut R) -> io::Result<Self> {
+ let mut buf = [0];
+ let mut result = 0usize;
+ for count in 0..8 {
+ if read.read(&mut buf)? != 1 {
+ return Ok(Self(0))
+ }
+ let byte = buf[0];
+ result |= ((byte & 0x7F) as usize) << (7 * count);
+ if byte & 0x80 == 0 {
+ return Ok(Self(result))
+ }
+ }
+ Ok(Self(0))
+ }
+}
diff --git a/matrix-lang/src/binary/serialize.rs b/matrix-lang/src/binary/serialize.rs
new file mode 100644
index 0000000..2f2b199
--- /dev/null
+++ b/matrix-lang/src/binary/serialize.rs
@@ -0,0 +1,283 @@
+use crate::{prelude::*, binary::PROGRAM_HEADER};
+use std::ops::Deref;
+use super::{prim::VarInt, Program, Serializer, Serialize};
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(BINARY_EXCEPTION, $($arg)*)
+ };
+}
+
+impl Serialize for Program {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ for b in PROGRAM_HEADER {
+ s.write(b)?;
+ }
+ s.write(self.version)?;
+ s.serialize(self.fun.as_ref())?;
+ Ok(())
+ }
+}
+
+impl Serialize for Instruction {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ use Instruction as I;
+ match self {
+ I::NoOp => {
+ s.write(0u8)?;
+ },
+ I::CreateLocal => {
+ s.write(1u8)?;
+ },
+ I::LoadLocal(idx) => {
+ s.write(2u8)?;
+ s.write(*idx)?;
+ },
+ I::StoreLocal(idx) => {
+ s.write(3u8)?;
+ s.write(*idx)?;
+ },
+ I::DiscardLocals(idx) => {
+ s.write(4u8)?;
+ s.write(*idx)?;
+ },
+ I::LoadGlobal(idx) => {
+ s.write(5u8)?;
+ s.write(*idx)?;
+ }
+ I::StoreGlobal(idx) => {
+ s.write(6u8)?;
+ s.write(*idx)?;
+ },
+ I::Const(idx) => {
+ s.write(7u8)?;
+ s.write(*idx)?;
+ },
+ I::Int(i) => {
+ s.write(8u8)?;
+ s.write(*i)?;
+ },
+ I::True => {
+ s.write(9u8)?;
+ },
+ I::False => {
+ s.write(10u8)?;
+ },
+ I::Nil => {
+ s.write(11u8)?;
+ },
+ I::Dup => {
+ s.write(12u8)?;
+ },
+ I::Discard(idx) => {
+ s.write(13u8)?;
+ s.write(*idx)?;
+ },
+ I::UnaryOp(op) => {
+ s.write(14u8)?;
+ s.write(*op as u8)?;
+ },
+ I::BinaryOp(op) => {
+ s.write(15u8)?;
+ s.write(*op as u8)?;
+ },
+ I::NewList(len) => {
+ s.write(16u8)?;
+ s.write(*len)?;
+ },
+ I::NewTable(len) => {
+ s.write(17u8)?;
+ s.write(*len)?;
+ },
+ I::NewMatrix(d, c) => {
+ s.write(18u8)?;
+ s.write(*d)?;
+ s.write(*c)?;
+ },
+ I::Field(idx) => {
+ s.write(19u8)?;
+ s.write(*idx)?;
+ },
+ I::StoreField(idx) => {
+ s.write(20u8)?;
+ s.write(*idx)?;
+ },
+ I::Index(idx) => {
+ s.write(21u8)?;
+ s.write(*idx)?;
+ },
+ I::StoreIndex(idx) => {
+ s.write(22u8)?;
+ s.write(*idx)?;
+ },
+ I::Jump(ip) => {
+ s.write(23u8)?;
+ s.write(*ip)?;
+ },
+ I::JumpTrue(ip) => {
+ s.write(24u8)?;
+ s.write(*ip)?;
+ },
+ I::JumpFalse(ip) => {
+ s.write(25u8)?;
+ s.write(*ip)?;
+ },
+ I::JumpNil(ip) => {
+ s.write(26u8)?;
+ s.write(*ip)?;
+ },
+ I::IterCreate => {
+ s.write(27u8)?;
+ },
+ I::IterNext => {
+ s.write(28u8)?;
+ },
+ I::Try(ip) => {
+ s.write(29u8)?;
+ s.write(*ip)?;
+ },
+ I::TryEnd => {
+ s.write(30u8)?;
+ },
+ I::Call(arity) => {
+ s.write(31u8)?;
+ s.write(*arity)?;
+ },
+ I::Return => {
+ s.write(32u8)?;
+ },
+ };
+ Ok(())
+ }
+}
+
+impl<T: Serialize> Serialize for Vec<T> {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ s.write(VarInt(self.len()))?;
+ for val in self {
+ val.serialize(s)?;
+ }
+ Ok(())
+ }
+}
+
+impl<T: Serialize + Deref> Serialize for Gc<T> {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ self.deref().serialize(s)
+ }
+}
+
+impl<T: Serialize + Deref> Serialize for Rc<T> {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ self.deref().serialize(s)
+ }
+}
+
+impl Serialize for Position {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ s.write(VarInt(self.row))?;
+ s.write(VarInt(self.col))?;
+ Ok(())
+ }
+}
+
+impl Serialize for Chunk {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ self.constants.serialize(s)?;
+ self.code.serialize(s)?;
+ self.pos.serialize(s)?;
+ Ok(())
+ }
+}
+
+impl Serialize for Value {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ use Value as V;
+ match self {
+ V::Nil => {
+ s.write(0u8)?;
+ },
+ V::Bool(b) => {
+ s.write(1u8)?;
+ s.write(*b)?;
+ },
+ V::Int(i) => {
+ s.write(2u8)?;
+ s.write(*i)?;
+ },
+ V::Float(f) => {
+ s.write(3u8)?;
+ s.write(*f)?;
+ },
+ V::Ratio(r) => {
+ s.write(4u8)?;
+ s.write(*r.numer())?;
+ s.write(*r.denom())?;
+ },
+ V::Complex(c) => {
+ s.write(5u8)?;
+ s.write(c.re)?;
+ s.write(c.im)?;
+ },
+ V::Regex(r) => {
+ s.write(6u8)?;
+ s.write(r.to_string())?;
+ },
+ V::String(str) => {
+ s.write(7u8)?;
+ s.write(str.to_string())?;
+ },
+ V::List(l) => {
+ s.write(8u8)?;
+ l.serialize(s)?;
+ },
+ V::Matrix(m) => {
+ s.write(9u8)?;
+ s.write(m.domain)?;
+ s.write(m.codomain)?;
+ m.values.serialize(s)?;
+ },
+ V::Table(t) => {
+ s.write(10u8)?;
+ s.write(VarInt(t.len()))?;
+ for (key, value) in t.entries() {
+ key.serialize(s)?;
+ value.serialize(s)?;
+ }
+ },
+ V::Function(f) => {
+ s.write(11u8)?;
+ f.serialize(s)?;
+ },
+ V::Range(r) => {
+ s.write(12u8)?;
+ s.write(r.0)?;
+ s.write(r.1)?;
+ s.write(r.2)?;
+ },
+ V::Iter(f) => {
+ s.write(13u8)?;
+ f.serialize(s)?;
+ },
+ V::File(_) => return Err(error!("cannot compile file")),
+ V::Exception(_) => return Err(error!("cannot compile exception")),
+ };
+ Ok(())
+ }
+}
+
+impl Serialize for Function {
+ fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> {
+ s.write(self.name.to_string())?;
+ s.write(self.arity)?;
+ s.write(self.variadic)?;
+ use InnerFunction as F;
+ match &self.fun {
+ F::Compiled(c) => {
+ c.serialize(s)?;
+ },
+ F::Native(_) => return Err(error!("cannot compile native function")),
+ };
+ Ok(())
+ }
+}
diff --git a/matrix/src/chunk.rs b/matrix-lang/src/chunk.rs
index 495b787..2fc3d9e 100644
--- a/matrix/src/chunk.rs
+++ b/matrix-lang/src/chunk.rs
@@ -1,5 +1,5 @@
-use crate::{value::Value, ast::{UnaryOp, BinaryOp}, vm::{Vm, StackFrame}, Result, lex::Position};
-use std::{fmt::{Debug, Display}, rc::Rc};
+use std::fmt::{Debug, Display};
+use crate::prelude::*;
#[derive(Clone, Default)]
pub struct Chunk {
@@ -18,53 +18,6 @@ impl Chunk {
}
}
-impl Debug for Chunk {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "Chunk({})", self.code.len())
- }
-}
-
-impl Display for Chunk {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- writeln!(f, "constants: ")?;
- for (i, c) in self.constants.iter().enumerate() {
- writeln!(f, " {i:04}: {c}")?;
- }
- writeln!(f, "code:")?;
- for (i, ins) in self.code.iter().enumerate() {
- writeln!(f, " {i:04}: {ins}")?;
- }
- Ok(())
- }
-}
-
-pub struct Function {
- pub name: Rc<str>,
- pub arity: usize,
- pub variadic: bool,
- pub fun: InnerFunction
-}
-
-#[derive(Clone)]
-pub enum InnerFunction {
- Compiled(Rc<Chunk>),
- Native(Rc<dyn Fn((&mut Vm, &mut StackFrame), Vec<Value>) -> Result<Value>>),
-}
-
-impl Debug for Function {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use InnerFunction as F;
- match self.fun {
- F::Compiled(_) => {
- write!(f, "[Function {}]", self.name)
- },
- F::Native(_) => {
- write!(f, "[NativeFunction {}]", self.name)
- }
- }
- }
-}
-
#[derive(Clone, Debug)]
#[repr(align(4))]
pub enum Instruction {
@@ -113,6 +66,26 @@ pub enum Instruction {
Return,
}
+impl Debug for Chunk {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[Chunk {}]", self.code.len())
+ }
+}
+
+impl Display for Chunk {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ writeln!(f, "constants: ")?;
+ for (i, c) in self.constants.iter().enumerate() {
+ writeln!(f, " {i:04}: {c}")?;
+ }
+ writeln!(f, "code:")?;
+ for (i, ins) in self.code.iter().enumerate() {
+ writeln!(f, " {i:04}: {ins}")?;
+ }
+ Ok(())
+ }
+}
+
impl Display for Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Instruction::*;
diff --git a/matrix/src/compiler.rs b/matrix-lang/src/compiler.rs
index 6b6a94b..95c6ccf 100644
--- a/matrix/src/compiler.rs
+++ b/matrix-lang/src/compiler.rs
@@ -1,14 +1,14 @@
-use std::{fmt::Display, rc::Rc, cell::RefCell};
-use crate::{ast::{Expr, ExprData, AstName}, chunk::{Function, Instruction, InnerFunction}, chunk::{Chunk, self}, value::Value, Result, lex::Position};
+use crate::prelude::*;
use Instruction as I;
use Value as V;
use ExprData as E;
pub type NamesTable = Rc<RefCell<Vec<Rc<str>>>>;
+pub type GlobalsTable = Rc<RefCell<Vec<Global>>>;
pub struct CompilerBuilder<'c> {
- globals: NamesTable,
+ globals: GlobalsTable,
names: NamesTable,
repl: bool,
debug: bool,
@@ -39,7 +39,7 @@ impl<'c> CompilerBuilder<'c> {
self
}
- pub fn globals(mut self, globals: NamesTable) -> Self {
+ pub fn globals(mut self, globals: GlobalsTable) -> Self {
self.globals = globals;
self
}
@@ -81,9 +81,9 @@ pub struct Compiler<'c> {
name: Rc<str>,
parent: Option<&'c Compiler<'c>>,
- locals: Vec<Rc<Local>>,
- globals: Rc<RefCell<Vec<Rc<str>>>>,
- names: Rc<RefCell<Vec<Rc<str>>>>,
+ locals: Vec<Local>,
+ globals: GlobalsTable,
+ names: NamesTable,
root_is_block: bool,
@@ -97,50 +97,25 @@ pub struct Compiler<'c> {
debug: bool,
}
+#[derive(Clone)]
struct Local {
name: Rc<str>,
idx: usize,
- scope: usize
-}
-
-#[derive(Debug, Clone)]
-pub enum InnerError {
- Undefined(Rc<str>),
- Redefined(Rc<str>),
- InvAssign(Expr),
- InvContinue,
- InvBreak,
- NotImplemented(&'static str),
-}
-
-#[derive(Debug, Clone)]
-pub struct Error {
- pos: Position,
- err: InnerError,
+ scope: usize,
+ is_const: bool,
}
-impl std::error::Error for self::Error {}
-
-impl Display for self::Error {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use InnerError as E;
- write!(f, "parse failed at {}:{}, ", self.pos.row, self.pos.col)?;
- match &self.err {
- E::Undefined(name) => write!(f, "value {name} is undefined"),
- E::Redefined(name) => write!(f, "cannot redefine {name} in the same scope"),
- E::InvAssign(expr) => write!(f, "cannot assign to {expr:?}"),
- E::InvContinue => write!(f, "cannot continue outside a loop"),
- E::InvBreak => write!(f, "cannot break outside a loop"),
- E::NotImplemented(str) => write!(f, "{str} is not implemented yet")
- }
- }
+#[derive(Clone)]
+pub struct Global {
+ pub name: Rc<str>,
+ pub idx: usize,
+ pub is_const: bool,
}
-fn error<T>(err: InnerError, pos: Position) -> Result<T> {
- Err(self::Error {
- pos,
- err
- }.into())
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(COMPILE_EXCEPTION, $($arg)*)
+ };
}
impl<'c> Compiler<'c> {
@@ -185,35 +160,35 @@ impl<'c> Compiler<'c> {
};
}
- fn create_local(&mut self, name: Rc<str>) {
- let local = Local { name, idx: self.locals.len(), scope: self.scopes.len()};
- self.locals.push(Rc::new(local));
+ fn create_local(&mut self, name: Rc<str>, is_const: bool) -> Local {
+ let local = Local { name, idx: self.locals.len(), scope: self.scopes.len(), is_const };
+ self.locals.push(local.clone());
+ local
}
- fn create_global(&mut self, name: Rc<str>) -> usize {
- self.globals.borrow_mut().push(name);
- let c = self.globals.borrow().len() - 1;
- c
+ fn create_global(&mut self, name: Rc<str>, is_const: bool) -> Global {
+ let global = Global { name, idx: self.globals.borrow().len(), is_const };
+ self.globals.borrow_mut().push(global.clone());
+ global
}
- fn create_local_checked(&mut self, name: Rc<str>, pos: Position) -> Result<()> {
+ fn create_local_checked(&mut self, name: Rc<str>, is_const: bool, pos: Position) -> Result<Local> {
if let Some(local) = self.find_local(&name) {
if local.scope == self.scopes.len() {
- return error(InnerError::Redefined(name), pos)
+ return Err(error!("redefined {name}").pos(pos))
}
};
- self.create_local(name);
- Ok(())
+ Ok(self.create_local(name, is_const))
}
- fn create_global_checked(&mut self, name: Rc<str>, pos: Position) -> Result<usize> {
+ fn create_global_checked(&mut self, name: Rc<str>, is_const: bool, pos: Position) -> Result<Global> {
if let Some(_) = self.find_global(&name) {
- return error(InnerError::Redefined(name).into(), pos)
+ return Err(error!("redefined {name}").pos(pos))
}
- Ok(self.create_global(name))
+ Ok(self.create_global(name, is_const))
}
- fn find_local(&self, name: &str) -> Option<Rc<Local>> {
+ fn find_local(&self, name: &str) -> Option<Local> {
for local in self.locals.iter().rev() {
if local.name.as_ref() == name {
return Some(local.clone())
@@ -222,13 +197,13 @@ impl<'c> Compiler<'c> {
None
}
- fn find_global(&self, name: &str) -> Option<usize> {
+ fn find_global(&self, name: &str) -> Option<Global> {
if let Some(parent) = self.parent {
return parent.find_global(name)
}
- for (i, global) in self.globals.borrow().iter().enumerate() {
- if global.as_ref() == name {
- return Some(i)
+ for global in self.globals.borrow().iter() {
+ if global.name.as_ref() == name {
+ return Some(global.clone())
}
}
None
@@ -294,7 +269,7 @@ impl<'c> Compiler<'c> {
let chunk = self.compile_function(name.clone(), params, body)?;
let arity = params.len() - if *varadic { 1 } else { 0 };
let fun = Value::Function(Rc::new(
- chunk::Function {
+ Function {
name: name.0.clone(),
arity,
fun: InnerFunction::Compiled(chunk.into()),
@@ -304,10 +279,10 @@ impl<'c> Compiler<'c> {
self.emit_const(fun, expr.pos);
self.emit(I::Dup, expr.pos);
if self.can_make_globals() {
- let idx = self.create_global_checked(name.0.clone(), name.1)?;
- self.emit(I::StoreGlobal(idx as u16), expr.pos);
+ let global = self.create_global_checked(name.0.clone(), false, name.1)?;
+ self.emit(I::StoreGlobal(global.idx as u16), expr.pos);
} else {
- self.create_local_checked(name.0.clone(), name.1)?;
+ self.create_local_checked(name.0.clone(), false, name.1)?;
self.emit(I::CreateLocal, expr.pos);
}
},
@@ -316,7 +291,7 @@ impl<'c> Compiler<'c> {
let chunk = self.compile_function(name.clone(), params, body)?;
let arity = params.len() - if *varadic { 1 } else { 0 };
let fun = Value::Function(Rc::new(
- chunk::Function {
+ Function {
name: name.0.clone(),
arity,
fun: InnerFunction::Compiled(chunk.into()),
@@ -341,7 +316,7 @@ impl<'c> Compiler<'c> {
let jmpidx2 = self.emit_temp(expr.pos);
self.re_emit(I::Try(self.cur()), jmpidx);
self.begin_scope();
- self.create_local(err.0.clone());
+ self.create_local(err.0.clone(), true);
self.emit(I::CreateLocal, err.1);
self.compile_expr(catch)?;
self.end_scope();
@@ -378,7 +353,7 @@ impl<'c> Compiler<'c> {
let jumpidx = self.emit_temp(expr.pos);
self.loop_top.push((top as usize, self.scopes.len()));
self.begin_scope();
- self.create_local(name.0.clone());
+ self.create_local(name.0.clone(), true);
self.emit(I::CreateLocal, name.1);
self.compile_expr(expr)?;
self.emit(I::Discard(1), expr.pos);
@@ -407,10 +382,21 @@ impl<'c> Compiler<'c> {
self.compile_expr(expr)?;
self.emit(I::Dup, expr.pos);
if self.can_make_globals() {
- let global = self.create_global_checked(name.0.clone(), name.1)?;
- self.emit(I::StoreGlobal(global as u16), expr.pos);
+ let global = self.create_global_checked(name.0.clone(), false, name.1)?;
+ self.emit(I::StoreGlobal(global.idx as u16), expr.pos);
+ } else {
+ self.create_local_checked(name.0.clone(), false, name.1)?;
+ self.emit(I::CreateLocal, expr.pos);
+ }
+ },
+ E::Const(name, expr) => {
+ self.compile_expr(expr)?;
+ self.emit(I::Dup, expr.pos);
+ if self.can_make_globals() {
+ let global = self.create_global_checked(name.0.clone(), true, name.1)?;
+ self.emit(I::StoreGlobal(global.idx as u16), expr.pos);
} else {
- self.create_local_checked(name.0.clone(), name.1)?;
+ self.create_local_checked(name.0.clone(), true, name.1)?;
self.emit(I::CreateLocal, expr.pos);
}
},
@@ -420,7 +406,7 @@ impl<'c> Compiler<'c> {
self.collapse_scopes(scope);
self.emit(I::Jump(top as u16), expr.pos);
} else {
- return error(InnerError::InvContinue, expr.pos)
+ return Err(error!("invalid continue outside loop").pos(expr.pos))
}
},
E::Break => {
@@ -430,7 +416,7 @@ impl<'c> Compiler<'c> {
let tmpidx = self.emit_temp(expr.pos);
self.loop_bot.push(tmpidx);
} else {
- return error(InnerError::InvBreak, expr.pos)
+ return Err(error!("invalid break outside loop").pos(expr.pos))
}
},
E::Return(expr) => {
@@ -444,9 +430,9 @@ impl<'c> Compiler<'c> {
} else if let Some(local) = self.find_local(name) {
self.emit(I::LoadLocal(local.idx as u16), expr.pos);
} else if let Some(global) = self.find_global(name) {
- self.emit(I::LoadGlobal(global as u16), expr.pos);
+ self.emit(I::LoadGlobal(global.idx as u16), expr.pos);
} else {
- return error(InnerError::Undefined(name.clone()), expr.pos)
+ return Err(error!("variable '{name}' is undefined").pos(expr.pos))
};
},
E::Assign(lhs, rhs) => {
@@ -455,14 +441,20 @@ impl<'c> Compiler<'c> {
match &lhs.data {
E::Ident(name) if name.as_ref() != "_" => {
if let Some(local) = self.find_local(&name) {
+ if local.is_const {
+ return Err(error!("cannot assign to const '{name}'").pos(lhs.pos))
+ }
self.emit(I::StoreLocal(local.idx as u16), lhs.pos);
} else if let Some(global) = self.find_global(&name) {
- self.emit(I::StoreGlobal(global as u16), lhs.pos);
+ if global.is_const {
+ return Err(error!("cannot assign to const '{name}'").pos(lhs.pos))
+ }
+ self.emit(I::StoreGlobal(global.idx as u16), lhs.pos);
} else if self.can_make_globals() {
- let global = self.create_global_checked(name.clone(), lhs.pos)?;
- self.emit(I::StoreGlobal(global as u16), lhs.pos);
+ let global = self.create_global_checked(name.clone(), false, lhs.pos)?;
+ self.emit(I::StoreGlobal(global.idx as u16), lhs.pos);
} else {
- self.create_local_checked(name.clone(), lhs.pos)?;
+ self.create_local_checked(name.clone(), false, lhs.pos)?;
self.emit(I::CreateLocal, lhs.pos);
}
},
@@ -478,7 +470,7 @@ impl<'c> Compiler<'c> {
let name = self.get_name(ident.0.clone());
self.emit(I::StoreField(name as u16), expr.pos);
}
- _ => return error(InnerError::InvAssign(*lhs.clone()), lhs.pos)
+ _ => return Err(error!("assignment to {lhs} is not allowed").pos(lhs.pos))
}
}
E::UnaryOp(expr, op) => {
@@ -554,7 +546,7 @@ impl<'c> Compiler<'c> {
fn compile_function(&mut self, name: AstName, params: &Vec<AstName>, body: &Box<Expr>) -> Result<Chunk> {
let mut compiler = self.child(name.0);
for (name, pos) in params {
- compiler.create_local(name.clone());
+ compiler.create_local(name.clone(), false);
compiler.emit(I::CreateLocal, *pos);
}
compiler.compile_expr(body)?;
@@ -611,7 +603,7 @@ impl<'c> Compiler<'c> {
};
if self.loop_bot.len() > 0 {
- return error(InnerError::InvBreak, pos)
+ return Err(error!("invalid break outside loop").pos(pos))
}
if self.debug {
diff --git a/matrix/src/lex.rs b/matrix-lang/src/lex.rs
index 8a07234..b2487ad 100644
--- a/matrix/src/lex.rs
+++ b/matrix-lang/src/lex.rs
@@ -1,6 +1,5 @@
-use std::{rc::Rc, fmt::Debug};
-use regex::Regex;
-use crate::Result;
+use std::fmt::{Debug, Display};
+use crate::prelude::*;
pub struct RegexToken {
regex: Regex
@@ -30,6 +29,36 @@ impl From<RegexToken> for Regex {
}
}
+#[derive(Debug, Clone, PartialEq, Eq, Copy)]
+pub struct Position {
+ pub row: usize,
+ pub col: usize,
+}
+
+impl Default for Position {
+ fn default() -> Self {
+ Self { row: 1, col: 1 }
+ }
+}
+
+impl Display for Position {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}:{}", self.row, self.col)
+ }
+}
+
+impl Display for TokenData {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{self:?}")
+ }
+}
+
+impl Display for Token {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.data)
+ }
+}
+
#[derive(Debug, PartialEq)]
pub enum TokenData {
//syntax
@@ -106,6 +135,7 @@ pub enum TokenData {
Else,
While,
Let,
+ Const,
Function,
True,
False,
@@ -133,48 +163,6 @@ pub struct Token {
pub blen: usize,
}
-#[derive(Debug)]
-pub enum Error {
- UnexpectedCharacter(char),
- ExpectedChar(char, char),
- InvalidCodepoint,
- UnexpectedEof,
- InvalidDigit(char),
- InvalidStringEscape(char),
- InvalidRegex(anyhow::Error),
- InvalidNumber(String),
-}
-
-impl std::fmt::Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use Error::*;
- match self {
- UnexpectedCharacter(char) => write!(f, "Unexpected char: '{char}'"),
- UnexpectedEof => write!(f, "Unexpected end of file"),
- ExpectedChar(expected, got) => write!(f, "Expected char: '{expected}', instead got: '{got}'"),
- InvalidCodepoint => write!(f, "Invalid codepoint"),
- InvalidDigit(char) => write!(f, "Invalid digit: '{char}'"),
- InvalidStringEscape(char) => write!(f, "Invalid string escape: '\\{char}"),
- InvalidRegex(err) => write!(f, "{err}"),
- InvalidNumber(num) => write!(f, "Invalid number: '{num}'")
- }
- }
-}
-
-impl std::error::Error for Error {}
-
-#[derive(Debug, Clone, PartialEq, Eq, Copy)]
-pub struct Position {
- pub row: usize,
- pub col: usize,
-}
-
-impl Default for Position {
- fn default() -> Self {
- Self { row: 1, col: 1 }
- }
-}
-
pub struct Lexer {
pub index: usize,
len: usize,
@@ -203,6 +191,12 @@ impl<T: Into<String>> From<T> for Lexer {
}
}
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(PARSE_EXCEPTION, $($arg)*)
+ };
+}
+
impl Lexer {
pub fn new<T: Into<String>>(input: T) -> Self {
let data: Vec<char> = input.into().chars().collect();
@@ -239,7 +233,7 @@ impl Lexer {
fn next_not_eof(&mut self) -> Result<char> {
let c = self.next();
if c == '\0' {
- return Err(Error::UnexpectedEof.into())
+ return Err(error!("unexpected end of file"))
}
Ok(c)
}
@@ -247,7 +241,7 @@ impl Lexer {
fn next_expect(&mut self, expected: char) -> Result<char> {
let c = self.next();
if c != expected {
- return Err(Error::ExpectedChar(expected, c).into())
+ return Err(error!("expected character '{c}'"))
}
Ok(c)
}
@@ -259,7 +253,6 @@ impl Lexer {
}
fn lex_string(&mut self, delimit: char) -> Result<Rc<str>> {
- use Error::*;
let mut buf = String::new();
@@ -291,8 +284,8 @@ impl Lexer {
let n1 = self.next_not_eof()?;
let n2 = self.next_not_eof()?;
buf.push(char::from_u32(
- n1.to_digit(16).ok_or(InvalidDigit(n1))? * 16 +
- n2.to_digit(16).ok_or(InvalidDigit(n2))?
+ n1.to_digit(16).ok_or(error!("invalid digit '{n1}'"))? * 16 +
+ n2.to_digit(16).ok_or(error!("invalid digit '{n2}'"))?
).unwrap());
},
'u' => {
@@ -302,15 +295,15 @@ impl Lexer {
let c = self.next_not_eof()?;
if c == '}' { break }
if n >= 0x1000_0000_u32 {
- return Err(InvalidCodepoint.into())
+ return Err(error!("invalid utf8 codepoint '{n}'"))
}
- n = n * 16 + c.to_digit(16).ok_or::<crate::Error>(InvalidDigit(c).into())?;
+ n = n * 16 + c.to_digit(16).ok_or(error!("invalid digit '{c}'"))?;
}
- let ch = char::from_u32(n).ok_or::<crate::Error>(InvalidCodepoint.into())?;
+ let ch = char::from_u32(n).ok_or(error!("invalid codepoint '{n}'"))?;
buf.push(ch);
},
- _ => return Err(InvalidStringEscape(next).into())
+ _ => return Err(error!("invalid string escape '\\{next}'"))
}
}
@@ -318,13 +311,12 @@ impl Lexer {
}
fn lex_ident(&mut self, initial: char) -> Result<TokenData> {
- use Error as E;
use TokenData as T;
let mut buf = std::string::String::new();
if !initial.is_initial_ident() {
- return Err(E::UnexpectedCharacter(initial).into())
+ return Err(error!("unexpected character '{initial}'"))
}
buf.push(initial);
@@ -342,6 +334,7 @@ impl Lexer {
"else" => T::Else,
"while" => T::While,
"let" => T::Let,
+ "const" => T::Const,
"fn" | "function" => T::Function,
"true" => T::True,
"false" => T::False,
@@ -364,7 +357,6 @@ impl Lexer {
fn lex_radix(&mut self, radix: i64, radix_char: char) -> Result<TokenData> {
use TokenData as T;
- use Error as E;
let mut n = 0i64;
let mut char_found = false;
@@ -375,7 +367,7 @@ impl Lexer {
n = n * radix + (i as i64);
char_found = true;
} else if self.peek().is_ident() {
- return Err(E::InvalidDigit(self.peek()).into())
+ return Err(error!("invalid digit '{}'", self.peek()))
} else {
break;
}
@@ -384,13 +376,11 @@ impl Lexer {
if char_found {
Ok(T::Int(n))
} else {
- Err(E::InvalidNumber(format!("0{radix_char}")).into())
+ Err(error!("invalid number radix specifier '0{radix_char}'"))
}
}
fn lex_number(&mut self, initial: char) -> Result<TokenData> {
- use Error as E;
-
if initial == '0' {
match self.peek() {
'x' => {
@@ -459,7 +449,7 @@ impl Lexer {
}
if self.peek().is_ident() {
- return Err(E::UnexpectedCharacter(self.peek()).into())
+ return Err(error!("unexpected character '{}'", self.peek()))
}
if let Ok(int) = buf.parse::<i64>() {
@@ -478,23 +468,11 @@ impl Lexer {
return Ok(T::Float(float))
}
- Err(E::InvalidNumber(buf).into())
+ Err(error!("invalid number '{buf}'"))
}
- fn peek_token_impl(&mut self, ignore_newlines: bool) -> Result<Token> {
- let idx = self.index;
- let pos = self.pos;
- let bidx = self.byte_len;
- let token = self.next_token_impl(ignore_newlines);
- self.index = idx;
- self.pos = pos;
- self.byte_len = bidx;
- token
- }
-
- fn next_token_impl(&mut self, ignore_newlines: bool) -> Result<Token> {
+ fn read_token(&mut self, ignore_newlines: bool) -> Result<Token> {
use TokenData as T;
- use Error as E;
self.skip_whitespace(ignore_newlines);
@@ -705,7 +683,7 @@ impl Lexer {
self.next();
T::Regex(regex::Regex::new(&self.lex_string(next)?)
.map(|e| e.into())
- .map_err(|e| E::InvalidRegex(e.into()))?)
+ .map_err(|e| error!("invalid regex: '{e}'"))?)
}
_ => {
self.lex_ident(char)?
@@ -744,7 +722,6 @@ impl Lexer {
let str_end = self.index;
let byte_end = self.byte_len;
let str = self.data[str_start..str_end].to_owned().into_iter().collect();
-
Ok(Token {
data,
pos,
@@ -754,19 +731,47 @@ impl Lexer {
})
}
- pub fn peek_token(&mut self) -> Result<Token> {
- self.peek_token_impl(true)
+ pub fn next_token(&mut self) -> Result<Token> {
+ let pos = self.pos;
+ match self.read_token(true) {
+ Ok(token) => Ok(token),
+ Err(e) => Err(e.pos(pos)),
+ }
}
- pub fn next_token(&mut self) -> Result<Token> {
- self.next_token_impl(true)
+ pub fn next_token_nl(&mut self) -> Result<Token> {
+ let pos = self.pos;
+ match self.read_token(false) {
+ Ok(token) => Ok(token),
+ Err(e) => Err(e.pos(pos)),
+ }
}
- pub fn peek_token_nl(&mut self) -> Result<Token> {
- self.peek_token_impl(false)
+ pub fn peek_token(&mut self) -> Result<Token> {
+ let idx = self.index;
+ let pos = self.pos;
+ let bidx = self.byte_len;
+ let token = self.read_token(true);
+ self.index = idx;
+ self.pos = pos;
+ self.byte_len = bidx;
+ match token {
+ Ok(token) => Ok(token),
+ Err(e) => Err(e.pos(pos)),
+ }
}
- pub fn next_token_nl(&mut self) -> Result<Token> {
- self.next_token_impl(false)
+ pub fn peek_token_nl(&mut self) -> Result<Token> {
+ let idx = self.index;
+ let pos = self.pos;
+ let bidx = self.byte_len;
+ let token = self.read_token(false);
+ self.index = idx;
+ self.pos = pos;
+ self.byte_len = bidx;
+ match token {
+ Ok(token) => Ok(token),
+ Err(e) => Err(e.pos(pos)),
+ }
}
}
diff --git a/matrix-lang/src/lib.rs b/matrix-lang/src/lib.rs
new file mode 100644
index 0000000..1452a09
--- /dev/null
+++ b/matrix-lang/src/lib.rs
@@ -0,0 +1,42 @@
+mod compiler;
+mod value;
+mod lex;
+mod vm;
+mod parse;
+mod chunk;
+mod ast;
+mod binary;
+
+pub mod prelude;
+
+#[macro_export]
+macro_rules! iter {
+ ($fn:expr) => {
+ $crate::prelude::Value::Iter(
+ ::std::rc::Rc::new(
+ $crate::prelude::Function {
+ name: ::std::rc::Rc::from("<iterator>"),
+ arity: 0,
+ variadic: false,
+ fun: $crate::prelude::InnerFunction::Native(
+ ::std::rc::Rc::new($fn
+ ))}))
+ };
+}
+
+#[macro_export]
+macro_rules! native {
+ ($name:expr, $arity:expr, $varadic:expr, $fn:expr) => {
+ $crate::prelude::Value::Function(
+ ::std::rc::Rc::new( $crate::prelude::Function {
+ name: std::rc::Rc::from($name),
+ arity: $arity,
+ variadic: $varadic,
+ fun: $crate::prelude::InnerFunction::Native(
+ ::std::rc::Rc::new($fn)
+ )
+ })
+ )
+ }
+}
+
diff --git a/matrix/src/parse.rs b/matrix-lang/src/parse.rs
index d967130..3a4c5f2 100644
--- a/matrix/src/parse.rs
+++ b/matrix-lang/src/parse.rs
@@ -1,6 +1,4 @@
-use std::{fmt::Display, rc::Rc};
-use num_complex::Complex64;
-use crate::{lex::{Lexer, self, Token, TokenData, Position}, ast::{Expr, BinaryOp, UnaryOp, optimize, ExprData, AstName}, value::{Value, self}, Result};
+use crate::prelude::*;
use Value as V;
use ExprData as E;
@@ -33,38 +31,6 @@ pub struct Parser {
optimize: bool
}
-#[derive(Debug)]
-pub enum Error {
- LexerError(crate::lex::Error),
- UnexpectedToken(Token),
- ExpectedToken(TokenData, Position),
- MatrixInvDomain(usize, usize, usize),
- NotAssignable(Expr),
- ValueError(value::Error),
-}
-
-impl Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use Error::*;
- match self {
- LexerError(err) => write!(f, "{err}"),
- UnexpectedToken(tok) => write!(f, "Unexpected token: '{:?}' at {}:{}", tok.data, tok.pos.row, tok.pos.col),
- ExpectedToken(tok, pos) => write!(f, "Expected token: '{tok:?}' at {}:{}", pos.row, pos.col),
- MatrixInvDomain(row, should, was) => write!(f, "In row {row} of matrix, domain was expected to be {should} but was given {was}"),
- NotAssignable(expr) => write!(f, "{expr:?} is not assignable"),
- ValueError(err) => write!(f, "{err}"),
- }
- }
-}
-
-impl From<lex::Error> for Error {
- fn from(value: lex::Error) -> Self {
- Self::LexerError(value)
- }
-}
-
-impl std::error::Error for Error {}
-
macro_rules! expr_parser {
($parser:ident, $pattern:pat, $fn:ident) => {{
let mut expr = $parser.$fn()?;
@@ -99,12 +65,18 @@ macro_rules! expr_parser_reverse {
}};
}
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(PARSE_EXCEPTION, $($arg)*)
+ };
+}
+
impl Parser {
fn force_token(&mut self, tok: TokenData) -> Result<TokenData> {
let next = self.lexer.next_token()?;
if next.data != tok {
- Err(Error::ExpectedToken(tok, next.pos).into())
+ Err(error!("expected token '{tok}'").pos(next.pos))
} else {
Ok(tok)
}
@@ -113,7 +85,7 @@ impl Parser {
fn force_token_nl(&mut self, tok: TokenData) -> Result<TokenData> {
let next = self.lexer.next_token_nl()?;
if next.data != tok {
- Err(Error::ExpectedToken(tok, next.pos).into())
+ Err(error!("expected token '{tok}'").pos(next.pos))
} else {
Ok(tok)
}
@@ -135,7 +107,7 @@ impl Parser {
match next.data {
T::Comma => continue,
T::RightParen => break,
- _ => return Err(Error::UnexpectedToken(next).into())
+ _ => return Err(error!("unexpected token '{next}'").pos(next.pos))
};
}
Ok(params)
@@ -157,7 +129,7 @@ impl Parser {
match next.data {
T::SemiColon => continue,
T::RightBrack => break,
- _ => return Err(Error::UnexpectedToken(next).into())
+ _ => return Err(error!("unexpected token '{next}'").pos(next.pos))
};
}
Ok(indicies)
@@ -193,7 +165,7 @@ impl Parser {
match next.data {
T::SemiColon => continue,
T::RightBrack => break,
- _ => return Err(Error::UnexpectedToken(next).into()),
+ _ => return Err(error!("unexpected token '{next}'").pos(next.pos))
};
}
if parts.len() == 1 {
@@ -201,9 +173,9 @@ impl Parser {
} else {
let codomain = parts.len();
let domain = parts[0].len();
- for (i, part) in parts.iter().enumerate() {
+ for part in parts.iter() {
if part.len() != domain {
- return Err(Error::MatrixInvDomain(i, domain, part.len()).into())
+ return Err(error!("matrix row domains do not match: {} != {}", domain, part.len()).pos(pos))
}
}
let mut data = Vec::new();
@@ -225,7 +197,7 @@ impl Parser {
},
T::Ident(ident) => (E::Literal(V::String(ident.to_string().into())), tok.pos).into(),
T::String(string) => (E::Literal(V::String(string.to_string().into())), tok.pos).into(),
- _ => return Err(Error::UnexpectedToken(tok).into())
+ t => return Err(error!("unexpected token '{t}'").pos(tok.pos))
})
}
@@ -247,7 +219,7 @@ impl Parser {
match next.data {
T::Comma => continue,
T::RightBrace => break,
- _ => return Err(Error::UnexpectedToken(next).into())
+ _ => return Err(error!("unexpected token '{next}'").pos(next.pos))
}
}
Ok((E::Table(table), pos).into())
@@ -273,7 +245,7 @@ impl Parser {
}
}
T::LeftParen => (),
- _ => return Err(Error::UnexpectedToken(tok).into()),
+ t => return Err(error!("unexpected token '{t}'").pos(tok.pos))
}
let mut params = Vec::new();
@@ -295,7 +267,7 @@ impl Parser {
}
T::Comma => continue,
T::RightParen => break,
- _ => return Err(Error::UnexpectedToken(next).into()),
+ _ => return Err(error!("unexpected token '{next}'").pos(next.pos))
}
}
@@ -307,7 +279,7 @@ impl Parser {
if let T::Ident(ident) = next.data {
Ok((ident, next.pos))
} else {
- Err(Error::UnexpectedToken(next).into())
+ Err(error!("unexpected token '{next}'").pos(next.pos))
}
}
@@ -327,7 +299,7 @@ impl Parser {
if let T::Ident(ident) = next.data {
Ok((ident, next.pos))
} else {
- Err(Error::UnexpectedToken(next).into())
+ Err(error!("unexpected token '{next}'").pos(next.pos))
}
}
@@ -419,6 +391,15 @@ impl Parser {
}
}
+ fn parse_const(&mut self) -> Result<Expr> {
+ let pos = self.lexer.peek_token()?.pos;
+ self.force_token(T::Const)?;
+ let ident = self.parse_ident_nl()?;
+ self.force_token(T::Assign)?;
+ let expr = self.parse_expr()?;
+ Ok((E::Const(ident, Box::new(expr)), pos).into())
+ }
+
fn parse_return(&mut self) -> Result<Expr> {
let pos = self.lexer.peek_token()?.pos;
self.force_token(T::Return)?;
@@ -431,7 +412,10 @@ impl Parser {
self.force_token(T::LeftBrace)?;
loop {
let expr = match self.lexer.peek_token()?.data {
- T::RightBrace => break,
+ T::RightBrace => {
+ self.lexer.next_token()?;
+ break
+ },
T::SemiColon => {
self.lexer.next_token()?;
continue;
@@ -443,12 +427,9 @@ impl Parser {
match next.data {
T::SemiColon => continue,
T::RightBrace => break,
- _ => return Err(Error::ExpectedToken(T::SemiColon, next.pos).into())
+ _ => return Err(error!("expected a semicolon").pos(next.pos))
}
}
- if self.lexer.peek_token()?.data == T::RightBrace {
- self.lexer.next_token()?;
- }
Ok((E::Block(block), pos).into())
}
@@ -474,7 +455,7 @@ impl Parser {
T::True => E::Literal(V::Bool(true)),
T::False => E::Literal(V::Bool(false)),
T::Ident(ident) => E::Ident(ident),
- _ => return Err(Error::UnexpectedToken(tok).into()),
+ t => return Err(error!("unexpected token '{t}'").pos(tok.pos))
};
Ok((data, tok.pos).into())
}
@@ -488,6 +469,7 @@ impl Parser {
While => self.parse_while(),
For => self.parse_for(),
Let => self.parse_let(),
+ Const => self.parse_const(),
LeftBrace => self.parse_block(),
Return => self.parse_return(),
If => self.parse_if(),
@@ -752,11 +734,11 @@ impl Parser {
};
let expr = self.parse_expr()?;
block.push(expr);
- let next = self.lexer.next_token()?;
+ let next = self.lexer.next_token_nl()?;
match next.data {
T::Eof => break,
T::SemiColon => continue,
- _ => return Err(Error::ExpectedToken(T::SemiColon, next.pos).into())
+ _ => return Err(error!("expected a semicolon").pos(next.pos))
};
}
Ok((E::Block(block), Position::default()).into())
diff --git a/matrix-lang/src/prelude.rs b/matrix-lang/src/prelude.rs
new file mode 100644
index 0000000..c5af0c8
--- /dev/null
+++ b/matrix-lang/src/prelude.rs
@@ -0,0 +1,60 @@
+pub type Result<T> = std::result::Result<T, Exception>;
+
+pub use crate::value::Value as Value;
+pub use crate::value::exception::Exception as Exception;
+pub use crate::value::matrix::Matrix as Matrix;
+pub use crate::value::gc::Gc as Gc;
+pub use crate::value::hash::ValueMap as ValueMap;
+pub use crate::value::function::Function as Function;
+pub use crate::value::function::InnerFunction as InnerFunction;
+
+pub use num_complex::Complex64 as Complex64;
+pub use num_rational::Rational64 as Rational64;
+pub use regex::Regex as Regex;
+pub use std::fs::File as File;
+
+pub use std::rc::Rc as Rc;
+pub use std::cell::RefCell as RefCell;
+
+pub use crate::exception as exception;
+pub use crate::native as native;
+pub use crate::iter as iter;
+
+pub use crate::value::exception::HASH_EXCEPTION as HASH_EXCEPTION;
+pub use crate::value::exception::VALUE_EXCEPTION as VALUE_EXCEPTION;
+pub use crate::value::exception::PARSE_EXCEPTION as PARSE_EXCEPTION;
+pub use crate::value::exception::COMPILE_EXCEPTION as COMPILE_EXCEPTION;
+pub use crate::value::exception::RUNTIME_EXCEPTION as RUNTIME_EXCEPTION;
+pub use crate::value::exception::BINARY_EXECPTION as BINARY_EXCEPTION;
+pub use crate::value::exception::IO_EXECPTION as IO_EXCEPTION;
+
+pub use crate::value::clone::ValueClone as ValueClone;
+pub use crate::value::hash::TryHash as TryHash;
+
+pub use crate::vm::Vm as Vm;
+pub use crate::vm::StackFrame as StackFrame;
+pub use crate::vm::Interupt as Interupt;
+
+pub use crate::lex::Lexer as Lexer;
+pub use crate::lex::Position as Position;
+pub use crate::lex::Token as Token;
+pub use crate::lex::TokenData as TokenData;
+pub use crate::parse::Parser as Parser;
+pub use crate::parse::ParserBuilder as ParserBuilder;
+pub use crate::compiler::Compiler as Compiler;
+pub use crate::compiler::CompilerBuilder as CompilerBuilder;
+pub use crate::compiler::NamesTable as NamesTable;
+pub use crate::compiler::GlobalsTable as GlobalsTable;
+pub use crate::compiler::Global as Global;
+
+pub use crate::ast::AstName as AstName;
+pub use crate::ast::Expr as Expr;
+pub use crate::ast::ExprData as ExprData;
+pub use crate::ast::BinaryOp as BinaryOp;
+pub use crate::ast::UnaryOp as UnaryOp;
+pub use crate::ast::optimize as optimize;
+
+pub use crate::chunk::Chunk as Chunk;
+pub use crate::chunk::Instruction as Instruction;
+
+pub use crate::binary::Program as Program;
diff --git a/matrix-lang/src/value/clone.rs b/matrix-lang/src/value/clone.rs
new file mode 100644
index 0000000..d5ac983
--- /dev/null
+++ b/matrix-lang/src/value/clone.rs
@@ -0,0 +1,54 @@
+use crate::prelude::*;
+
+pub trait ValueClone {
+ fn deep_clone(&self) -> Self;
+ fn shallow_clone(&self) -> Self;
+}
+
+impl ValueClone for Value {
+ fn deep_clone(&self) -> Self {
+ use Value as V;
+ match self {
+ V::List(l) => V::List(l.deep_clone()),
+ V::Table(t) => V::Table(t.deep_clone()),
+ V::Matrix(m) => V::Matrix(m.deep_clone()),
+ _ => self.clone()
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ use Value as V;
+ match self {
+ V::List(l) => V::List(l.shallow_clone()),
+ V::Table(t) => V::Table(t.shallow_clone()),
+ V::Matrix(m) => V::Matrix(m.shallow_clone()),
+ _ => self.clone()
+ }
+ }
+}
+
+impl ValueClone for Vec<Value> {
+ fn deep_clone(&self) -> Self {
+ let mut vals = Vec::new();
+ for val in self {
+ vals.push(val.deep_clone())
+ }
+ vals
+ }
+
+ fn shallow_clone(&self) -> Self {
+ self.clone()
+ }
+}
+
+impl ValueClone for Matrix {
+ fn deep_clone(&self) -> Self {
+ let values = self.values.deep_clone();
+ Self::new(self.domain, self.codomain, values)
+ }
+
+ fn shallow_clone(&self) -> Self {
+ let values = self.values.shallow_clone();
+ Self::new(self.domain, self.codomain, values)
+ }
+}
diff --git a/matrix-lang/src/value/comp.rs b/matrix-lang/src/value/comp.rs
new file mode 100644
index 0000000..3557927
--- /dev/null
+++ b/matrix-lang/src/value/comp.rs
@@ -0,0 +1,373 @@
+use std::{ops::{Add, Sub, Mul, Div, Shl, Shr, BitOr, BitAnd, BitXor, Neg, Not}, cmp::Ordering};
+use crate::prelude::*;
+
+fn ratio_to_f64(r: Rational64) -> f64 {
+ *r.numer() as f64 / *r.denom() as f64
+}
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(VALUE_EXCEPTION, $($arg)*)
+ };
+}
+
+///
+/// MATH OPERATIONS
+///
+
+fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> {
+ Ok(match (n, d, p) {
+ (0, _, 0) => Err(error!("cannot exponent 0 ** 0"))?,
+ (0, _, _) => (0, 1),
+ (_, _, 0) => (1, 1),
+ (1, 1, _) => (1, 1),
+ (n, d, p) if p < 0 => (d.pow((-p) as u32), n.pow((-p) as u32)),
+ (n, d, p) => (n.pow(p as u32), d.pow(p as u32)),
+ })
+}
+
+fn promote(a: Value, b: Value) -> (Value, Value) {
+ use Value as V;
+ match (&a, &b) {
+ (V::Int(x), V::Ratio(..)) => (V::Ratio((*x).into()), b),
+ (V::Int(x), V::Float(..)) => (V::Float(*x as f64), b),
+ (V::Int(x), V::Complex(..)) => (V::Complex((*x as f64).into()), b),
+ (V::Ratio(x), V::Float(..)) => (V::Float(ratio_to_f64(*x)), b),
+ (V::Ratio(x), V::Complex(..)) => (V::Complex(ratio_to_f64(*x).into()), b),
+ (V::Float(x), V::Complex(..)) => (V::Complex((*x).into()), b),
+ (V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())),
+ (V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)),
+ (V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())),
+ (V::Float(..), V::Ratio(y)) => (a, V::Float(ratio_to_f64(*y))),
+ (V::Complex(..), V::Ratio(y)) => (a, V::Complex(ratio_to_f64(*y).into())),
+ (V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())),
+ (V::List(l1), V::List(l2)) if l1.len() > 0 && l2.len() > 0
+ => (V::Matrix(Matrix::from_list(l1.to_vec()).into()), V::Matrix(Matrix::from_list(l2.to_vec()).into())),
+ (_, V::List(l)) if l.len() > 0
+ => (a, V::Matrix(Matrix::from_list(l.to_vec()).into())),
+ (V::List(l), _) if l.len() > 0
+ => (V::Matrix(Matrix::from_list(l.to_vec()).into()), b),
+ _ => (a, b),
+ }
+}
+
+
+impl Add for Value {
+ type Output = Result<Self>;
+ fn add(self, rhs: Self) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x + y)),
+ (Float(x), Float(y)) => Ok(Float(x + y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x + y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x + y)),
+ (Matrix(x), Matrix(y)) => Ok(Matrix((x + y)?.into())),
+ (Matrix(x), r) => Ok(Matrix(x.increment(r)?.into())),
+ (l, Matrix(y)) => Ok(Matrix(y.increment(l)?.into())),
+ (String(str), value) => Ok(String(Rc::from(
+ format!("{str}{value}")
+ ))),
+ (value, String(str)) => Ok(String(Rc::from(
+ format!("{value}{str}")
+ ))),
+ (List(mut l1), List(l2)) => {
+ l1.extend_from_slice(&l2);
+ Ok(List(l1))
+ },
+ (l, r) => Err(error!("cannot add {l:?} + {r:?}"))
+ }
+ }
+}
+
+impl Sub for Value {
+ type Output = Result<Self>;
+ fn sub(self, rhs: Self) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x - y)),
+ (Float(x), Float(y)) => Ok(Float(x - y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x - y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x - y)),
+ (Matrix(x), Matrix(y)) => Ok(Matrix((x - y)?.into())),
+ (Matrix(x), r) => Ok(Matrix(x.decrement(r)?.into())),
+ (l, r) => Err(error!("cannot subtract {l:?} - {r:?}"))
+ }
+ }
+}
+
+impl Mul for Value {
+ type Output = Result<Self>;
+ fn mul(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x * y)),
+ (Float(x), Float(y)) => Ok(Float(x * y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x * y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x * y)),
+ (Matrix(x), Matrix(y)) => Ok(Matrix((x * y)?.into())),
+ (Matrix(x), r) => Ok(Matrix(x.scale(r)?.into())),
+ (l, Matrix(y)) => Ok(Matrix(y.scale(l)?.into())),
+ (l, r) => Err(error!("cannot multiply {l:?} * {r:?}"))
+ }
+ }
+}
+
+impl Div for Value {
+ type Output = Result<Self>;
+ fn div(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(_), Int(0)) => Err(error!("cannot divide by zero")),
+ (Int(x), Int(y)) => Ok(Ratio(Rational64::new(x, y))),
+ (Float(x), Float(y)) => Ok(Float(x / y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x / y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x / y)),
+ (l, r) => Err(error!("cannot divide {l:?} / {r:?}"))
+ }
+ }
+}
+
+impl BitOr for Value {
+ type Output = Result<Self>;
+ fn bitor(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x | y)),
+ (l, r) => Err(error!("cannot bitwise or {l:?} | {r:?}"))
+ }
+ }
+}
+
+impl BitAnd for Value {
+ type Output = Result<Self>;
+ fn bitand(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x & y)),
+ (l, r) => Err(error!("cannot bitwise and {l:?} & {r:?}"))
+ }
+ }
+}
+
+impl BitXor for Value {
+ type Output = Result<Self>;
+ fn bitxor(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x ^ y)),
+ (l, r) => Err(error!("cannot bitwise xor {l:?} ^ {r:?}"))
+ }
+ }
+}
+
+impl Shl for Value {
+ type Output = Result<Self>;
+ fn shl(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x << y)),
+ (l, r) => Err(error!("cannot bitwise shift left {l:?} << {r:?}"))
+ }
+ }
+}
+
+impl Shr for Value {
+ type Output = Result<Self>;
+ fn shr(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x >> y)),
+ (l, r) => Err(error!("cannot bitwise shift right {l:?} >> {r:?}"))
+ }
+ }
+}
+
+impl PartialEq for Value {
+ fn eq(&self, other: &Self) -> bool {
+ use Value::*;
+ match (self, other) {
+ (Nil, Nil) => true,
+ (Bool(a), Bool(b)) => a == b,
+ (Int(a), Int(b)) => *a == *b,
+ (Ratio(a), Ratio(b)) => *a == *b,
+ (Float(a), Float(b)) => *a == *b,
+ (Complex(a), Complex(b)) => *a == *b,
+ (Int(a), Ratio(b)) => Rational64::from(*a) == *b,
+ (Ratio(a), Int(b)) => *a == Rational64::from(*b),
+ (Int(a), Float(b)) => *a as f64 == *b,
+ (Float(a), Int(b)) => *a == *b as f64,
+ (Int(a), Complex(b)) => Complex64::from(*a as f64) == *b,
+ (Complex(a), Int(b)) => *a == Complex64::from(*b as f64),
+ (Ratio(a), Float(b)) => ratio_to_f64(*a) == *b,
+ (Float(a), Ratio(b)) => *a == ratio_to_f64(*b),
+ (Ratio(a), Complex(b)) => Complex64::from(ratio_to_f64(*a)) == *b,
+ (Complex(a), Ratio(b)) => *a == Complex64::from(ratio_to_f64(*b)),
+ (Float(a), Complex(b)) => Complex64::from(*a) == *b,
+ (Complex(a), Float(b)) => *a == Complex64::from(*b),
+ (String(a), String(b)) => *a == *b,
+ (List(a), List(b)) => *a == *b,
+ (Matrix(a), Matrix(b)) => a == b,
+ _ => false,
+ }
+ }
+}
+
+impl PartialOrd for Value {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ use Value::*;
+ match (self, other) {
+ (Nil, Nil) => Some(Ordering::Equal),
+ (Bool(a), Bool(b)) => a.partial_cmp(b),
+ (Int(a), Int(b)) => a.partial_cmp(b),
+ (Ratio(a), Ratio(b)) => a.partial_cmp(b),
+ (Float(a), Float(b)) => a.partial_cmp(b),
+ (Int(a), Ratio(b)) => Rational64::from(*a).partial_cmp(b),
+ (Ratio(a), Int(b)) => a.partial_cmp(&Rational64::from(*b)),
+ (Int(a), Float(b)) => (*a as f64).partial_cmp(b),
+ (Float(a), Int(b)) => a.partial_cmp(&(*b as f64)),
+ (Ratio(a), Float(b)) => ratio_to_f64(*a).partial_cmp(b),
+ (Float(a), Ratio(b)) => a.partial_cmp(&ratio_to_f64(*b)),
+ (String(a), String(b)) => a.partial_cmp(b),
+ (List(a), List(b)) => a.partial_cmp(b),
+ (Matrix(a), Matrix(b)) => a.values.partial_cmp(&b.values),
+ _ => None,
+ }
+ }
+}
+
+impl Neg for Value {
+ type Output = Value;
+
+ fn neg(self) -> Self::Output {
+ use Value::*;
+ match self {
+ Bool(b) => Bool(!b),
+ Int(i) => Int(-i),
+ Float(f) => Float(-f),
+ Ratio(r) => Ratio(-r),
+ Complex(c) => Complex(-c),
+ _ => return Float(f64::NAN)
+ }
+ }
+}
+
+impl Not for Value {
+ type Output = bool;
+
+ fn not(self) -> Self::Output {
+ use Value as V;
+ match self {
+ V::Nil => true,
+ V::Bool(b) => !b,
+ V::Int(i) => i == 0,
+ V::Float(f) => f == 0.0,
+ V::Ratio(r) => *(r.numer()) == 0 || *(r.denom()) == 0,
+ V::Complex(c) => !c.is_normal(),
+ V::Regex(_) => false,
+ V::List(_) => false,
+ V::Matrix(_) => false,
+ V::Table(_) => false,
+ V::String(s) => s.as_ref() == "",
+ V::Function(_) => false,
+ V::Iter(_) => false,
+ V::Range(_) => false,
+ V::File(_) => false,
+ V::Exception(_) => false,
+ }
+ }
+}
+
+
+impl Value {
+
+ pub fn modulo(self, rhs: Value) -> Result<Self> {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x % y)),
+ (Float(x), Float(y)) => Ok(Float(x % y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x % y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x % y)),
+ (l, r) => Err(error!("cannot modulo: {l:?} % {r:?}"))
+ }
+ }
+
+ pub fn pow(self, rhs: Value) -> Result<Self> {
+ use Value::*;
+ if let (Ratio(x), Int(y)) = (&self, &rhs) {
+ return Ok(Ratio(ipow(*(*x).numer(), *(*x).denom(), *y)?.into()));
+ }
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Ratio(ipow(x, 1, y)?.into())),
+ (Float(x), Float(y)) => Ok(Float(x.powf(y))),
+ (Ratio(x), Ratio(y)) => Ok(Float(ratio_to_f64(x).powf(ratio_to_f64(y)))),
+ (Complex(x), Complex(y)) => Ok(Complex(x.powc(y))),
+ (l, r) => Err(error!("cannot exponent: {l:?} ** {r:?}"))
+ }
+ }
+
+ pub fn floaty(self) -> Self {
+ use Value as V;
+ match self {
+ V::Int(i) => V::Float(i as f64),
+ V::Ratio(r) => V::Float(ratio_to_f64(r)),
+ a => a
+ }
+ }
+
+ pub fn is_zero(&self) -> bool {
+ use Value as V;
+ match self {
+ V::Int(i) => *i == 0,
+ V::Float(f) => *f == 0.0 || *f == -0.0,
+ V::Ratio(r) => *r.numer() == 0,
+ _ => false,
+ }
+ }
+
+ pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
+ use BinaryOp::*;
+ match op {
+ Add => lhs + rhs,
+ Subtract => lhs - rhs,
+ Multiply => lhs * rhs,
+ Divide => lhs / rhs,
+ Modulo => lhs.modulo(rhs),
+ Power => lhs.pow(rhs),
+ BitwiseAnd => lhs & rhs,
+ BitwiseOr => lhs | rhs,
+ BitwiseXor => lhs ^ rhs,
+ BitwiseShiftLeft => lhs << rhs,
+ BitwiseShiftRight => lhs >> rhs,
+ Equals => Ok(Self::Bool(lhs == rhs)),
+ NotEquals => Ok(Self::Bool(lhs != rhs)),
+ GreaterEquals => Ok(Self::Bool(lhs >= rhs)),
+ LessEquals => Ok(Self::Bool(lhs <= rhs)),
+ GreaterThan => Ok(Self::Bool(lhs > rhs)),
+ LessThan => Ok(Self::Bool(lhs < rhs)),
+ Range | RangeEq => {
+ let Value::Int(lhs) = lhs else {
+ return Err(error!("range can only take [Int]'s"))
+ };
+ let Value::Int(rhs) = rhs else {
+ return Err(error!("range can only take [Int]'s"))
+ };
+ Ok(Self::Range(Rc::new((lhs, rhs, op == RangeEq))))
+ },
+ }
+ }
+
+ pub fn unary_op(op: UnaryOp, val: Value) -> Value {
+ use UnaryOp::*;
+ match op {
+ Negate => -val,
+ Not => Self::Bool(!val),
+ }
+ }
+
+ pub fn to_regex(value: &str) -> Result<Self> {
+ match Regex::new(value) {
+ Ok(r) => Ok(Self::Regex(r.into())),
+ Err(e) => Err(error!("{e}")),
+ }
+ }
+}
diff --git a/matrix-lang/src/value/exception.rs b/matrix-lang/src/value/exception.rs
new file mode 100644
index 0000000..0df6f5c
--- /dev/null
+++ b/matrix-lang/src/value/exception.rs
@@ -0,0 +1,78 @@
+use std::{fmt::{Debug, Display}, error::Error};
+use crate::prelude::*;
+
+#[macro_export]
+macro_rules! exception {
+ ($type:expr) => {
+ $crate::prelude::Exception::new($type)
+ };
+ ($type:expr, $($arg:tt)*) => {
+ $crate::prelude::Exception::msg($type, format!($($arg)*).as_str())
+ };
+}
+
+pub const HASH_EXCEPTION: &'static str = "hash";
+pub const VALUE_EXCEPTION: &'static str = "value";
+pub const PARSE_EXCEPTION: &'static str = "parse";
+pub const COMPILE_EXCEPTION: &'static str = "compile";
+pub const RUNTIME_EXCEPTION: &'static str = "runtime";
+pub const BINARY_EXECPTION: &'static str = "binary";
+pub const IO_EXECPTION: &'static str = "io";
+
+#[derive(Clone)]
+pub struct Exception(Gc<ExceptionInner>);
+
+#[derive(Clone)]
+struct ExceptionInner {
+ ty: Rc<str>,
+ msg: Rc<str>,
+ trace: Vec<(Rc<str>, Position)>
+}
+
+impl Exception {
+ pub fn msg(ty: &str, msg: &str) -> Self {
+ Self(Gc::new(ExceptionInner { ty: ty.into(), msg: msg.into(), trace: Vec::new() }))
+ }
+
+ pub fn pos(mut self, pos: Position) -> Self {
+ self.0.trace.push((
+ Rc::from("<root>"),
+ pos
+ ));
+ self
+ }
+
+ pub fn trace(mut self, block: Rc<str>, pos: Position) -> Self {
+ self.0.trace.push((
+ block,
+ pos
+ ));
+ self
+ }
+}
+
+impl Display for Exception {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let ty = self.0.ty.as_ref();
+ let msg = self.0.msg.as_ref();
+ write!(f, "{}\n Type <{}>", msg, ty)?;
+ for (block, pos) in self.0.trace.iter() {
+ write!(f, "\n In {block} at {pos}\n")?;
+ }
+ Ok(())
+ }
+}
+
+impl Debug for Exception {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[Exception {}]", self.0.ty.as_ref())
+ }
+}
+
+impl Error for Exception {}
+
+impl<T> From<Exception> for Result<T> {
+ fn from(value: Exception) -> Self {
+ Err(value)
+ }
+}
diff --git a/matrix-lang/src/value/fmt.rs b/matrix-lang/src/value/fmt.rs
new file mode 100644
index 0000000..f276bf1
--- /dev/null
+++ b/matrix-lang/src/value/fmt.rs
@@ -0,0 +1,186 @@
+use std::fmt::{Debug, Display};
+use crate::prelude::*;
+
+use Value as V;
+
+impl Debug for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ V::Nil => write!(f, "[Nil]"),
+ V::Int(i) => write!(f, "[Int {i}]"),
+ V::Bool(b) => write!(f, "[Bool {b}]"),
+ V::Float(vf) => write!(f, "[Float {vf}]"),
+ V::Ratio(r) => write!(f, "[Ratio {r}]"),
+ V::Complex(c) => write!(f, "[Complex {c}]"),
+ V::Regex(r) => write!(f, "[Regex /{r}/]"),
+ V::String(s) => write!(f, "[String '{s}']"),
+ V::List(l) => write!(f, "[List {}]", l.len()),
+ V::Matrix(m) => write!(f, "[Matirx {}x{}]", m.domain, m.codomain),
+ V::Table(t) => write!(f, "[Table {}]", t.len()),
+ V::Function(vf) => write!(f, "[Function {}]", vf.name),
+ V::Range(r) => write!(f, "[Range {:?}..{:?}]", r.0, r.1),
+ V::Iter(_) => write!(f, "[Iterator]"),
+ V::Exception(_) => write!(f, "[Error]"),
+ V::File(_) => write!(f, "[File]"),
+ }
+ }
+}
+
+impl Display for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let red;
+ let green;
+ let yellow;
+ let blue;
+ let pink;
+ let cyan;
+ let clear;
+
+ if f.alternate() {
+ red = "\x1b[31m";
+ green = "\x1b[32m";
+ yellow = "\x1b[33m";
+ blue = "\x1b[34m";
+ pink = "\x1b[35m";
+ cyan = "\x1b[36m";
+ clear = "\x1b[0m";
+ } else {
+ red = "";
+ green = "";
+ yellow = "";
+ blue = "";
+ pink = "";
+ cyan = "";
+ clear = "";
+ }
+
+ match self {
+ V::Nil => {write!(f, "{blue}nil{clear}")?;},
+ V::Bool(b) => {write!(f, "{yellow}{b}{clear}")?;},
+ V::Int(i) => {write!(f, "{yellow}{i}{clear}")?;},
+ V::Float(l) => {write!(f, "{yellow}{l}{clear}")?;},
+ V::Ratio(r) => {write!(f, "{yellow}{r}{clear}")?;},
+ V::Complex(c) => {write!(f, "{yellow}{c}{clear}")?;},
+ V::Regex(r) => {write!(f, "/{red}{r}{clear}/")?;},
+ V::String(s) => {
+ if f.alternate() {
+ write!(f, "{green}'{s}'{clear}")?;
+ } else {
+ write!(f, "{s}")?;
+ }
+ }
+ V::List(l) => {
+ if l.len() < 1 {
+ write!(f, "[]")?;
+ return Ok(())
+ }
+ write!(f, "[ ")?;
+ for (i, el) in l.iter().enumerate() {
+ if i != 0 {
+ write!(f, " ")?;
+ }
+ if f.alternate() {
+ write!(f, "{el:#}")?;
+ } else {
+ write!(f, "{el}")?;
+ }
+ }
+ write!(f, " ]")?;
+ },
+ V::Matrix(m) => {
+ if f.alternate() {
+ write!(f, "{m:#}")?;
+ } else {
+ write!(f, "{m}")?;
+ }
+ },
+ V::Table(t) => {
+ if f.alternate() {
+ write!(f, "{t:#}")?;
+ } else {
+ write!(f, "{t}")?;
+ }
+ },
+ V::Function(fun) => {
+ write!(f, "{cyan}{fun}{clear}")?;
+ }
+ V::Range(r) => {
+ if f.alternate() {
+ write!(f, "{:#}..{:#}", r.0, r.1)?;
+ } else {
+ write!(f, "{}..{}", r.0, r.1)?;
+ }
+ }
+ V::Iter(_) => {write!(f, "{pink}[Iterator]{clear}")?;},
+ V::File(_) => {write!(f, "{pink}[File]{clear}")?;},
+ V::Exception(e) => {write!(f, "{red}{e}{clear}")?;},
+ };
+ Ok(())
+ }
+}
+
+impl Debug for Matrix {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[Matrix {}x{}]", self.domain, self.codomain)
+ }
+}
+
+impl Display for Matrix {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let mut max_cols = vec![0; self.domain];
+ let mut vals: Vec<String> = Vec::with_capacity(self.domain * self.codomain);
+ for row in 0..self.codomain {
+ for col in 0..self.domain {
+ let idx = col + row * self.domain;
+ let el = &self.values[idx];
+ let s = match f.alternate() {
+ true => format!("{:#}", el),
+ false => format!("{}", el)
+ };
+ max_cols[col] = max_cols[col].max(s.len());
+ vals.push(s);
+ }
+ }
+
+ write!(f, "\n")?;
+ for row in 0..self.codomain {
+ for col in 0..self.domain {
+ let idx = col + row * self.domain;
+ let s = vals[idx].as_str();
+ let width = max_cols[col];
+ write!(f, " {s:>width$}")?;
+ }
+ write!(f, "\n")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl Debug for ValueMap {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[Table {}]", self.len())
+ }
+}
+
+impl Display for ValueMap {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if self.len() < 1 {
+ write!(f, "{{}}")?;
+ return Ok(())
+ }
+ write!(f, "{{ ")?;
+ for (i, (key, value)) in self.entries().enumerate() {
+ if i != 0 {
+ write!(f, ", ")?;
+ }
+ if f.alternate() {
+ write!(f, "{key:#} = {value:#}")?
+ } else {
+ write!(f, "{key} = {value}")?
+ }
+ }
+ write!(f, " }}")?;
+ Ok(())
+ }
+}
diff --git a/matrix-lang/src/value/function.rs b/matrix-lang/src/value/function.rs
new file mode 100644
index 0000000..38d8b0b
--- /dev/null
+++ b/matrix-lang/src/value/function.rs
@@ -0,0 +1,43 @@
+use crate::prelude::*;
+use std::fmt::{Debug, Display};
+
+pub struct Function {
+ pub name: Rc<str>,
+ pub arity: usize,
+ pub variadic: bool,
+ pub fun: InnerFunction
+}
+
+#[derive(Clone)]
+pub enum InnerFunction {
+ Compiled(Rc<Chunk>),
+ Native(Rc<dyn Fn((&mut Vm, &mut StackFrame), Vec<Value>) -> Result<Value>>),
+}
+
+impl Debug for Function {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use InnerFunction as F;
+ match self.fun {
+ F::Compiled(_) => {
+ write!(f, "[Function {}]", self.name)
+ },
+ F::Native(_) => {
+ write!(f, "[Builtin {}]", self.name)
+ }
+ }
+ }
+}
+
+impl Display for Function {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use InnerFunction as F;
+ match self.fun {
+ F::Compiled(_) => {
+ write!(f, "[Function {}]", self.name)
+ },
+ F::Native(_) => {
+ write!(f, "[Builtin {}]", self.name)
+ }
+ }
+ }
+}
diff --git a/matrix/src/gc.rs b/matrix-lang/src/value/gc.rs
index 7af020b..5ef8b80 100644
--- a/matrix/src/gc.rs
+++ b/matrix-lang/src/value/gc.rs
@@ -1,4 +1,5 @@
use std::{ops::{Index, IndexMut, Deref, DerefMut, Add, Sub, Mul}, marker::PhantomData, ptr::NonNull, fmt::{Debug, Display}};
+use crate::prelude::*;
pub struct Gc<T> {
ptr: NonNull<GcInner<T>>,
@@ -24,22 +25,31 @@ impl<T> Gc<T> {
}
impl <T: Clone> Gc<T> {
- pub fn clone_inside(&self) -> Self {
+ pub fn into_inner(self) -> T {
unsafe {
- let data = self.ptr.as_ref().data.clone();
- Self::new(data)
+ self.ptr.as_ref().data.clone()
}
}
- pub fn into_inner(self) -> T {
+ fn data(&self) -> T {
unsafe {
self.ptr.as_ref().data.clone()
}
}
+}
- fn data(&self) -> T {
+impl <T: ValueClone> ValueClone for Gc<T> {
+ fn deep_clone(&self) -> Self {
unsafe {
- self.ptr.as_ref().data.clone()
+ let data = self.ptr.as_ref().data.deep_clone();
+ Self::new(data)
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ unsafe {
+ let data = self.ptr.as_ref().data.shallow_clone();
+ Self::new(data)
}
}
}
diff --git a/matrix-lang/src/value/hash.rs b/matrix-lang/src/value/hash.rs
new file mode 100644
index 0000000..35c1343
--- /dev/null
+++ b/matrix-lang/src/value/hash.rs
@@ -0,0 +1,240 @@
+use crate::prelude::*;
+use std::hash::{Hash, DefaultHasher, Hasher};
+
+#[derive(Clone)]
+pub struct ValueMap {
+ values: Vec<ValueEntry>,
+ size: usize,
+ used: usize,
+}
+
+#[derive(Clone)]
+enum ValueEntry {
+ Empty,
+ Taken((Value, Value)),
+ Gravestone(Value),
+}
+
+impl Default for ValueMap {
+ fn default() -> Self {
+ ValueMap {
+ values: vec![ValueEntry::Empty; 8],
+ size: 8,
+ used: 0,
+ }
+ }
+}
+
+impl ValueMap {
+
+ fn get_index(values: &Vec<ValueEntry>, size: usize, key: &Value, hash: usize) -> usize {
+ let mut nearest_grave = None;
+ let start = hash & size;
+ for offset in 0..size {
+ let idx = (start + offset) % size;
+ match &values[idx] {
+ ValueEntry::Empty => return idx,
+ ValueEntry::Taken((marker, _)) => {
+ if marker.eq(key) { return idx };
+ continue;
+ },
+ ValueEntry::Gravestone(grave) => {
+ if grave.eq(key) { return idx };
+ if nearest_grave.is_none() {
+ nearest_grave = Some(idx);
+ }
+ continue;
+ },
+ }
+ }
+
+ match nearest_grave {
+ Some(idx) => idx,
+ None => panic!("cannot get value map index: full!!!"),
+ }
+ }
+
+ fn expand(&mut self) -> Result<()> {
+ let pairs = self.values.iter()
+ .filter_map(|e| {
+ match e {
+ ValueEntry::Taken(s) => Some(s.clone()),
+ _ => None
+ }
+ })
+ .collect::<Vec<(Value, Value)>>();
+
+ let new_used = pairs.len();
+ let new_size = self.size * 2 + pairs.len();
+ let mut new_values = vec![ValueEntry::Empty; new_size];
+
+ for (key, value) in pairs.into_iter() {
+ let hash = self.hash(&key)?;
+ let idx = ValueMap::get_index(&new_values, new_size, &key, hash);
+ new_values[idx] = ValueEntry::Taken((key, value));
+ }
+
+ self.used = new_used;
+ self.size = new_size;
+ self.values = new_values;
+
+ Ok(())
+ }
+
+ fn hash(&self, key: &Value) -> Result<usize> {
+ let mut hasher = DefaultHasher::new();
+ key.try_hash(&mut hasher)?;
+ Ok(hasher.finish() as usize)
+ }
+
+ pub fn get<'a>(&'a self, key: &Value) -> Result<Option<&'a Value>> {
+ let hash = self.hash(key)?;
+ let idx = ValueMap::get_index(&self.values, self.size, key, hash);
+ match &self.values[idx] {
+ ValueEntry::Taken((_, value)) => Ok(Some(value)),
+ _ => Ok(None)
+ }
+ }
+
+ pub fn insert(&mut self, key: Value, value: Value) -> Result<()> {
+ if self.used * 3 >= self.size * 2 {
+ self.expand()?;
+ }
+ let key = key.deep_clone();
+ let hash = self.hash(&key)?;
+ let idx = ValueMap::get_index(&self.values, self.size, &key, hash);
+ self.values[idx] = ValueEntry::Taken((key, value));
+ self.used += 1;
+ Ok(())
+ }
+
+ pub fn remove(&mut self, key: &Value) -> Result<Option<Value>> {
+ let hash = self.hash(key)?;
+ let idx = ValueMap::get_index(&self.values, self.size, key, hash);
+ let mut value = ValueEntry::Gravestone(key.clone());
+ std::mem::swap(&mut value, &mut self.values[idx]);
+ match value {
+ ValueEntry::Taken((_, v)) => {
+ self.used -= 1;
+ Ok(Some(v))
+ }
+ _ => Ok(None),
+ }
+ }
+
+ pub fn entries<'a>(&'a self) -> ValueMapIterator<'a> {
+ ValueMapIterator::new(self)
+ }
+
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn len(&self) -> usize {
+ self.used
+ }
+}
+
+pub struct ValueMapIterator<'a> {
+ map: &'a ValueMap,
+ index: usize
+}
+
+impl<'a> ValueMapIterator<'a> {
+ fn new(map: &'a ValueMap) -> Self {
+ Self { map, index: 0 }
+ }
+}
+
+impl<'a> Iterator for ValueMapIterator<'a> {
+ type Item = (&'a Value, &'a Value);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut idx = self.index;
+ loop {
+ if idx >= self.map.size {
+ return None
+ }
+ use ValueEntry as E;
+ let E::Taken((k, v)) = &self.map.values[idx] else {
+ idx += 1;
+ continue;
+ };
+
+ self.index = idx + 1;
+ return Some((k, v))
+ }
+ }
+}
+
+pub trait TryHash {
+ fn try_hash<H: std::hash::Hasher>(&self, state: &mut H) -> Result<()>;
+}
+
+impl TryHash for Value {
+ fn try_hash<H: std::hash::Hasher>(&self, state: &mut H) -> Result<()> {
+ use Value::*;
+ match self {
+ Nil => 0x23845.hash(state),
+ Bool(b) => b.hash(state),
+ Int(i) => i.hash(state),
+ Ratio(r) => r.hash(state),
+ Regex(r) => r.as_str().hash(state),
+ String(s) => s.hash(state),
+ List(l) => {
+ for val in l.iter() {
+ val.try_hash(state)?;
+ }
+ }
+ Matrix(m) => {
+ m.domain.hash(state);
+ m.codomain.hash(state);
+ for val in m.values.iter() {
+ val.try_hash(state)?;
+ }
+ },
+ _ => return Err(exception!(HASH_EXCEPTION, "cannot hash {self:?}"))
+ };
+ Ok(())
+ }
+}
+
+impl ValueClone for ValueEntry {
+ fn deep_clone(&self) -> Self {
+ use ValueEntry as E;
+ match self {
+ E::Empty => E::Empty,
+ E::Taken((k, v)) => E::Taken((k.deep_clone(), v.deep_clone())),
+ E::Gravestone(g) => E::Gravestone(g.deep_clone()),
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ use ValueEntry as E;
+ match self {
+ E::Empty => E::Empty,
+ E::Taken((k, v)) => E::Taken((k.clone(), v.clone())),
+ E::Gravestone(g) => E::Gravestone(g.clone()),
+ }
+ }
+}
+
+impl ValueClone for ValueMap {
+ fn deep_clone(&self) -> Self {
+ let values = self.values.iter().map(|e| e.deep_clone()).collect();
+ Self {
+ values,
+ size: self.size,
+ used: self.used
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ let values = self.values.iter().map(|e| e.clone()).collect();
+ Self {
+ values,
+ size: self.size,
+ used: self.used
+ }
+ }
+}
diff --git a/matrix-lang/src/value/index.rs b/matrix-lang/src/value/index.rs
new file mode 100644
index 0000000..a5725e8
--- /dev/null
+++ b/matrix-lang/src/value/index.rs
@@ -0,0 +1,230 @@
+use std::cmp::Ordering;
+
+use crate::prelude::*;
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ Err(exception!(VALUE_EXCEPTION, $($arg)*))
+ };
+}
+
+impl Value {
+ pub fn val_cmp(&self, other: &Self) -> Result<Ordering> {
+ self.partial_cmp(other)
+ .map_or_else(|| error!("cannot compare: {self:?} and {other:?}"), Ok)
+ }
+
+ fn index_single(&self, index: &Value) -> Result<Self> {
+ use Value as V;
+ match (self, index) {
+ (V::Table(t), index) => {
+ Ok(t.get(index)?.unwrap_or(&Value::Nil).clone())
+ },
+ (V::List(l), V::Int(i)) => {
+ if *i < 0 || *i as usize >= l.len() {
+ return error!("{i} out of bounds for {self:?}")
+ }
+ Ok(l[*i as usize].clone())
+ },
+ (V::Matrix(m), V::Int(i)) => {
+ if *i < 0 || *i as usize >= m.values.len() {
+ return error!("{i} out of bounds for {self:?}")
+ }
+ Ok(m.values[*i as usize].clone())
+ },
+ _ => return error!("{index:?} cant index {self:?}")
+ }
+ }
+
+ fn index_multiple(&self, indexes: &Vec<Value>) -> Result<Self> {
+ use Value as V;
+ match self {
+ V::List(..) => {
+ let mut ret = Vec::new();
+ for index in indexes {
+ let res = self.index_single(index)?;
+ ret.push(res);
+ }
+ Ok(V::List(ret.into()))
+ }
+ V::Table(..) => {
+ let mut ret = ValueMap::new();
+ for index in indexes {
+ let res = self.index_single(index)?;
+ ret.insert(index.clone(), res)?;
+ }
+ Ok(V::Table(ret.into()))
+ }
+ V::Matrix(m) => {
+ let err = || error!("{self:?} can be index by [Int] or [Int;Int]");
+ if indexes.len() != 2 {
+ return err()
+ }
+ let lhs = indexes[0].clone();
+ let rhs = indexes[1].clone();
+ match (lhs, rhs) {
+ (V::Nil, V::Nil) => {
+ Ok(V::Matrix(m.shallow_clone()))
+ },
+ (V::Int(row), V::Nil) => {
+ let Some((_, row)) = m.rows().enumerate().filter(|(idx, _)| *idx as i64 == row).next() else {
+ return err();
+ };
+ let row: Vec<Value> = row.into_iter().map(|e| e.clone()).collect();
+ Ok(V::Matrix(Matrix::new(row.len(), 1, row).into()))
+ },
+ (V::Nil, V::Int(col)) => {
+ let Some((_, col)) = m.cols().enumerate().filter(|(idx, _)| *idx as i64 == col).next() else {
+ return err();
+ };
+ let col: Vec<Value> = col.into_iter().map(|e| e.clone()).collect();
+ Ok(V::Matrix(Matrix::new(1, col.len(), col).into()))
+ },
+ (V::Int(row), V::Int(col)) => {
+ if row < 0 || col < 0 {
+ return err();
+ }
+ m.get(row as usize, col as usize)
+ }
+ _ => return err()
+ }
+ }
+ _ => return error!("cannot index {self:?}")
+ }
+ }
+
+ pub fn index(&self, index: &Vec<Value>) -> Result<Self> {
+ if index.len() == 0 {
+ Ok(self.shallow_clone())
+ } else if index.len() == 1 {
+ self.index_single(&index[0])
+ } else {
+ self.index_multiple(index)
+ }
+ }
+
+ fn store_index_single(&mut self, index: &Value, store: Value) -> Result<()> {
+ use Value as V;
+ let err = format!("{self:?}");
+ match (self, index) {
+ (V::Table(t), index) => {
+ t.insert(index.clone(), store)
+ },
+ (V::List(l), V::Int(i)) => {
+ if *i < 0 || *i as usize >= l.len() {
+ return error!("{i} out of bounds for {err}")
+ }
+ l[*i as usize] = store;
+ Ok(())
+ },
+ (V::Matrix(m), V::Int(i)) => {
+ if *i < 0 || *i as usize >= m.values.len() {
+ return error!("{i} out of bounds for {err}")
+ }
+ m.values[*i as usize] = store;
+ Ok(())
+ },
+ _ => return error!("{index:?} cant index {err}")
+ }
+ }
+
+ fn store_index_multiple(&mut self, indexes: &Vec<Value>, store: Value) -> Result<()> {
+ use Value as V;
+ match self {
+ V::List(..) => {
+ for index in indexes {
+ self.store_index_single(index, store.clone())?;
+ }
+ Ok(())
+ }
+ V::Table(..) => {
+ for index in indexes {
+ self.store_index_single(index, store.clone())?;
+ }
+ Ok(())
+ }
+ _ => return error!("cannot index {self:?}")
+ }
+ }
+
+ pub fn store_index(&mut self, index: &Vec<Value>, store: Value) -> Result<()> {
+ if index.len() == 0 {
+ Ok(())
+ } else if index.len() == 1 {
+ self.store_index_single(&index[0], store)
+ } else {
+ self.store_index_multiple(index, store)
+ }
+ }
+
+ pub fn store_field_access(&mut self, ident: &str, val: Value) -> Result<()> {
+ use Value as V;
+ match self {
+ V::Table(t) => {
+ let key = V::String(Rc::from(ident));
+ Ok(t.insert(key, val)?)
+ },
+ _ => return error!("cannot field access assign {self:?}")
+ }
+ }
+
+ pub fn field_access(&self, ident: &str) -> Result<Self> {
+ use Value as V;
+ match self {
+ V::Table(t) => {
+ let key = V::String(Rc::from(ident));
+ Ok(t.get(&key)?.unwrap_or(&V::Nil).clone())
+ },
+ _ => return error!("cannot field access {self:?}")
+ }
+ }
+
+}
+
+impl Value {
+
+ pub fn into_iter_fn(self) -> Result<Rc<Function>> {
+ let Value::Iter(iter) = self.into_iter()? else {
+ return error!("bypassed iter check")
+ };
+ Ok(iter)
+ }
+
+ pub fn into_iter(self) -> Result<Self> {
+ use Value as V;
+ Ok(match self {
+ V::Iter(..) => self,
+ V::List(l) => {
+ let iter = RefCell::new(l.into_inner().into_iter());
+ iter!(move |_,_| {
+ match iter.borrow_mut().next() {
+ Some(v) => Ok(v),
+ None => Ok(V::Nil),
+ }
+ })
+ },
+ V::Range(r) => {
+ let r = (*r).clone();
+ let lhs = RefCell::new(r.0);
+ let rhs = r.1;
+ iter!(move |_,_| {
+ let val = *lhs.borrow();
+ let next = *lhs.borrow() + 1;
+ if (!r.2 && *lhs.borrow() < rhs) || (r.2 && *lhs.borrow() <= rhs) {
+ *lhs.borrow_mut() = next;
+ return Ok(Value::Int(val))
+ }
+ Ok(Value::Nil)
+ })
+ },
+ V::Function(f) => {
+ if f.arity > 0 || f.variadic {
+ return error!("iterator functions cannot be varadic or take arguments")
+ }
+ V::Iter(f)
+ },
+ val => return error!("cannot turn {val:?} into an iterator")
+ })
+ }
+}
+
diff --git a/matrix-lang/src/value/matrix.rs b/matrix-lang/src/value/matrix.rs
new file mode 100644
index 0000000..91e3ec2
--- /dev/null
+++ b/matrix-lang/src/value/matrix.rs
@@ -0,0 +1,337 @@
+use std::ops::{Add, Sub, Mul};
+
+use crate::prelude::*;
+
+#[derive(Clone)]
+pub struct Matrix {
+ pub domain: usize,
+ pub codomain: usize,
+ pub values: Vec<Value>
+}
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(VALUE_EXCEPTION, $($arg)*)
+ };
+}
+
+impl Matrix {
+ pub fn new(
+ domain: usize,
+ codomain: usize,
+ values: Vec<Value>
+ ) -> Self {
+ Self {
+ domain,
+ codomain,
+ values
+ }
+ }
+
+ pub fn from_list(
+ values: Vec<Value>
+ ) -> Self {
+ Self {
+ domain: values.len(),
+ codomain: 1,
+ values
+ }
+ }
+
+ pub fn empty(
+ domain: usize,
+ codomain: usize
+ ) -> Self {
+ let values = (0..(domain * codomain)).into_iter()
+ .map(|_| Value::Int(0))
+ .collect();
+ Self {
+ domain,
+ codomain,
+ values
+ }
+ }
+
+ pub fn get(&self, row: usize, col: usize) -> Result<Value> {
+ if row >= self.codomain || col >= self.domain {
+ return Err(error!("[{};{}] out of bounds for [Matrix {}x{}]", row, col, self.domain, self.codomain))
+ }
+ let idx = col + row * self.domain;
+ Ok(self.values[idx].clone())
+ }
+
+
+
+ pub fn set(&mut self, row: usize, col: usize, val: Value) -> Result<()> {
+ if row >= self.codomain || col >= self.domain {
+ return Err(error!("[{};{}] out of bounds for [Matrix {}x{}]", row, col, self.domain, self.codomain))
+ }
+ let idx = col + row * self.domain;
+ self.values[idx] = val;
+ Ok(())
+ }
+
+ pub fn rows<'a>(&'a self) -> MatrixRows<'a> {
+ MatrixRows {
+ matrix: self,
+ row: 0
+ }
+ }
+
+ pub fn cols<'a>(&'a self) -> MatrixCols<'a> {
+ MatrixCols {
+ matrix: self,
+ col: 0
+ }
+ }
+
+ // SPLCIE DOMAIN
+ pub fn splice_cols(&self, col_start: usize, col_end: usize) -> Result<Self> {
+ if col_start <= col_end || col_end > self.domain {
+ return Err(error!("[_;{}..{}] invalid for [Matrix {}x{}]", col_start, col_end, self.domain, self.codomain))
+ }
+
+ let mut cols = Vec::new();
+
+ for (i, col) in self.cols().enumerate() {
+ if i >= col_start && i < col_end {
+ cols.push(col);
+ }
+ }
+
+ let domain = cols.len();
+ let codomain = cols[0].len();
+ let mut res = Self::empty(domain, codomain);
+
+ for i in 0..domain {
+ for j in 0..codomain {
+ res.set(j, i, cols[i][j].clone())?;
+ }
+ }
+
+ Ok(res)
+ }
+
+ // SPLICE CODOMAIN
+ pub fn splice_rows(&self, row_start: usize, row_end: usize) -> Result<Self> {
+ if row_start <= row_end || row_end > self.codomain {
+ return Err(error!("[{}..{};_] invalid for [Matrix {}x{}]", row_start, row_end, self.domain, self.codomain))
+ }
+
+ let mut rows = Vec::new();
+
+ for (i, row) in self.rows().enumerate() {
+ if i >= row_start && i < row_end {
+ rows.push(row);
+ }
+ }
+
+ let domain = rows[0].len();
+ let codomain = rows.len();
+ let mut res = Self::empty(domain, codomain);
+
+ for i in 0..domain {
+ for j in 0..codomain {
+ res.set(j, i, rows[j][i].clone())?;
+ }
+ }
+
+ Ok(res)
+ }
+
+ pub fn increment(&self, increment: Value) -> Result<Self> {
+ let values = self.values.iter()
+ .map(|v| v.clone() + increment.clone())
+ .collect::<Result<Vec<Value>>>()?;
+ Ok(Matrix::new(self.domain, self.codomain, values))
+ }
+
+ pub fn decrement(&self, decrement: Value) -> Result<Self> {
+ let values = self.values.iter()
+ .map(|v| v.clone() - decrement.clone())
+ .collect::<Result<Vec<Value>>>()?;
+ Ok(Matrix::new(self.domain, self.codomain, values))
+ }
+
+ pub fn scale(&self, scale: Value) -> Result<Self> {
+ let values = self.values.iter()
+ .map(|v| v.clone() * scale.clone())
+ .collect::<Result<Vec<Value>>>()?;
+ Ok(Matrix::new(self.domain, self.codomain, values))
+ }
+
+ pub fn join_right(&self, other: &Matrix) -> Result<Self> {
+ if self.codomain != other.codomain {
+ return Err(error!("matrix codomain's do not match"))
+ }
+ let mut r1 = self.rows();
+ let mut r2 = other.rows();
+ let mut rows = Vec::new();
+ loop {
+ let Some(r1) = r1.next() else { break; };
+ let Some(r2) = r2.next() else { break; };
+
+ let mut row = r1
+ .into_iter()
+ .map(|v| v.clone())
+ .collect::<Vec<Value>>();
+
+ row.extend(r2.into_iter().map(|v| v.clone()));
+
+ rows.push(row);
+ }
+
+ let values = rows
+ .into_iter()
+ .reduce(|mut a,b| {a.extend(b); a})
+ .unwrap();
+
+ Ok(Matrix::new(self.domain + other.domain, self.codomain, values))
+ }
+
+ pub fn join_bottom(&self, other: &Matrix) -> Result<Self> {
+ if self.domain != other.domain {
+ return Err(error!("matrix domain's do not match"))
+ }
+ let mut values = self.values.clone();
+ values.extend(other.values.clone());
+ Ok(Matrix::new(self.domain, self.codomain + other.codomain, values))
+ }
+}
+
+impl PartialEq for Matrix {
+ fn eq(&self, other: &Self) -> bool {
+ if self.domain != other.domain || self.codomain != other.codomain {
+ return false
+ }
+
+ for i in 0..self.values.len() {
+ if self.values[i] != other.values[i] {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+impl Add for Matrix {
+ type Output = Result<Self>;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ if self.domain != rhs.domain || self.codomain != rhs.codomain {
+ return Err(error!("cannot add {self:?} + {rhs:?}"))
+ }
+ let mut res = Matrix::empty(self.domain, self.codomain);
+ for col in 0..self.domain {
+ for row in 0..self.codomain {
+ let add = self.get(row, col)? + rhs.get(row, col)?;
+ res.set(row, col, add?)?;
+ }
+ }
+ Ok(res)
+ }
+}
+
+impl Sub for Matrix {
+ type Output = Result<Self>;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ if self.domain != rhs.domain || self.codomain != rhs.codomain {
+ return Err(error!("cannot subtract {self:?} - {rhs:?}"))
+ }
+ let mut res = Matrix::empty(self.domain, self.codomain);
+ for col in 0..self.domain {
+ for row in 0..self.codomain {
+ let sub = self.get(row, col)? - rhs.get(row, col)?;
+ res.set(row, col, sub?)?;
+ }
+ }
+ Ok(res)
+ }
+}
+
+fn dot(lhs: Vec<&Value>, rhs: Vec<&Value>) -> Result<Value> {
+ let len = lhs.len();
+
+ let mut res = Value::Int(0);
+ for i in 0..len {
+ let val = (lhs[i].clone() * rhs[i].clone())?;
+ res = (res + val)?;
+ }
+
+ Ok(res)
+}
+
+impl Mul for Matrix {
+ type Output = Result<Self>;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ if self.domain != rhs.codomain {
+ return Err(error!("cannot multiply {self:?} * {rhs:?}"))
+ }
+ let mut res = Self::empty(rhs.domain, self.codomain);
+ for (i, row) in self.rows().enumerate() {
+ for (j, col) in rhs.cols().enumerate() {
+ let dot = dot(row.clone(), col.clone())?;
+ res.set(i, j, dot)?;
+ }
+ }
+ Ok(res)
+ }
+}
+
+pub struct MatrixRows<'a> {
+ matrix: &'a Matrix,
+ row: usize
+}
+
+impl<'a> Iterator for MatrixRows<'a> {
+ type Item = Vec<&'a Value>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.row >= self.matrix.codomain {
+ return None
+ }
+
+ let row_start = self.row * self.matrix.domain;
+ let row_end = row_start + self.matrix.domain;
+
+ let res = self.matrix.values
+ .iter()
+ .enumerate()
+ .filter(|(idx, _)| *idx >= row_start && *idx < row_end)
+ .map(|v| v.1)
+ .collect();
+
+ self.row += 1;
+
+ Some(res)
+ }
+}
+
+pub struct MatrixCols<'a> {
+ matrix: &'a Matrix,
+ col: usize
+}
+
+impl<'a> Iterator for MatrixCols<'a> {
+ type Item = Vec<&'a Value>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.col >= self.matrix.domain {
+ return None
+ }
+
+ let res = self.matrix.values
+ .iter()
+ .enumerate()
+ .filter(|(idx, _)| *idx % self.matrix.domain == self.col)
+ .map(|v| v.1)
+ .collect();
+
+ self.col += 1;
+
+ Some(res)
+ }
+}
diff --git a/matrix-lang/src/value/mod.rs b/matrix-lang/src/value/mod.rs
new file mode 100644
index 0000000..9094bb6
--- /dev/null
+++ b/matrix-lang/src/value/mod.rs
@@ -0,0 +1,42 @@
+pub mod comp;
+pub mod gc;
+pub mod matrix;
+pub mod hash;
+pub mod exception;
+pub mod function;
+pub mod fmt;
+pub mod index;
+pub mod clone;
+
+use crate::prelude::*;
+
+#[derive(Clone)]
+pub enum Value {
+ Nil,
+
+ Bool(bool),
+ Int(i64),
+ Float(f64),
+ Ratio(Rational64),
+ Complex(Complex64),
+
+ Regex(Rc<Regex>),
+ String(Rc<str>),
+
+ List(Gc<Vec<Value>>),
+ Matrix(Gc<Matrix>),
+ Table(Gc<ValueMap>),
+
+ Function(Rc<Function>),
+ Range(Rc<(i64, i64, bool)>),
+ Iter(Rc<Function>),
+ File(Rc<RefCell<File>>),
+
+ Exception(Exception),
+}
+
+impl From<&str> for Value {
+ fn from(value: &str) -> Self {
+ Value::String(Rc::from(value))
+ }
+}
diff --git a/matrix-lang/src/value/value.rs b/matrix-lang/src/value/value.rs
new file mode 100644
index 0000000..10d8398
--- /dev/null
+++ b/matrix-lang/src/value/value.rs
@@ -0,0 +1,522 @@
+use std::{
+ collections::HashMap,
+ rc::Rc,
+ hash::Hash,
+ fmt::{Display, Debug},
+ ops::{Add, Neg, Not, Sub, Div, Mul, BitOr, BitAnd, BitXor, Shl, Shr},
+ cmp::Ordering,
+ cell::RefCell, fs::File
+};
+
+use crate::iter;
+use num_complex::Complex64;
+use num_rational::Rational64;
+use regex::Regex;
+
+use crate::{ast::{Expr, BinaryOp, UnaryOp}, chunk::Function, Result, gc::Gc};
+
+
+pub type InlineList = Vec<Expr>;
+pub type InlineMatrix = (usize, usize, Vec<Expr>);
+pub type InlineTable = Vec<(Expr, Expr)>;
+
+#[derive(Debug)]
+pub struct Error(String);
+
+impl Display for self::Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl std::error::Error for self::Error {}
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ Err(self::Error(format!($($arg)*)).into())
+ };
+}
+
+
+impl From<&str> for Value {
+ fn from(value: &str) -> Self {
+ Value::String(value.into())
+ }
+}
+
+
+impl Debug for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use Value as V;
+ match self {
+ V::Nil => write!(f, "[Nil]"),
+ V::Bool(b) => write!(f, "[Bool {b}]"),
+ V::Int(i) => write!(f, "[Int {i}]"),
+ V::Float(vf) => write!(f, "[Float {vf}]"),
+ V::Ratio(r) => write!(f, "[Ratio {r}]"),
+ V::Complex(c) => write!(f, "[Complex {c}]"),
+ V::Regex(r) => write!(f, "[Regex /{r}/]"),
+ V::String(s) => write!(f, "[String '{s}']"),
+ V::List(l) => write!(f, "[List {}]", l.len()),
+ V::Matrix(m) => write!(f, "[Matirx {}x{}]", m.domain, m.codomain),
+ V::Table(t) => write!(f, "[Table {}]", t.0.len()),
+ V::Function(vf) => write!(f, "[Function {}]", vf.name),
+ V::Range(r) => write!(f, "[Range {:?}..{:?}]", r.0, r.1),
+ V::Iter(_) => write!(f, "[Iterator]"),
+ V::Error(_) => write!(f, "[Error]"),
+ V::File(_) => write!(f, "[File]"),
+ }
+ }
+}
+
+impl Display for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use Value as V;
+
+ let red;
+ let green;
+ let yellow;
+ let blue;
+ let pink;
+ let cyan;
+ let clear;
+
+ if f.alternate() {
+ red = "\x1b[31m";
+ green = "\x1b[32m";
+ yellow = "\x1b[33m";
+ blue = "\x1b[34m";
+ pink = "\x1b[35m";
+ cyan = "\x1b[36m";
+ clear = "\x1b[0m";
+ } else {
+ red = "";
+ green = "";
+ yellow = "";
+ blue = "";
+ pink = "";
+ cyan = "";
+ clear = "";
+ }
+
+ match self {
+ V::Nil => {write!(f, "{blue}nil{clear}")?;},
+ V::Bool(b) => {write!(f, "{yellow}{b}{clear}")?;},
+ V::Int(i) => {write!(f, "{yellow}{i}{clear}")?;},
+ V::Float(l) => {write!(f, "{yellow}{l}{clear}")?;},
+ V::Ratio(r) => {write!(f, "{yellow}{r}{clear}")?;},
+ V::Complex(c) => {write!(f, "{yellow}{c}{clear}")?;},
+ V::Regex(r) => {write!(f, "/{red}{r}{clear}/")?;},
+ V::String(s) => {
+ if f.alternate() {
+ write!(f, "{green}'{s}'{clear}")?;
+ } else {
+ write!(f, "{s}")?;
+ }
+ }
+ V::List(l) => {
+ write!(f, "[")?;
+ for (i, el) in l.iter().enumerate() {
+ if i != 0 {
+ write!(f, " ")?;
+ }
+ if f.alternate() {
+ write!(f, "{el:#}")?;
+ } else {
+ write!(f, "{el}")?;
+ }
+ }
+ write!(f, "]")?;
+ },
+ V::Matrix(m) => {
+ if f.alternate() {
+ write!(f, "{m:#}")?;
+ } else {
+ write!(f, "{m}")?;
+ }
+ },
+ V::Table(t) => {
+ write!(f, "{{")?;
+ for (i, (key, val)) in t.0.iter().enumerate() {
+ if i != 0 {
+ write!(f, ", ")?;
+ }
+ if f.alternate() {
+ write!(f, "{key:#} = {val:#}")?;
+ } else {
+ write!(f, "{key} = {val}")?;
+ }
+ }
+ write!(f, "}}")?;
+ },
+ V::Function(fun) => {
+ use crate::chunk::InnerFunction as F;
+ match fun.fun {
+ F::Compiled(_) => write!(f, "{cyan}[Function {}]{clear}", fun.name)?,
+ F::Native(_) => write!(f, "{cyan}[Builtin {}]{clear}", fun.name)?,
+ };
+ },
+ V::Range(r) => {
+ if f.alternate() {
+ write!(f, "{:#}..{:#}", r.0, r.1)?;
+ } else {
+ write!(f, "{}..{}", r.0, r.1)?;
+ }
+ }
+ V::Iter(_) => {write!(f, "{pink}[Iterator]{clear}")?;},
+ V::File(_) => {write!(f, "{pink}[File]{clear}")?;},
+ V::Error(e) => {write!(f, "{red}{e}{clear}")?;},
+ };
+ Ok(())
+ }
+}
+
+impl Value {
+ pub fn can_hash(&self) -> Result<()> {
+ use Value::*;
+ match self {
+ Nil => {},
+ Bool(_) => {},
+ Int(_) => {},
+ Ratio(_) => {},
+ Regex(_) => {},
+ String(_) => {}
+ List(l) => {
+ for val in l.iter() {
+ val.can_hash()?;
+ }
+ }
+ Matrix(m) => {
+ for val in m.values.iter() {
+ val.can_hash()?;
+ }
+ },
+ _ => return error!("cannot hash {self:?}")
+ }
+ Ok(())
+ }
+
+ pub fn is_zero(&self) -> bool {
+ use Value as V;
+ match self {
+ V::Int(i) => *i == 0,
+ V::Float(f) => *f == 0.0 || *f == -0.0,
+ V::Ratio(r) => *r.numer() == 0,
+ _ => false,
+ }
+ }
+}
+
+
+impl Value {
+ pub fn val_cmp(&self, other: &Self) -> Result<Ordering> {
+ self.partial_cmp(other)
+ .map_or_else(|| error!("cannot compare: {self:?} and {other:?}"), Ok)
+ }
+
+ fn index_single(&self, index: &Value) -> Result<Self> {
+ use Value as V;
+ match (self, index) {
+ (V::Table(t), index) => {
+ Ok(t.get(index)?.unwrap_or(&Value::Nil).clone())
+ },
+ (V::List(l), V::Int(i)) => {
+ if *i < 0 || *i as usize >= l.len() {
+ return error!("{i} out of bounds for {self:?}")
+ }
+ Ok(l[*i as usize].clone())
+ },
+ (V::Matrix(m), V::Int(i)) => {
+ if *i < 0 || *i as usize >= m.values.len() {
+ return error!("{i} out of bounds for {self:?}")
+ }
+ Ok(m.values[*i as usize].clone())
+ },
+ _ => return error!("{index:?} cant index {self:?}")
+ }
+ }
+
+ fn index_multiple(&self, indexes: &Vec<Value>) -> Result<Self> {
+ use Value as V;
+ match self {
+ V::List(..) => {
+ let mut ret = Vec::new();
+ for index in indexes {
+ let res = self.index_single(index)?;
+ ret.push(res);
+ }
+ Ok(V::List(ret.into()))
+ }
+ V::Table(..) => {
+ let mut ret = ValueMap::new();
+ for index in indexes {
+ let res = self.index_single(index)?;
+ ret.insert(index.clone(), res)?;
+ }
+ Ok(V::Table(ret.into()))
+ }
+ V::Matrix(m) => {
+ let err = || error!("{self:?} can be index by [Int] or [Int;Int]");
+ if indexes.len() != 2 {
+ return err()
+ }
+ let lhs = indexes[0].clone();
+ let rhs = indexes[1].clone();
+ match (lhs, rhs) {
+ (V::Nil, V::Nil) => {
+ Ok(V::Matrix(m.clone_inside()))
+ },
+ (V::Int(row), V::Nil) => {
+ let Some((_, row)) = m.rows().enumerate().filter(|(idx, _)| *idx as i64 == row).next() else {
+ return err();
+ };
+ let row: Vec<Value> = row.into_iter().map(|e| e.clone()).collect();
+ Ok(V::Matrix(Matrix::new(row.len(), 1, row).into()))
+ },
+ (V::Nil, V::Int(col)) => {
+ let Some((_, col)) = m.cols().enumerate().filter(|(idx, _)| *idx as i64 == col).next() else {
+ return err();
+ };
+ let col: Vec<Value> = col.into_iter().map(|e| e.clone()).collect();
+ Ok(V::Matrix(Matrix::new(1, col.len(), col).into()))
+ },
+ (V::Int(row), V::Int(col)) => {
+ if row < 0 || col < 0 {
+ return err();
+ }
+ m.get(row as usize, col as usize)
+ }
+ _ => return err()
+ }
+ }
+ _ => return error!("cannot index {self:?}")
+ }
+ }
+
+ pub fn index(&self, index: &Vec<Value>) -> Result<Self> {
+ if index.len() == 0 {
+ Ok(self.clone_inside())
+ } else if index.len() == 1 {
+ self.index_single(&index[0])
+ } else {
+ self.index_multiple(index)
+ }
+ }
+
+ fn store_index_single(&mut self, index: &Value, store: Value) -> Result<()> {
+ use Value as V;
+ let err = format!("{self:?}");
+ match (self, index) {
+ (V::Table(t), index) => {
+ t.insert(index.clone(), store)
+ },
+ (V::List(l), V::Int(i)) => {
+ if *i < 0 || *i as usize >= l.len() {
+ return error!("{i} out of bounds for {err}")
+ }
+ l[*i as usize] = store;
+ Ok(())
+ },
+ (V::Matrix(m), V::Int(i)) => {
+ if *i < 0 || *i as usize >= m.values.len() {
+ return error!("{i} out of bounds for {err}")
+ }
+ m.values[*i as usize] = store;
+ Ok(())
+ },
+ _ => return error!("{index:?} cant index {err}")
+ }
+ }
+
+ fn store_index_multiple(&mut self, indexes: &Vec<Value>, store: Value) -> Result<()> {
+ use Value as V;
+ match self {
+ V::List(..) => {
+ for index in indexes {
+ self.store_index_single(index, store.clone())?;
+ }
+ Ok(())
+ }
+ V::Table(..) => {
+ for index in indexes {
+ self.store_index_single(index, store.clone())?;
+ }
+ Ok(())
+ }
+ _ => return error!("cannot index {self:?}")
+ }
+ }
+
+ pub fn store_index(&mut self, index: &Vec<Value>, store: Value) -> Result<()> {
+ if index.len() == 0 {
+ Ok(())
+ } else if index.len() == 1 {
+ self.store_index_single(&index[0], store)
+ } else {
+ self.store_index_multiple(index, store)
+ }
+ }
+
+ pub fn store_field_access(&mut self, ident: &str, val: Value) -> Result<()> {
+ use Value as V;
+ match self {
+ V::Table(t) => {
+ let key = V::String(Rc::from(ident));
+ Ok(t.insert(key, val)?)
+ },
+ _ => return error!("cannot field access assign {self:?}")
+ }
+ }
+
+ pub fn field_access(&self, ident: &str) -> Result<Self> {
+ use Value as V;
+ match self {
+ V::Table(t) => {
+ let key = V::String(Rc::from(ident));
+ Ok(t.get(&key)?.unwrap_or(&V::Nil).clone())
+ },
+ _ => return error!("cannot field access {self:?}")
+ }
+ }
+
+ pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
+ use BinaryOp::*;
+ match op {
+ Add => lhs + rhs,
+ Subtract => lhs - rhs,
+ Multiply => lhs * rhs,
+ Divide => lhs / rhs,
+ Modulo => lhs.modulo(rhs),
+ Power => lhs.pow(rhs),
+ BitwiseAnd => lhs & rhs,
+ BitwiseOr => lhs | rhs,
+ BitwiseXor => lhs ^ rhs,
+ BitwiseShiftLeft => lhs << rhs,
+ BitwiseShiftRight => lhs >> rhs,
+ Equals => Ok(Self::Bool(lhs == rhs)),
+ NotEquals => Ok(Self::Bool(lhs != rhs)),
+ GreaterEquals => Ok(Self::Bool(lhs >= rhs)),
+ LessEquals => Ok(Self::Bool(lhs <= rhs)),
+ GreaterThan => Ok(Self::Bool(lhs > rhs)),
+ LessThan => Ok(Self::Bool(lhs < rhs)),
+ Range | RangeEq => {
+ let Value::Int(lhs) = lhs else {
+ return error!("range can only take [Int]'s")
+ };
+ let Value::Int(rhs) = rhs else {
+ return error!("range can only take [Int]'s")
+ };
+ Ok(Self::Range(Rc::new((lhs, rhs, op == RangeEq))))
+ },
+ }
+ }
+
+ pub fn unary_op(op: UnaryOp, val: Value) -> Value {
+ use UnaryOp::*;
+ match op {
+ Negate => -val,
+ Not => Self::Bool(!val),
+ }
+ }
+}
+
+impl Neg for Value {
+ type Output = Value;
+
+ fn neg(self) -> Self::Output {
+ use Value::*;
+ match self {
+ Bool(b) => Bool(!b),
+ Int(i) => Int(-i),
+ Float(f) => Float(-f),
+ Ratio(r) => Ratio(-r),
+ Complex(c) => Complex(-c),
+ _ => return Float(f64::NAN)
+ }
+ }
+}
+
+impl Not for Value {
+ type Output = bool;
+
+ fn not(self) -> Self::Output {
+ use Value as V;
+ match self {
+ V::Nil => true,
+ V::Bool(b) => !b,
+ V::Int(i) => i == 0,
+ V::Float(f) => f == 0.0,
+ V::Ratio(r) => *(r.numer()) == 0 || *(r.denom()) == 0,
+ V::Complex(c) => !c.is_normal(),
+ V::Regex(_) => false,
+ V::List(_) => false,
+ V::Matrix(_) => false,
+ V::Table(_) => false,
+ V::String(s) => s.as_ref() == "",
+ V::Function(_) => false,
+ V::Iter(_) => false,
+ V::Range(_) => false,
+ V::File(_) => false,
+ V::Error(_) => false,
+ }
+ }
+}
+
+impl Value {
+
+ pub fn into_iter_fn(self) -> Result<Rc<Function>> {
+ let Value::Iter(iter) = self.into_iter()? else {
+ return error!("bypassed iter check")
+ };
+ Ok(iter)
+ }
+
+ pub fn into_iter(self) -> Result<Self> {
+ use Value as V;
+ Ok(match self {
+ V::Iter(..) => self,
+ V::List(l) => {
+ let iter = RefCell::new(l.into_inner().into_iter());
+ iter!(move |_,_| {
+ match iter.borrow_mut().next() {
+ Some(v) => Ok(v),
+ None => Ok(V::Nil),
+ }
+ })
+ },
+ V::Range(r) => {
+ let r = (*r).clone();
+ let lhs = RefCell::new(r.0);
+ let rhs = r.1;
+ iter!(move |_,_| {
+ let val = *lhs.borrow();
+ let next = *lhs.borrow() + 1;
+ if (!r.2 && *lhs.borrow() < rhs) || (r.2 && *lhs.borrow() <= rhs) {
+ *lhs.borrow_mut() = next;
+ return Ok(Value::Int(val))
+ }
+ Ok(Value::Nil)
+ })
+ },
+ V::Function(f) => {
+ if f.arity > 0 || f.variadic {
+ return error!("iterator functions cannot be varadic or take arguments")
+ }
+ V::Iter(f)
+ },
+ val => return error!("cannot turn {val:?} into an iterator")
+ })
+ }
+}
+
+fn dot(lhs: Vec<&Value>, rhs: Vec<&Value>) -> Result<Value> {
+ let len = lhs.len();
+
+ let mut res = Value::Int(0);
+ for i in 0..len {
+ let val = (lhs[i].clone() * rhs[i].clone())?;
+ res = (res + val)?;
+ }
+
+ Ok(res)
+}
diff --git a/matrix/src/vm.rs b/matrix-lang/src/vm.rs
index e511adf..bac6341 100644
--- a/matrix/src/vm.rs
+++ b/matrix-lang/src/vm.rs
@@ -1,33 +1,6 @@
-use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap, cell::RefCell, sync::{atomic::{AtomicUsize, Ordering}, Arc}};
-use crate::{value::{Value, self, ValueMap, Matrix}, Result, gc::Gc, chunk::{Function, Instruction, Chunk, InnerFunction}, compiler::NamesTable, native};
+use std::{fmt::Display, ops::{IndexMut, Index}, sync::{atomic::{AtomicUsize, Ordering}, Arc}, collections::HashMap};
+use crate::prelude::*;
-#[derive(Debug)]
-pub enum Error {
- ValueError(value::Error),
- NotFunction(Value),
- InvArity(usize, usize, Rc<str>),
- ExecNative,
-}
-
-impl std::error::Error for Error {}
-
-impl Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use Error::*;
- match self {
- ValueError(err) => write!(f, "{err}"),
- NotFunction(v) => write!(f, "{v:?} is not a function"),
- InvArity(wanted, had, name) => write!(f, "function {name} takes {wanted} params but was given {had}"),
- ExecNative => write!(f, "cannot execute a native function"),
- }
- }
-}
-
-impl From<value::Error> for Error {
- fn from(value: value::Error) -> Self {
- Error::ValueError(value)
- }
-}
pub struct Stack<T> {
inner: Vec<T>
}
@@ -99,12 +72,12 @@ pub struct StackFrame {
}
struct VmError {
- err: crate::Error,
+ err: Exception,
frames: Vec<StackFrame>
}
-impl From<crate::Error> for VmError {
- fn from(err: crate::Error) -> Self {
+impl From<Exception> for VmError {
+ fn from(err: Exception) -> Self {
VmError {
err,
frames: Vec::new()
@@ -112,15 +85,6 @@ impl From<crate::Error> for VmError {
}
}
-impl From<self::Error> for VmError {
- fn from(err: self::Error) -> Self {
- VmError {
- err: err.into(),
- frames: Vec::new()
- }
- }
-}
-
type VmResult<T> = std::result::Result<T, VmError>;
impl StackFrame {
@@ -166,10 +130,16 @@ pub struct Vm {
trystack: Vec<TryScope>,
globals: Rc<RefCell<HashMap<u16, Value>>>,
names: NamesTable,
- global_names: NamesTable,
+ global_names: GlobalsTable,
interupt: Arc<AtomicUsize>,
}
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(RUNTIME_EXCEPTION, $($arg)*)
+ };
+}
+
impl Vm {
fn push(&mut self, val: Value) {
@@ -188,7 +158,7 @@ impl Vm {
self.names.clone()
}
- pub fn global_names(&self) -> NamesTable {
+ pub fn globals(&self) -> GlobalsTable {
self.global_names.clone()
}
@@ -210,7 +180,7 @@ impl Vm {
pub fn load_global(&mut self, value: Value, name: &str) {
let idx = self.global_names.borrow().len();
- self.global_names.borrow_mut().push(name.into());
+ self.global_names.borrow_mut().push(Global { idx, name: Rc::from(name), is_const: true });
self.globals.borrow_mut().insert(idx as u16, value);
}
@@ -220,7 +190,7 @@ impl Vm {
fn init_frame(&mut self, fun: Rc<Function>) -> Result<StackFrame> {
let InnerFunction::Compiled(ref compiled_chunk) = fun.fun else {
- return Err(self::Error::ExecNative.into())
+ return Err(error!("cannot create stack frame on builtin function"))
};
Ok(StackFrame::new(
self,
@@ -240,7 +210,7 @@ impl Vm {
match ins {
I::NoOp => {},
I::CreateLocal => self.locals.push(self.stack.pop()),
- I::LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());},
+ I::LoadLocal(idx) => {self.stack.push(self.locals[frame.lp + idx as usize].clone());},
I::StoreLocal(idx) => self.locals[frame.bp + idx as usize] = self.pop(),
I::DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
I::LoadGlobal(idx) => {
@@ -325,11 +295,12 @@ impl Vm {
let fun = self.pop();
let Value::Function(fun) = fun else {
- return Err(Error::NotFunction(fun).into())
+ Err(error!("cannot call {fun} (not a function)"))?
};
if !fun.variadic && arity > fun.arity {
- return Err(Error::InvArity(fun.arity, arity as usize, fun.name.clone()).into())
+ let needs = fun.arity;
+ Err(error!("function {fun} takes {needs} args, given {arity}"))?
}
let mut params = self.stack.split_off(self.stack.len() - arity).inner;
@@ -416,14 +387,14 @@ impl Vm {
Ok(None)
}
- fn stack_trace(&mut self, frames: Vec<StackFrame>) -> String {
- let mut trace = String::from("\x1b[33m\x1b[1mStack Trace:\x1b[0m\n");
+ fn stack_trace(&mut self, frames: Vec<StackFrame>, e: Exception) -> Exception {
+ let mut e = e;
for frame in frames {
let ip = frame.ip - 1;
let pos = frame.body.pos[ip];
- trace.push_str(&format!(" {} at {}:{}\n", &frame.name, pos.row, pos.col));
+ e = e.trace(frame.name, pos);
}
- trace
+ e
}
fn exec_fn(&mut self, frame: &mut StackFrame, fun: Rc<Function>, params: Vec<Value>) -> VmResult<Value> {
@@ -438,7 +409,8 @@ impl Vm {
self.stack.push(param);
}
let mut new_frame = StackFrame::new(self, name, body.clone(), params_len, frame.depth + 1);
- self.exec(&mut new_frame)
+ let res = self.exec(&mut new_frame);
+ res
},
InnerFunction::Native(native_fun) => {
Ok(native_fun((self, frame), params)?)
@@ -462,7 +434,7 @@ impl Vm {
self.stack.truncate(catch.stack_len);
self.locals.truncate(catch.locals_len);
frame.ip = catch.err_idx;
- self.stack.push(Value::Error(err.err));
+ self.stack.push(Value::Exception(err.err));
} else {
let mut err = err;
err.frames.push(frame.clone());
@@ -478,13 +450,12 @@ impl Vm {
}
pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> {
- let mut frame = self.init_frame(fun)?;
self.interupt.store(0, Ordering::SeqCst);
self.stack = Stack::new();
self.locals = Stack::new();
+ let mut frame = self.init_frame(fun)?;
self.exec(&mut frame).map_err(|e| {
- let trace = self.stack_trace(e.frames);
- (e.err, trace).into()
+ self.stack_trace(e.frames, e.err)
})
}
}
diff --git a/matrix-macros/Cargo.toml b/matrix-macros/Cargo.toml
index df84237..4aff09a 100644
--- a/matrix-macros/Cargo.toml
+++ b/matrix-macros/Cargo.toml
@@ -9,4 +9,4 @@ proc-macro = true
[dependencies]
syn = { version = "1", features = ["full"] }
quote = "1"
-matrix = { path = "../matrix" }
+matrix-lang = { path = "../matrix-lang" }
diff --git a/matrix-macros/src/lib.rs b/matrix-macros/src/lib.rs
index b12d30b..a660053 100644
--- a/matrix-macros/src/lib.rs
+++ b/matrix-macros/src/lib.rs
@@ -37,12 +37,12 @@ pub fn native_func(input: TokenStream, annotated_item: TokenStream) -> TokenStre
assert!(itemfn.sig.variadic.is_none(), "item must not be variadic");
let expanded = quote! {
- #visibility fn #name() -> ::std::rc::Rc< ::matrix::chunk::Function> {
- ::std::rc::Rc::new( ::matrix::chunk::Function {
+ #visibility fn #name() -> ::std::rc::Rc< ::matrix_lang::prelude::Function> {
+ ::std::rc::Rc::new( ::matrix_lang::prelude::Function {
name: ::std::rc::Rc::from( #name_str ),
arity: #arity,
variadic: #variadic,
- fun: ::matrix::chunk::InnerFunction::Native(
+ fun: ::matrix_lang::prelude::InnerFunction::Native(
::std::rc::Rc::new(
|#inputs| #output #block
)
diff --git a/matrix-stdlib/Cargo.toml b/matrix-std/Cargo.toml
index 6256cfa..476272c 100644
--- a/matrix-stdlib/Cargo.toml
+++ b/matrix-std/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "matrix-stdlib"
+name = "matrix-std"
version = "0.1.0"
edition = "2021"
@@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
anyhow = "1"
-matrix = { path = "../matrix" }
+matrix-lang = { path = "../matrix-lang" }
matrix-macros = { path = "../matrix-macros" }
os_info = "3"
rand = "0.8"
diff --git a/matrix-stdlib/src/core.rs b/matrix-std/src/core.rs
index 2c76497..69b6d97 100644
--- a/matrix-stdlib/src/core.rs
+++ b/matrix-std/src/core.rs
@@ -1,10 +1,8 @@
-use std::hash::{DefaultHasher, Hash, Hasher};
-
-use matrix::{vm::Vm, value::Value, unpack_args, Result, unpack_varargs};
-use matrix_macros::native_func;
+use std::hash::{DefaultHasher, Hasher};
use rand::Rng;
-use crate::{VmArgs, next, error};
-
+use matrix_lang::prelude::*;
+use matrix_macros::native_func;
+use crate::{VmArgs, next, error, unpack_args, unpack_varargs};
fn to_radix(r: i64, mut n: i64) -> String {
let mut result = String::new();
@@ -123,11 +121,8 @@ fn remove(_: VmArgs, args: Vec<Value>) -> Result<Value> {
#[native_func(1)]
fn hash(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
- if let Err(e) = value.can_hash() {
- return Err(e)
- };
let mut hasher = DefaultHasher::new();
- value.hash(&mut hasher);
+ value.try_hash(&mut hasher)?;
let fin = hasher.finish();
Ok(Value::Int(fin as u32 as i64))
}
@@ -201,8 +196,10 @@ fn sort(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let Value::List(mut list) = value else {
return error!("sort requires a list")
};
- let hi = list.len() - 1;
- quicksort(list.as_mut(), 0, hi);
+ if list.len() > 1 {
+ let hi = list.len() - 1;
+ quicksort(list.as_mut(), 0, hi);
+ }
Ok(Value::List(list))
}
diff --git a/matrix-stdlib/src/io.rs b/matrix-std/src/io.rs
index d72248c..19ff074 100644
--- a/matrix-stdlib/src/io.rs
+++ b/matrix-std/src/io.rs
@@ -1,8 +1,7 @@
use std::{io::{self, Read, Write}, cell::RefCell, fs::OpenOptions, rc::Rc};
-
-use matrix::{value::Value, self, vm::Vm, Result, unpack_varargs, iter, unpack_args};
+use matrix_lang::prelude::*;
use matrix_macros::native_func;
-use crate::{error, VmArgs};
+use crate::{error, VmArgs, unpack_varargs, unpack_args};
#[native_func(0..)]
fn print(_: VmArgs, args: Vec<Value>) -> Result<Value> {
diff --git a/matrix-stdlib/src/iter.rs b/matrix-std/src/iter.rs
index 630e52c..638755c 100644
--- a/matrix-stdlib/src/iter.rs
+++ b/matrix-std/src/iter.rs
@@ -1,7 +1,7 @@
use std::{cell::RefCell, rc::Rc};
-use matrix::{iter, vm::Vm, value::Value, Result, unpack_varargs, unpack_args};
+use matrix_lang::prelude::*;
use matrix_macros::native_func;
-use crate::{error, next, VmArgs};
+use crate::{error, next, VmArgs, unpack_args, unpack_varargs};
use Value as V;
@@ -54,7 +54,7 @@ fn range(_: VmArgs, args: Vec<Value>) -> Result<Value> {
Ok(iter!(move |_,_| {
let curr = *(i.borrow());
*(i.borrow_mut()) = curr + step;
- if curr >= max {
+ if (step >= 0 && curr >= max) || (step <= 0 && curr <= max) {
return Ok(V::Nil)
} else {
return Ok(V::Int(curr))
@@ -235,7 +235,7 @@ fn lines(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let Value::String(str) = str else {
return error!("lines arg must be a string")
};
- let lines: Vec<Rc<str>> = str.split_inclusive("\n").map(|s| Rc::from(s)).collect();
+ let lines: Vec<Rc<str>> = str.split("\n").map(|s| Rc::from(s)).collect();
let res = RefCell::new(lines.into_iter());
Ok(iter!(move |_,_| {
match res.borrow_mut().next() {
@@ -245,7 +245,7 @@ fn lines(_: VmArgs, args: Vec<Value>) -> Result<Value> {
}))
}
-#[native_func(1)]
+#[native_func(2)]
fn skip((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
let [count, iter] = unpack_args!(args);
let iter = iter.into_iter_fn()?;
@@ -291,25 +291,32 @@ fn alternate(_: VmArgs, args: Vec<Value>) -> Result<Value> {
}
#[native_func(2)]
-fn intersperse(_: VmArgs, args: Vec<Value>) -> Result<Value> {
+fn intersperse((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
let [value, iter] = unpack_args!(args);
let iter = iter.into_iter_fn()?;
let flag = RefCell::new(Some(0));
+ let next = RefCell::new(next!(vm, frame, iter)?);
Ok(iter!(move |(vm, frame),_| {
let f = *flag.borrow();
match f {
Some(0) => {
- let val = next!(vm, frame, iter)?;
- if val == Value::Nil {
+ let val = next.borrow();
+ if *val == Value::Nil {
*flag.borrow_mut() = None;
} else {
*flag.borrow_mut() = Some(1);
}
- Ok(val)
+ Ok(val.clone())
},
Some(1) => {
+ *next.borrow_mut() = next!(vm, frame, iter)?;
+ if *next.borrow() == Value::Nil {
+ *flag.borrow_mut() = None;
+ return Ok(Value::Nil)
+ } else {
+ *flag.borrow_mut() = Some(0);
+ }
let val = value.clone();
- *flag.borrow_mut() = Some(0);
Ok(val)
},
_ => Ok(Value::Nil)
@@ -331,6 +338,7 @@ fn zip(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let vr = next!(vm, frame, ir)?;
if vl == Value::Nil || vr == Value::Nil {
*flag.borrow_mut() = false;
+ return Ok(Value::Nil)
}
Ok(Value::List(vec![vl, vr].into()))
},
@@ -401,7 +409,7 @@ fn take((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
Ok(Value::List(values.into()))
}
-#[native_func(2)]
+#[native_func(1)]
fn last((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
let [iter] = unpack_args!(args);
let iter = iter.into_iter_fn()?;
@@ -414,7 +422,7 @@ fn last((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
Ok(last)
}
-#[native_func(2)]
+#[native_func(1)]
fn next((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
let [iter] = unpack_args!(args);
let iter = iter.into_iter_fn()?;
diff --git a/matrix-std/src/lib.rs b/matrix-std/src/lib.rs
new file mode 100644
index 0000000..af4ecab
--- /dev/null
+++ b/matrix-std/src/lib.rs
@@ -0,0 +1,50 @@
+mod core;
+mod sys;
+mod math;
+mod io;
+mod iter;
+
+use matrix_lang::prelude::*;
+pub(crate) type VmArgs<'a, 'b> = (&'a mut Vm, &'b mut StackFrame);
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ Err(::matrix_lang::prelude::exception!(::matrix_lang::prelude::RUNTIME_EXCEPTION, $($arg)*))
+ };
+}
+
+macro_rules! next {
+ ($vm:expr, $frame:expr, $iter:expr) => {
+ $vm.run_fn($frame, $iter.clone(), vec![])
+ };
+}
+
+macro_rules! unpack_args {
+ ($e:expr) => {
+ $e.try_into().expect("bypassed arity check")
+ };
+}
+
+macro_rules! unpack_varargs {
+ ($e:expr) => {{
+ let mut args = $e;
+ let matrix_lang::prelude::Value::List(varargs) = args.pop().expect("bypassed arity check") else {
+ panic!("bypassed arity check")
+ };
+ let varargs = varargs.into_inner();
+ (args.try_into().expect("bypassed arity check"), varargs)
+ }};
+}
+
+pub(crate) use error;
+pub(crate) use next;
+pub(crate) use unpack_args;
+pub(crate) use unpack_varargs;
+
+pub fn load(vm: &mut Vm) {
+ core::load(vm);
+ sys::load(vm);
+ io::load(vm);
+ iter::load(vm);
+ math::load(vm);
+}
diff --git a/matrix-stdlib/src/math.rs b/matrix-std/src/math.rs
index 3f33951..111544c 100644
--- a/matrix-stdlib/src/math.rs
+++ b/matrix-std/src/math.rs
@@ -1,9 +1,8 @@
use core::f64;
use std::f64::{consts::{PI, E, TAU}, NAN, INFINITY};
-
-use matrix::{vm::Vm, value::{Value, Matrix}, Result, unpack_args, Rational64, Complex64};
+use matrix_lang::prelude::*;
use matrix_macros::native_func;
-use crate::{error, VmArgs};
+use crate::{error, VmArgs, unpack_args};
#[native_func(1)]
fn trans(_: VmArgs, args: Vec<Value>) -> Result<Value> {
@@ -280,7 +279,7 @@ macro_rules! trig {
fn $type(_: VmArgs, args: Vec<Value>) -> Result<Value> {
use Value as V;
let [value] = unpack_args!(args);
- match value.promote_trig() {
+ match value.floaty() {
V::Float(f) => Ok(V::Float(f.$type())),
V::Complex(c) => Ok(V::Complex(c.$type())),
v => error!("cannot compute {} on {v}", stringify!($type))
@@ -295,7 +294,7 @@ macro_rules! trigf {
fn $str(_: VmArgs, args: Vec<Value>) -> Result<Value> {
use Value as V;
let [value] = unpack_args!(args);
- match value.promote_trig() {
+ match value.floaty() {
V::Float(f) => Ok(V::Float(f.$type())),
v => error!("cannot compute {} on {v}", stringify!($str))
}
@@ -307,7 +306,7 @@ macro_rules! trigf {
fn log(_: VmArgs, args: Vec<Value>) -> Result<Value> {
use Value as V;
let [base, value] = unpack_args!(args);
- match (base.promote_trig(), value.promote_trig()) {
+ match (base.floaty(), value.floaty()) {
(V::Float(base), V::Float(arg)) => Ok(V::Float(arg.log(base))),
(V::Float(base), V::Complex(arg)) => Ok(V::Complex(arg.log(base))),
(V::Complex(base), V::Float(arg)) => Ok(V::Complex(arg.ln() / base.ln())),
@@ -463,7 +462,7 @@ fn im(_: VmArgs, args: Vec<Value>) -> Result<Value> {
#[native_func(1)]
fn cis(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
- match value.promote_trig() {
+ match value.floaty() {
Value::Float(f) => Ok(Value::Complex(Complex64::cis(f))),
Value::Complex(c) => Ok((Value::Complex(Complex64::cis(c.re)) * Value::Float((-c.im).exp()))?),
_ => error!("cis can only take floats")
diff --git a/matrix-stdlib/src/sys.rs b/matrix-std/src/sys.rs
index d30226f..609e72d 100644
--- a/matrix-stdlib/src/sys.rs
+++ b/matrix-std/src/sys.rs
@@ -1,9 +1,9 @@
use std::{process::{exit, Command, Stdio, Child}, env, rc::Rc, io::{Read, self}, cell::RefCell, fs::{File, self}, os::fd::FromRawFd, sync::OnceLock, path::PathBuf};
-use matrix::{vm::Vm, value::{Value, ValueMap}, unpack_args, Result, gc::Gc};
+use matrix_lang::prelude::*;
use matrix_macros::native_func;
use os_info::Info;
-use crate::{VmArgs, error};
+use crate::{VmArgs, error, unpack_args};
#[native_func(1)]
fn sys_exit(_: VmArgs, args: Vec<Value>) -> Result<Value> {
diff --git a/matrix-stdlib/src/lib.rs b/matrix-stdlib/src/lib.rs
deleted file mode 100644
index b4ab658..0000000
--- a/matrix-stdlib/src/lib.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use matrix::vm::{Vm, StackFrame};
-
-mod core;
-mod sys;
-mod math;
-mod io;
-mod iter;
-
-pub(crate) type VmArgs<'a, 'b> = (&'a mut Vm, &'b mut StackFrame);
-
-macro_rules! error {
- ($($arg:tt)*) => {
- Err(format!($($arg)*).into())
- };
-}
-
-macro_rules! next {
- ($vm:expr, $frame:expr, $iter:expr) => {
- $vm.run_fn($frame, $iter.clone(), vec![])
- };
-}
-
-pub(crate) use error;
-pub(crate) use next;
-
-pub fn load(vm: &mut Vm) {
- core::load(vm);
- sys::load(vm);
- io::load(vm);
- iter::load(vm);
- math::load(vm);
-}
diff --git a/matrix/src/lib.rs b/matrix/src/lib.rs
deleted file mode 100644
index 5a9be9f..0000000
--- a/matrix/src/lib.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-use std::{fmt::Display, rc::Rc};
-
-pub mod compiler;
-pub mod value;
-pub mod gc;
-pub mod lex;
-pub mod vm;
-pub mod parse;
-pub mod chunk;
-pub mod ast;
-
-pub use ::num_complex::Complex64 as Complex64;
-pub use ::num_rational::Rational64 as Rational64;
-
-#[derive(Debug, Clone)]
-pub struct Error(Rc<ErrorInner>);
-
-impl std::error::Error for Error {}
-
-#[derive(Debug)]
-enum ErrorInner {
- Lex(lex::Error),
- Parse(parse::Error),
- Value(value::Error),
- Compile(compiler::Error),
- Runtime(vm::Error),
- External(anyhow::Error),
- Traced(Box<Error>, String),
- Any(String),
-}
-
-impl Display for crate::Error {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use crate::ErrorInner::*;
- match self.0.as_ref() {
- Lex(err) => write!(f, "{err}"),
- Parse(err) => write!(f, "{err}"),
- Value(err) => write!(f, "{err}"),
- Compile(err) => write!(f, "{err}"),
- Runtime(err) => write!(f, "{err}"),
- External(err) => write!(f, "{err}"),
- Traced(err, trace) => write!(f, "{err}\n{trace}"),
- Any(err) => write!(f, "{err}"),
- }
- }
-}
-
-macro_rules! from_error {
- ($struct:ty, $tuple:tt) => {
- impl From<$struct> for crate::Error {
- fn from(value: $struct) -> Self {
- crate::Error(Rc::new(ErrorInner::$tuple(value)))
- }
- }
- };
-}
-
-from_error!(lex::Error, Lex);
-from_error!(parse::Error, Parse);
-from_error!(value::Error, Value);
-from_error!(compiler::Error, Compile);
-from_error!(vm::Error, Runtime);
-from_error!(anyhow::Error, External);
-from_error!(String, Any);
-
-impl From<(Error, String)> for Error {
- fn from(value: (Error, String)) -> Self {
- Self(Rc::new(ErrorInner::Traced(Box::new(value.0), value.1)))
- }
-}
-
-#[macro_export]
-macro_rules! iter {
- ($fn:expr) => {
- $crate::value::Value::Iter(
- ::std::rc::Rc::new(
- $crate::chunk::Function {
- name: ::std::rc::Rc::from("<iterator>"),
- arity: 0,
- variadic: false,
- fun: $crate::chunk::InnerFunction::Native(
- ::std::rc::Rc::new($fn
- ))}))
- };
-}
-
-#[macro_export]
-macro_rules! native {
- ($name:expr, $arity:expr, $varadic:expr, $fn:expr) => {
- $crate::value::Value::Function(
- ::std::rc::Rc::new( $crate::chunk::Function {
- name: std::rc::Rc::from($name),
- arity: $arity,
- variadic: $varadic,
- fun: $crate::chunk::InnerFunction::Native(
- ::std::rc::Rc::new($fn)
- )
- })
- )
- }
-}
-
-#[macro_export]
-macro_rules! unpack_args {
- ($e:expr) => {
- $e.try_into().expect("bypassed arity check")
- };
-}
-
-#[macro_export]
-macro_rules! unpack_varargs {
- ($e:expr) => {{
- let mut args = $e;
- let $crate::value::Value::List(varargs) = args.pop().expect("bypassed arity check") else {
- panic!("bypassed arity check")
- };
- let varargs = varargs.into_inner();
- (args.try_into().expect("bypassed arity check"), varargs)
- }};
-}
-
-pub type Result<T> = std::result::Result<T, crate::Error>;
diff --git a/matrix/src/value.rs b/matrix/src/value.rs
deleted file mode 100644
index f7d5170..0000000
--- a/matrix/src/value.rs
+++ /dev/null
@@ -1,1223 +0,0 @@
-use std::{
- collections::HashMap,
- rc::Rc,
- hash::Hash,
- fmt::{Display, Debug},
- ops::{Add, Neg, Not, Sub, Div, Mul, BitOr, BitAnd, BitXor, Shl, Shr},
- cmp::Ordering,
- cell::RefCell, fs::File
-};
-
-use crate::iter;
-use num_complex::Complex64;
-use num_rational::Rational64;
-use regex::Regex;
-
-use crate::{ast::{Expr, BinaryOp, UnaryOp}, chunk::Function, Result, gc::Gc};
-
-pub type List = Vec<Value>;
-pub type Table = ValueMap;
-
-pub type InlineList = Vec<Expr>;
-pub type InlineMatrix = (usize, usize, Vec<Expr>);
-pub type InlineTable = Vec<(Expr, Expr)>;
-
-#[derive(Debug, Clone)]
-pub struct ValueMap(HashMap<Value, Value>);
-
-impl ValueMap {
- pub fn new() -> Self {
- Self(HashMap::new())
- }
- pub fn get(&self, key: &Value) -> Result<Option<&Value>> {
- key.can_hash()?;
- Ok(self.0.get(key))
- }
- pub fn insert(&mut self, key: Value, value: Value) -> Result<()> {
- key.can_hash()?;
- self.0.insert(key, value);
- Ok(())
- }
- pub fn len(&self) -> usize {
- self.0.len()
- }
-}
-
-#[derive(Debug)]
-pub struct Error(String);
-
-impl Display for self::Error {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.0)
- }
-}
-
-impl std::error::Error for self::Error {}
-
-macro_rules! error {
- ($($arg:tt)*) => {
- Err(self::Error(format!($($arg)*)).into())
- };
-}
-
-#[derive(Clone)]
-pub enum Value {
- Nil,
- Bool(bool),
- Int(i64),
- Float(f64),
- Ratio(Rational64),
- Complex(Complex64),
- Regex(Rc<Regex>),
- String(Rc<str>),
- List(Gc<List>),
- Matrix(Gc<Matrix>),
- Table(Gc<Table>),
- Function(Rc<Function>),
- Range(Rc<(i64, i64, bool)>),
- Iter(Rc<Function>),
- File(Rc<RefCell<File>>),
- Error(crate::Error),
-}
-
-impl From<&str> for Value {
- fn from(value: &str) -> Self {
- Value::String(value.into())
- }
-}
-
-impl Hash for Value {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- use Value::*;
- match self {
- Nil => 0x23845.hash(state),
- Bool(b) => b.hash(state),
- Int(i) => i.hash(state),
- Ratio(r) => r.hash(state),
- Regex(r) => r.as_str().hash(state),
- String(s) => s.hash(state),
- List(l) => {
- for val in l.iter() {
- val.hash(state);
- }
- }
- Matrix(m) => {
- m.domain.hash(state);
- m.codomain.hash(state);
- for val in m.values.iter() {
- val.hash(state);
- }
- },
- _ => panic!("tried to hash {self:?}")
- };
- }
-}
-
-impl Debug for Value {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use Value as V;
- match self {
- V::Nil => write!(f, "[Nil]"),
- V::Bool(b) => write!(f, "[Bool {b}]"),
- V::Int(i) => write!(f, "[Int {i}]"),
- V::Float(vf) => write!(f, "[Float {vf}]"),
- V::Ratio(r) => write!(f, "[Ratio {r}]"),
- V::Complex(c) => write!(f, "[Complex {c}]"),
- V::Regex(r) => write!(f, "[Regex /{r}/]"),
- V::String(s) => write!(f, "[String '{s}']"),
- V::List(l) => write!(f, "[List {}]", l.len()),
- V::Matrix(m) => write!(f, "[Matirx {}x{}]", m.domain, m.codomain),
- V::Table(t) => write!(f, "[Table {}]", t.0.len()),
- V::Function(vf) => write!(f, "[Function {}]", vf.name),
- V::Range(r) => write!(f, "[Range {:?}..{:?}]", r.0, r.1),
- V::Iter(_) => write!(f, "[Iterator]"),
- V::Error(_) => write!(f, "[Error]"),
- V::File(_) => write!(f, "[File]"),
- }
- }
-}
-
-impl Display for Value {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use Value as V;
-
- let red;
- let green;
- let yellow;
- let blue;
- let pink;
- let cyan;
- let clear;
-
- if f.alternate() {
- red = "\x1b[31m";
- green = "\x1b[32m";
- yellow = "\x1b[33m";
- blue = "\x1b[34m";
- pink = "\x1b[35m";
- cyan = "\x1b[36m";
- clear = "\x1b[0m";
- } else {
- red = "";
- green = "";
- yellow = "";
- blue = "";
- pink = "";
- cyan = "";
- clear = "";
- }
-
- match self {
- V::Nil => {write!(f, "{blue}nil{clear}")?;},
- V::Bool(b) => {write!(f, "{yellow}{b}{clear}")?;},
- V::Int(i) => {write!(f, "{yellow}{i}{clear}")?;},
- V::Float(l) => {write!(f, "{yellow}{l}{clear}")?;},
- V::Ratio(r) => {write!(f, "{yellow}{r}{clear}")?;},
- V::Complex(c) => {write!(f, "{yellow}{c}{clear}")?;},
- V::Regex(r) => {write!(f, "/{red}{r}{clear}/")?;},
- V::String(s) => {
- if f.alternate() {
- write!(f, "{green}'{s}'{clear}")?;
- } else {
- write!(f, "{s}")?;
- }
- }
- V::List(l) => {
- write!(f, "[")?;
- for (i, el) in l.iter().enumerate() {
- if i != 0 {
- write!(f, " ")?;
- }
- if f.alternate() {
- write!(f, "{el:#}")?;
- } else {
- write!(f, "{el}")?;
- }
- }
- write!(f, "]")?;
- },
- V::Matrix(m) => {
- if f.alternate() {
- write!(f, "{m:#}")?;
- } else {
- write!(f, "{m}")?;
- }
- },
- V::Table(t) => {
- write!(f, "{{")?;
- for (i, (key, val)) in t.0.iter().enumerate() {
- if i != 0 {
- write!(f, ", ")?;
- }
- if f.alternate() {
- write!(f, "{key:#} = {val:#}")?;
- } else {
- write!(f, "{key} = {val}")?;
- }
- }
- write!(f, "}}")?;
- },
- V::Function(fun) => {
- use crate::chunk::InnerFunction as F;
- match fun.fun {
- F::Compiled(_) => write!(f, "{cyan}[Function {}]{clear}", fun.name)?,
- F::Native(_) => write!(f, "{cyan}[Builtin {}]{clear}", fun.name)?,
- };
- },
- V::Range(r) => {
- if f.alternate() {
- write!(f, "{:#}..{:#}", r.0, r.1)?;
- } else {
- write!(f, "{}..{}", r.0, r.1)?;
- }
- }
- V::Iter(_) => {write!(f, "{pink}[Iterator]{clear}")?;},
- V::File(_) => {write!(f, "{pink}[File]{clear}")?;},
- V::Error(e) => {write!(f, "{red}{e}{clear}")?;},
- };
- Ok(())
- }
-}
-
-impl Value {
- pub fn can_hash(&self) -> Result<()> {
- use Value::*;
- match self {
- Nil => {},
- Bool(_) => {},
- Int(_) => {},
- Ratio(_) => {},
- Regex(_) => {},
- String(_) => {}
- List(l) => {
- for val in l.iter() {
- val.can_hash()?;
- }
- }
- Matrix(m) => {
- for val in m.values.iter() {
- val.can_hash()?;
- }
- },
- _ => return error!("cannot hash {self:?}")
- }
- Ok(())
- }
-
- pub fn is_zero(&self) -> bool {
- use Value as V;
- match self {
- V::Int(i) => *i == 0,
- V::Float(f) => *f == 0.0 || *f == -0.0,
- V::Ratio(r) => *r.numer() == 0,
- _ => false,
- }
- }
-}
-
-fn ratio_to_f64(r: Rational64) -> f64 {
- *r.numer() as f64 / *r.denom() as f64
-}
-
-impl Value {
- pub fn promote_trig(self) -> Self {
- use Value as V;
- match self {
- V::Int(i) => V::Float(i as f64),
- V::Ratio(r) => V::Float(ratio_to_f64(r)),
- a => a
- }
- }
-}
-
-fn promote(a: Value, b: Value) -> (Value, Value) {
- use Value as V;
- match (&a, &b) {
- (V::Int(x), V::Ratio(..)) => (V::Ratio((*x).into()), b),
- (V::Int(x), V::Float(..)) => (V::Float(*x as f64), b),
- (V::Int(x), V::Complex(..)) => (V::Complex((*x as f64).into()), b),
- (V::Ratio(x), V::Float(..)) => (V::Float(ratio_to_f64(*x)), b),
- (V::Ratio(x), V::Complex(..)) => (V::Complex(ratio_to_f64(*x).into()), b),
- (V::Float(x), V::Complex(..)) => (V::Complex((*x).into()), b),
- (V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())),
- (V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)),
- (V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())),
- (V::Float(..), V::Ratio(y)) => (a, V::Float(ratio_to_f64(*y))),
- (V::Complex(..), V::Ratio(y)) => (a, V::Complex(ratio_to_f64(*y).into())),
- (V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())),
- (V::List(l1), V::List(l2)) if l1.len() > 0 && l2.len() > 0
- => (V::Matrix(Matrix::from_list(l1.to_vec()).into()), V::Matrix(Matrix::from_list(l2.to_vec()).into())),
- (_, V::List(l)) if l.len() > 0
- => (a, V::Matrix(Matrix::from_list(l.to_vec()).into())),
- (V::List(l), _) if l.len() > 0
- => (V::Matrix(Matrix::from_list(l.to_vec()).into()), b),
- _ => (a, b),
- }
-}
-
-impl Add for Value {
- type Output = Result<Self>;
- fn add(self, rhs: Self) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x + y)),
- (Float(x), Float(y)) => Ok(Float(x + y)),
- (Ratio(x), Ratio(y)) => Ok(Ratio(x + y)),
- (Complex(x), Complex(y)) => Ok(Complex(x + y)),
- (Matrix(x), Matrix(y)) => Ok(Matrix((x + y)?.into())),
- (Matrix(x), r) => Ok(Matrix(x.increment(r)?.into())),
- (l, Matrix(y)) => Ok(Matrix(y.increment(l)?.into())),
- (String(str), value) => Ok(String(Rc::from(
- format!("{str}{value}")
- ))),
- (value, String(str)) => Ok(String(Rc::from(
- format!("{value}{str}")
- ))),
- (List(mut l1), List(l2)) => {
- l1.extend_from_slice(&l2);
- Ok(List(l1))
- },
- (l, r) => error!("cannot add: {l:?} + {r:?}")
- }
- }
-}
-
-impl Sub for Value {
- type Output = Result<Self>;
- fn sub(self, rhs: Self) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x - y)),
- (Float(x), Float(y)) => Ok(Float(x - y)),
- (Ratio(x), Ratio(y)) => Ok(Ratio(x - y)),
- (Complex(x), Complex(y)) => Ok(Complex(x - y)),
- (Matrix(x), Matrix(y)) => Ok(Matrix((x - y)?.into())),
- (Matrix(x), r) => Ok(Matrix(x.decrement(r)?.into())),
- (l, r) => error!("cannot subtract: {l:?} - {r:?}")
- }
- }
-}
-
-impl Mul for Value {
- type Output = Result<Self>;
- fn mul(self, rhs: Value) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x * y)),
- (Float(x), Float(y)) => Ok(Float(x * y)),
- (Ratio(x), Ratio(y)) => Ok(Ratio(x * y)),
- (Complex(x), Complex(y)) => Ok(Complex(x * y)),
- (Matrix(x), Matrix(y)) => Ok(Matrix((x * y)?.into())),
- (Matrix(x), r) => Ok(Matrix(x.scale(r)?.into())),
- (l, Matrix(y)) => Ok(Matrix(y.scale(l)?.into())),
- (l, r) => error!("cannot multiply: {l:?} * {r:?}")
- }
- }
-}
-
-impl Div for Value {
- type Output = Result<Self>;
- fn div(self, rhs: Value) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(_), Int(0)) => error!("cannot divide by zero"),
- (Int(x), Int(y)) => Ok(Ratio(Rational64::new(x, y))),
- (Float(x), Float(y)) => Ok(Float(x / y)),
- (Ratio(x), Ratio(y)) => Ok(Ratio(x / y)),
- (Complex(x), Complex(y)) => Ok(Complex(x / y)),
- (l, r) => error!("cannot divide: {l:?} / {r:?}")
- }
- }
-}
-
-impl BitOr for Value {
- type Output = Result<Self>;
- fn bitor(self, rhs: Value) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x | y)),
- (l, r) => error!("cannot bitwise or: {l:?} | {r:?}")
- }
- }
-}
-
-impl BitAnd for Value {
- type Output = Result<Self>;
- fn bitand(self, rhs: Value) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x & y)),
- (l, r) => error!("cannot bitwise and: {l:?} & {r:?}")
- }
- }
-}
-
-impl BitXor for Value {
- type Output = Result<Self>;
- fn bitxor(self, rhs: Value) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x ^ y)),
- (l, r) => error!("cannot bitwise xor: {l:?} ^ {r:?}")
- }
- }
-}
-
-impl Shl for Value {
- type Output = Result<Self>;
- fn shl(self, rhs: Value) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x << y)),
- (l, r) => error!("cannot bitwise shift left: {l:?} << {r:?}")
- }
- }
-}
-
-impl Shr for Value {
- type Output = Result<Self>;
- fn shr(self, rhs: Value) -> Self::Output {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x >> y)),
- (l, r) => error!("cannot bitwise shift right: {l:?} >> {r:?}")
- }
- }
-}
-
-fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> {
- Ok(match (n, d, p) {
- (0, _, 0) => return error!("cannot exponent: 0 ** 0"),
- (0, _, _) => (0, 1),
- (_, _, 0) => (1, 1),
- (1, 1, _) => (1, 1),
- (n, d, p) if p < 0 => (d.pow((-p) as u32), n.pow((-p) as u32)),
- (n, d, p) => (n.pow(p as u32), d.pow(p as u32)),
- })
-}
-
-impl Value {
-
- pub fn modulo(self, rhs: Value) -> Result<Self> {
- use Value::*;
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Int(x % y)),
- (Float(x), Float(y)) => Ok(Float(x % y)),
- (Ratio(x), Ratio(y)) => Ok(Ratio(x % y)),
- (Complex(x), Complex(y)) => Ok(Complex(x % y)),
- (l, r) => error!("cannot modulo: {l:?} % {r:?}")
- }
- }
-
- pub fn pow(self, rhs: Value) -> Result<Self> {
- use Value::*;
- if let (Ratio(x), Int(y)) = (&self, &rhs) {
- return Ok(Ratio(ipow(*(*x).numer(), *(*x).denom(), *y)?.into()));
- }
- match promote(self, rhs) {
- (Int(x), Int(y)) => Ok(Ratio(ipow(x, 1, y)?.into())),
- (Float(x), Float(y)) => Ok(Float(x.powf(y))),
- (Ratio(x), Ratio(y)) => Ok(Float(ratio_to_f64(x).powf(ratio_to_f64(y)))),
- (Complex(x), Complex(y)) => Ok(Complex(x.powc(y))),
- (l, r) => error!("cannot exponent: {l:?} ** {r:?}")
- }
- }
-
- pub fn clone_inside(&self) -> Self {
- use Value as V;
- match self {
- V::List(l) => V::List(l.clone_inside()),
- V::Table(t) => V::Table(t.clone_inside()),
- V::Matrix(m) => V::Matrix(m.clone_inside()),
- _ => self.clone()
- }
- }
-}
-
-impl Eq for Value {}
-
-impl PartialEq for Value {
- fn eq(&self, other: &Self) -> bool {
- use Value::*;
- match (self, other) {
- (Nil, Nil) => true,
- (Bool(a), Bool(b)) => a == b,
- (Int(a), Int(b)) => *a == *b,
- (Ratio(a), Ratio(b)) => *a == *b,
- (Float(a), Float(b)) => *a == *b,
- (Complex(a), Complex(b)) => *a == *b,
- (Int(a), Ratio(b)) => Rational64::from(*a) == *b,
- (Ratio(a), Int(b)) => *a == Rational64::from(*b),
- (Int(a), Float(b)) => *a as f64 == *b,
- (Float(a), Int(b)) => *a == *b as f64,
- (Int(a), Complex(b)) => Complex64::from(*a as f64) == *b,
- (Complex(a), Int(b)) => *a == Complex64::from(*b as f64),
- (Ratio(a), Float(b)) => ratio_to_f64(*a) == *b,
- (Float(a), Ratio(b)) => *a == ratio_to_f64(*b),
- (Ratio(a), Complex(b)) => Complex64::from(ratio_to_f64(*a)) == *b,
- (Complex(a), Ratio(b)) => *a == Complex64::from(ratio_to_f64(*b)),
- (Float(a), Complex(b)) => Complex64::from(*a) == *b,
- (Complex(a), Float(b)) => *a == Complex64::from(*b),
- (String(a), String(b)) => *a == *b,
- (List(a), List(b)) => *a == *b,
- (Matrix(a), Matrix(b)) => a == b,
- _ => false,
- }
- }
-}
-
-impl PartialOrd for Value {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- use Value::*;
- match (self, other) {
- (Nil, Nil) => Some(Ordering::Equal),
- (Bool(a), Bool(b)) => a.partial_cmp(b),
- (Int(a), Int(b)) => a.partial_cmp(b),
- (Ratio(a), Ratio(b)) => a.partial_cmp(b),
- (Float(a), Float(b)) => a.partial_cmp(b),
- (Int(a), Ratio(b)) => Rational64::from(*a).partial_cmp(b),
- (Ratio(a), Int(b)) => a.partial_cmp(&Rational64::from(*b)),
- (Int(a), Float(b)) => (*a as f64).partial_cmp(b),
- (Float(a), Int(b)) => a.partial_cmp(&(*b as f64)),
- (Ratio(a), Float(b)) => ratio_to_f64(*a).partial_cmp(b),
- (Float(a), Ratio(b)) => a.partial_cmp(&ratio_to_f64(*b)),
- (String(a), String(b)) => a.partial_cmp(b),
- (List(a), List(b)) => a.partial_cmp(b),
- (Matrix(a), Matrix(b)) => a.domain.partial_cmp(&b.domain),
- _ => None,
- }
- }
-}
-
-impl Value {
- pub fn val_cmp(&self, other: &Self) -> Result<Ordering> {
- self.partial_cmp(other)
- .map_or_else(|| error!("cannot compare: {self:?} and {other:?}"), Ok)
- }
-
- fn index_single(&self, index: &Value) -> Result<Self> {
- use Value as V;
- match (self, index) {
- (V::Table(t), index) => {
- Ok(t.get(index)?.unwrap_or(&Value::Nil).clone())
- },
- (V::List(l), V::Int(i)) => {
- if *i < 0 || *i as usize >= l.len() {
- return error!("{i} out of bounds for {self:?}")
- }
- Ok(l[*i as usize].clone())
- },
- (V::Matrix(m), V::Int(i)) => {
- if *i < 0 || *i as usize >= m.values.len() {
- return error!("{i} out of bounds for {self:?}")
- }
- Ok(m.values[*i as usize].clone())
- },
- _ => return error!("{index:?} cant index {self:?}")
- }
- }
-
- fn index_multiple(&self, indexes: &Vec<Value>) -> Result<Self> {
- use Value as V;
- match self {
- V::List(..) => {
- let mut ret = Vec::new();
- for index in indexes {
- let res = self.index_single(index)?;
- ret.push(res);
- }
- Ok(V::List(ret.into()))
- }
- V::Table(..) => {
- let mut ret = ValueMap::new();
- for index in indexes {
- let res = self.index_single(index)?;
- ret.insert(index.clone(), res)?;
- }
- Ok(V::Table(ret.into()))
- }
- V::Matrix(m) => {
- let err = || error!("{self:?} can be index by [Int] or [Int;Int]");
- if indexes.len() != 2 {
- return err()
- }
- let lhs = indexes[0].clone();
- let rhs = indexes[1].clone();
- match (lhs, rhs) {
- (V::Nil, V::Nil) => {
- Ok(V::Matrix(m.clone_inside()))
- },
- (V::Int(row), V::Nil) => {
- let Some((_, row)) = m.rows().enumerate().filter(|(idx, _)| *idx as i64 == row).next() else {
- return err();
- };
- let row: Vec<Value> = row.into_iter().map(|e| e.clone()).collect();
- Ok(V::Matrix(Matrix::new(row.len(), 1, row).into()))
- },
- (V::Nil, V::Int(col)) => {
- let Some((_, col)) = m.cols().enumerate().filter(|(idx, _)| *idx as i64 == col).next() else {
- return err();
- };
- let col: Vec<Value> = col.into_iter().map(|e| e.clone()).collect();
- Ok(V::Matrix(Matrix::new(1, col.len(), col).into()))
- },
- (V::Int(row), V::Int(col)) => {
- if row < 0 || col < 0 {
- return err();
- }
- m.get(row as usize, col as usize)
- }
- _ => return err()
- }
- }
- _ => return error!("cannot index {self:?}")
- }
- }
-
- pub fn index(&self, index: &Vec<Value>) -> Result<Self> {
- if index.len() == 0 {
- Ok(self.clone_inside())
- } else if index.len() == 1 {
- self.index_single(&index[0])
- } else {
- self.index_multiple(index)
- }
- }
-
- fn store_index_single(&mut self, index: &Value, store: Value) -> Result<()> {
- use Value as V;
- let err = format!("{self:?}");
- match (self, index) {
- (V::Table(t), index) => {
- t.insert(index.clone(), store)
- },
- (V::List(l), V::Int(i)) => {
- if *i < 0 || *i as usize >= l.len() {
- return error!("{i} out of bounds for {err}")
- }
- l[*i as usize] = store;
- Ok(())
- },
- (V::Matrix(m), V::Int(i)) => {
- if *i < 0 || *i as usize >= m.values.len() {
- return error!("{i} out of bounds for {err}")
- }
- m.values[*i as usize] = store;
- Ok(())
- },
- _ => return error!("{index:?} cant index {err}")
- }
- }
-
- fn store_index_multiple(&mut self, indexes: &Vec<Value>, store: Value) -> Result<()> {
- use Value as V;
- match self {
- V::List(..) => {
- for index in indexes {
- self.store_index_single(index, store.clone())?;
- }
- Ok(())
- }
- V::Table(..) => {
- for index in indexes {
- self.store_index_single(index, store.clone())?;
- }
- Ok(())
- }
- _ => return error!("cannot index {self:?}")
- }
- }
-
- pub fn store_index(&mut self, index: &Vec<Value>, store: Value) -> Result<()> {
- if index.len() == 0 {
- Ok(())
- } else if index.len() == 1 {
- self.store_index_single(&index[0], store)
- } else {
- self.store_index_multiple(index, store)
- }
- }
-
- pub fn store_field_access(&mut self, ident: &str, val: Value) -> Result<()> {
- use Value as V;
- match self {
- V::Table(t) => {
- let key = V::String(Rc::from(ident));
- Ok(t.insert(key, val)?)
- },
- _ => return error!("cannot field access assign {self:?}")
- }
- }
-
- pub fn field_access(&self, ident: &str) -> Result<Self> {
- use Value as V;
- match self {
- V::Table(t) => {
- let key = V::String(Rc::from(ident));
- Ok(t.get(&key)?.unwrap_or(&V::Nil).clone())
- },
- _ => return error!("cannot field access {self:?}")
- }
- }
-
- pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
- use BinaryOp::*;
- match op {
- Add => lhs + rhs,
- Subtract => lhs - rhs,
- Multiply => lhs * rhs,
- Divide => lhs / rhs,
- Modulo => lhs.modulo(rhs),
- Power => lhs.pow(rhs),
- BitwiseAnd => lhs & rhs,
- BitwiseOr => lhs | rhs,
- BitwiseXor => lhs ^ rhs,
- BitwiseShiftLeft => lhs << rhs,
- BitwiseShiftRight => lhs >> rhs,
- Equals => Ok(Self::Bool(lhs == rhs)),
- NotEquals => Ok(Self::Bool(lhs != rhs)),
- GreaterEquals => Ok(Self::Bool(lhs >= rhs)),
- LessEquals => Ok(Self::Bool(lhs <= rhs)),
- GreaterThan => Ok(Self::Bool(lhs > rhs)),
- LessThan => Ok(Self::Bool(lhs < rhs)),
- Range | RangeEq => {
- let Value::Int(lhs) = lhs else {
- return error!("range can only take [Int]'s")
- };
- let Value::Int(rhs) = rhs else {
- return error!("range can only take [Int]'s")
- };
- Ok(Self::Range(Rc::new((lhs, rhs, op == RangeEq))))
- },
- }
- }
-
- pub fn unary_op(op: UnaryOp, val: Value) -> Value {
- use UnaryOp::*;
- match op {
- Negate => -val,
- Not => Self::Bool(!val),
- }
- }
-}
-
-impl Neg for Value {
- type Output = Value;
-
- fn neg(self) -> Self::Output {
- use Value::*;
- match self {
- Bool(b) => Bool(!b),
- Int(i) => Int(-i),
- Float(f) => Float(-f),
- Ratio(r) => Ratio(-r),
- Complex(c) => Complex(-c),
- _ => return Float(f64::NAN)
- }
- }
-}
-
-impl Not for Value {
- type Output = bool;
-
- fn not(self) -> Self::Output {
- use Value as V;
- match self {
- V::Nil => true,
- V::Bool(b) => !b,
- V::Int(i) => i == 0,
- V::Float(f) => f == 0.0,
- V::Ratio(r) => *(r.numer()) == 0 || *(r.denom()) == 0,
- V::Complex(c) => !c.is_normal(),
- V::Regex(_) => false,
- V::List(_) => false,
- V::Matrix(_) => false,
- V::Table(_) => false,
- V::String(s) => s.as_ref() == "",
- V::Function(_) => false,
- V::Iter(_) => false,
- V::Range(_) => false,
- V::File(_) => false,
- V::Error(_) => false,
- }
- }
-}
-
-impl Value {
-
- pub fn into_iter_fn(self) -> Result<Rc<Function>> {
- let Value::Iter(iter) = self.into_iter()? else {
- return error!("bypassed iter check")
- };
- Ok(iter)
- }
-
- pub fn into_iter(self) -> Result<Self> {
- use Value as V;
- Ok(match self {
- V::Iter(..) => self,
- V::List(l) => {
- let iter = RefCell::new(l.into_inner().into_iter());
- iter!(move |_,_| {
- match iter.borrow_mut().next() {
- Some(v) => Ok(v),
- None => Ok(V::Nil),
- }
- })
- },
- V::Range(r) => {
- let r = (*r).clone();
- let lhs = RefCell::new(r.0);
- let rhs = r.1;
- iter!(move |_,_| {
- let val = *lhs.borrow();
- let next = *lhs.borrow() + 1;
- if (!r.2 && *lhs.borrow() < rhs) || (r.2 && *lhs.borrow() <= rhs) {
- *lhs.borrow_mut() = next;
- return Ok(Value::Int(val))
- }
- Ok(Value::Nil)
- })
- },
- V::Function(f) => {
- if f.arity > 0 || f.variadic {
- return error!("iterator functions cannot be varadic or take arguments")
- }
- V::Iter(f)
- },
- val => return error!("cannot turn {val:?} into an iterator")
- })
- }
-}
-
-fn dot(lhs: Vec<&Value>, rhs: Vec<&Value>) -> Result<Value> {
- let len = lhs.len();
-
- let mut res = Value::Int(0);
- for i in 0..len {
- let val = (lhs[i].clone() * rhs[i].clone())?;
- res = (res + val)?;
- }
-
- Ok(res)
-}
-
-#[derive(Clone)]
-pub struct Matrix {
- pub domain: usize,
- pub codomain: usize,
- pub values: Vec<Value>
-}
-
-impl Matrix {
- pub fn new(
- domain: usize,
- codomain: usize,
- values: Vec<Value>
- ) -> Self {
- Self {
- domain,
- codomain,
- values
- }
- }
-
- pub fn from_list(
- values: Vec<Value>
- ) -> Self {
- Self {
- domain: values.len(),
- codomain: 1,
- values
- }
- }
-
- pub fn empty(
- domain: usize,
- codomain: usize
- ) -> Self {
- let values = (0..(domain * codomain)).into_iter()
- .map(|_| Value::Int(0))
- .collect();
- Self {
- domain,
- codomain,
- values
- }
- }
-
- pub fn get(&self, row: usize, col: usize) -> Result<Value> {
- if row >= self.codomain || col >= self.domain {
- return error!("[{};{}] out of bounds for [Matrix {}x{}]", row, col, self.domain, self.codomain)
- }
- let idx = col + row * self.domain;
- Ok(self.values[idx].clone())
- }
-
-
-
- pub fn set(&mut self, row: usize, col: usize, val: Value) -> Result<()> {
- if row >= self.codomain || col >= self.domain {
- return error!("[{};{}] out of bounds for [Matrix {}x{}]", row, col, self.domain, self.codomain)
- }
- let idx = col + row * self.domain;
- self.values[idx] = val;
- Ok(())
- }
-
- pub fn rows<'a>(&'a self) -> MatrixRows<'a> {
- MatrixRows {
- matrix: self,
- row: 0
- }
- }
-
- pub fn cols<'a>(&'a self) -> MatrixCols<'a> {
- MatrixCols {
- matrix: self,
- col: 0
- }
- }
-
- // SPLCIE DOMAIN
- pub fn splice_cols(&self, col_start: usize, col_end: usize) -> Result<Self> {
- if col_start <= col_end || col_end > self.domain {
- return error!("[_;{}..{}] invalid for [Matrix {}x{}]", col_start, col_end, self.domain, self.codomain)
- }
-
- let mut cols = Vec::new();
-
- for (i, col) in self.cols().enumerate() {
- if i >= col_start && i < col_end {
- cols.push(col);
- }
- }
-
- let domain = cols.len();
- let codomain = cols[0].len();
- let mut res = Self::empty(domain, codomain);
-
- for i in 0..domain {
- for j in 0..codomain {
- res.set(j, i, cols[i][j].clone())?;
- }
- }
-
- Ok(res)
- }
-
- // SPLICE CODOMAIN
- pub fn splice_rows(&self, row_start: usize, row_end: usize) -> Result<Self> {
- if row_start <= row_end || row_end > self.codomain {
- return error!("[{}..{};_] invalid for [Matrix {}x{}]", row_start, row_end, self.domain, self.codomain)
- }
-
- let mut rows = Vec::new();
-
- for (i, row) in self.rows().enumerate() {
- if i >= row_start && i < row_end {
- rows.push(row);
- }
- }
-
- let domain = rows[0].len();
- let codomain = rows.len();
- let mut res = Self::empty(domain, codomain);
-
- for i in 0..domain {
- for j in 0..codomain {
- res.set(j, i, rows[j][i].clone())?;
- }
- }
-
- Ok(res)
- }
-
- pub fn increment(&self, increment: Value) -> Result<Self> {
- let values = self.values.iter()
- .map(|v| v.clone() + increment.clone())
- .collect::<Result<Vec<Value>>>()?;
- Ok(Matrix::new(self.domain, self.codomain, values))
- }
-
- pub fn decrement(&self, decrement: Value) -> Result<Self> {
- let values = self.values.iter()
- .map(|v| v.clone() - decrement.clone())
- .collect::<Result<Vec<Value>>>()?;
- Ok(Matrix::new(self.domain, self.codomain, values))
- }
-
- pub fn scale(&self, scale: Value) -> Result<Self> {
- let values = self.values.iter()
- .map(|v| v.clone() * scale.clone())
- .collect::<Result<Vec<Value>>>()?;
- Ok(Matrix::new(self.domain, self.codomain, values))
- }
-
- pub fn join_right(&self, other: &Matrix) -> Result<Self> {
- if self.codomain != other.codomain {
- return error!("matrix codomain's do not match");
- }
- let mut r1 = self.rows();
- let mut r2 = other.rows();
- let mut rows = Vec::new();
- loop {
- let Some(r1) = r1.next() else { break; };
- let Some(r2) = r2.next() else { break; };
-
- let mut row = r1
- .into_iter()
- .map(|v| v.clone())
- .collect::<Vec<Value>>();
-
- row.extend(r2.into_iter().map(|v| v.clone()));
-
- rows.push(row);
- }
-
- let values = rows
- .into_iter()
- .reduce(|mut a,b| {a.extend(b); a})
- .unwrap();
-
- Ok(Matrix::new(self.domain + other.domain, self.codomain, values))
- }
-
- pub fn join_bottom(&self, other: &Matrix) -> Result<Self> {
- if self.domain != other.domain {
- return error!("matrix domain's do not match");
- }
- let mut values = self.values.clone();
- values.extend(other.values.clone());
- Ok(Matrix::new(self.domain, self.codomain + other.codomain, values))
- }
-}
-
-impl Debug for Matrix {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "[Matrix {}x{}]", self.domain, self.codomain)
- }
-}
-
-impl PartialEq for Matrix {
- fn eq(&self, other: &Self) -> bool {
- if self.domain != other.domain || self.codomain != other.codomain {
- return false
- }
-
- for i in 0..self.values.len() {
- if self.values[i] != other.values[i] {
- return false;
- }
- }
-
- return true;
- }
-}
-
-impl Add for Matrix {
- type Output = Result<Self>;
-
- fn add(self, rhs: Self) -> Self::Output {
- if self.domain != rhs.domain || self.codomain != rhs.codomain {
- return error!("cannot add: [Matrix {}x{}] + [Matrix {}x{}]",
- self.domain, self.codomain,
- rhs.domain, rhs.codomain)
- }
- let mut res = Matrix::empty(self.domain, self.codomain);
- for col in 0..self.domain {
- for row in 0..self.codomain {
- let add = self.get(row, col)? + rhs.get(row, col)?;
- res.set(row, col, add?)?;
- }
- }
- Ok(res)
- }
-}
-
-impl Sub for Matrix {
- type Output = Result<Self>;
-
- fn sub(self, rhs: Self) -> Self::Output {
- if self.domain != rhs.domain || self.codomain != rhs.codomain {
- return error!("cannot sub: [Matrix {}x{}] - [Matrix {}x{}]",
- self.domain, self.codomain,
- rhs.domain, rhs.codomain)
- }
- let mut res = Matrix::empty(self.domain, self.codomain);
- for col in 0..self.domain {
- for row in 0..self.codomain {
- let sub = self.get(row, col)? - rhs.get(row, col)?;
- res.set(row, col, sub?)?;
- }
- }
- Ok(res)
- }
-}
-
-impl Mul for Matrix {
- type Output = Result<Self>;
-
- fn mul(self, rhs: Self) -> Self::Output {
- if self.domain != rhs.codomain {
- return error!("cannot multiply: [Matrix {}x{}] * [Matrix {}x{}]",
- self.domain, self.codomain,
- rhs.domain, rhs.codomain)
- }
- let mut res = Self::empty(rhs.domain, self.codomain);
- for (i, row) in self.rows().enumerate() {
- for (j, col) in rhs.cols().enumerate() {
- let dot = dot(row.clone(), col.clone())?;
- res.set(i, j, dot)?;
- }
- }
- Ok(res)
- }
-}
-
-pub struct MatrixRows<'a> {
- matrix: &'a Matrix,
- row: usize
-}
-
-impl<'a> Iterator for MatrixRows<'a> {
- type Item = Vec<&'a Value>;
-
- fn next(&mut self) -> Option<Self::Item> {
- if self.row >= self.matrix.codomain {
- return None
- }
-
- let row_start = self.row * self.matrix.domain;
- let row_end = row_start + self.matrix.domain;
-
- let res = self.matrix.values
- .iter()
- .enumerate()
- .filter(|(idx, _)| *idx >= row_start && *idx < row_end)
- .map(|v| v.1)
- .collect();
-
- self.row += 1;
-
- Some(res)
- }
-}
-
-pub struct MatrixCols<'a> {
- matrix: &'a Matrix,
- col: usize
-}
-
-impl<'a> Iterator for MatrixCols<'a> {
- type Item = Vec<&'a Value>;
-
- fn next(&mut self) -> Option<Self::Item> {
- if self.col >= self.matrix.domain {
- return None
- }
-
- let res = self.matrix.values
- .iter()
- .enumerate()
- .filter(|(idx, _)| *idx % self.matrix.domain == self.col)
- .map(|v| v.1)
- .collect();
-
- self.col += 1;
-
- Some(res)
- }
-}
-
-impl Display for Matrix {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let mut max_cols = vec![0; self.domain];
- let mut vals: Vec<String> = Vec::with_capacity(self.domain * self.codomain);
- for row in 0..self.codomain {
- for col in 0..self.domain {
- let idx = col + row * self.domain;
- let el = &self.values[idx];
- let s = match f.alternate() {
- true => format!("{:#}", el),
- false => format!("{}", el)
- };
- max_cols[col] = max_cols[col].max(s.len());
- vals.push(s);
- }
- }
-
- write!(f, "\n")?;
- for row in 0..self.codomain {
- for col in 0..self.domain {
- let idx = col + row * self.domain;
- let s = vals[idx].as_str();
- let width = max_cols[col];
- write!(f, " {s:>width$}")?;
- }
- write!(f, "\n")?;
- }
-
- Ok(())
- }
-}