diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..2c821bc --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,23 @@ +name: Rust + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Checkout submodules + shell: bash + run: | + # If your submodules are configured to use SSH instead of HTTPS please uncomment the following line + # git config --global url."https://github.com/".insteadOf "git@github.com:" + auth_header="$(git config --local --get http.https://github.com/.extraheader)" + git submodule sync --recursive + git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 + - name: Build + run: cargo build --locked --verbose + - name: Run tests + run: cargo test --locked --verbose diff --git a/Cargo.lock b/Cargo.lock index 8571919..a174357 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,6 +16,22 @@ dependencies = [ "const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "aho-corasick" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atty" version = "0.2.14" @@ -56,6 +72,11 @@ name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytecount" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.3.2" @@ -227,6 +248,10 @@ dependencies = [ "hashlink 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "hmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "jlight-vm 0.1.0", + "nom 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom-packrat 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom-recursive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "regalloc 0.0.1", ] @@ -235,6 +260,18 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lexical-core" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" version = "0.2.66" @@ -265,6 +302,11 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memoffset" version = "0.5.3" @@ -282,6 +324,69 @@ dependencies = [ "libmimalloc-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nom" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nom-packrat" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom-packrat-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nom-packrat-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nom-recursive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom-recursive-macros 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nom-recursive-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nom_locate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num_cpus" version = "1.12.0" @@ -352,6 +457,22 @@ dependencies = [ "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc-demangle" version = "0.1.16" @@ -373,6 +494,11 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "1.0.0" @@ -396,6 +522,11 @@ name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "static_assertions" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "1.0.14" @@ -414,11 +545,24 @@ dependencies = [ "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -454,11 +598,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" "checksum ahash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0989268a37e128d4d7a8028f1c60099430113fdbc70419010601ce51a228e4fe" +"checksum aho-corasick 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5f56c476256dc249def911d6f7580b5fc7e875895b5d7ee88f5d602208035744" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "7f80256bc78f67e7df7e36d77366f636ed976895d91fe2ab9efa3973e8fe8c4f" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" @@ -478,12 +625,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" "checksum hmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92fbd0445bda1ac099b76a3fbad67668f915f1873cc1d9b47c02889211fa1ace" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum libmimalloc-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5cc0c6c08cecf3766641f1e60072a9031fb60567c3dd08e5374fffbf198ea96b" "checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" "checksum mimalloc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "d1c5de6f9778f47c43e872159578a3d72779f55b40a1da4f57fe9220c14a39b1" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +"checksum nom 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c433f4d505fe6ce7ff78523d2fa13a0b9f2690e181fc26168bcbe5ccc5d14e07" +"checksum nom-packrat 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebe0000c3976925b8061384e7c5d464415557a9df7eb650e672c08715015845" +"checksum nom-packrat-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f385978c3d5019786a9114bae4df8feea277da06ac4e4a4f924bd58ccc6c6c9" +"checksum nom-recursive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1fb9373dbaba1dc5ec078eaf12294a9a255207bce8341c5dfb6eb29f99d1e929" +"checksum nom-recursive-macros 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88458f0accd9f629bc0ba5bb8cf5a1aeeaf0d5a7237ed4524b62b4cb2bc7bb24" +"checksum nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f932834fd8e391fc7710e2ba17e8f9f8645d846b55aa63207e17e110a1e1ce35" "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" "checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" @@ -491,16 +647,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" +"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" +"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" diff --git a/Cargo.toml b/Cargo.toml index f375de2..c82f01f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,10 @@ hmap = "0.1" jlight-vm = {path = "jlight-vm"} regalloc = {path = "jlight-vm/regalloc.rs/lib"} hashlink = "0.4" +nom_locate = "1.0.0" +nom-recursive = "0.1.1" +nom-packrat = "0.3.0" +[dependencies.nom] +version = "5.1.0" +features = ["regexp_macros"] diff --git a/src/ast.rs b/src/ast.rs index 0007956..9b0eee8 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,21 +1,45 @@ use crate::token::Position; +use core::ops::Deref; +use std::borrow::Borrow; -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Default)] pub struct Expr { pub pos: Position, pub expr: ExprKind, } +#[derive(Clone, Debug, PartialEq)] +pub struct Ident(pub String); + +impl From for String { + fn from(ident: Ident) -> Self { + ident.0 + } +} + +impl Deref for Ident { + type Target = String; + fn deref(&self) -> &String { + &self.0 + } +} + +impl Borrow for Ident { + fn borrow(&self) -> &String { + &self.0 + } +} + #[derive(Clone, Debug, PartialEq)] pub enum ExprKind { Assign(Box, Box), BinOp(Box, String, Box), Unop(String, Box), - Access(Box, String), - Ident(String), - Function(Option, Vec, Box), + Access(Box, Ident), + Ident(Ident), + Function(Option, Vec, Box), Class(String, Box, Option>), - Lambda(Vec, Box), + Lambda(Vec, Box), Match(Box, Vec<(Box, Box)>, Option>), If(Box, Box, Option>), ConstInt(i64), @@ -24,7 +48,7 @@ pub enum ExprKind { New(Box), ConstFloat(f64), Object(Vec<(Box, Box)>), - Var(bool, String, Option>), + Var(bool, Ident, Option>), While(Box, Box), Block(Vec>), Return(Option>), @@ -32,13 +56,19 @@ pub enum ExprKind { Nil, Break, Continue, - Throw(String), + Throw(Box), ConstBool(bool), Array(Vec>), ArrayIndex(Box, Box), This, } +impl Default for ExprKind { + fn default() -> Self { + ExprKind::Nil + } +} + use std::fmt; impl Expr { diff --git a/src/codegen.rs b/src/codegen.rs index 475d079..7d58a3c 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -236,23 +236,23 @@ impl Context { pub fn compile_access(&mut self, e: &ExprKind) -> Access { match e { ExprKind::Ident(name) => { - let l = self.locals.get(name); + let l = self.locals.get(name as &str); let s: &str = name; if l.is_some() { let l = *l.unwrap(); - return Access::Stack(name.to_owned(), l); + return Access::Stack(name.to_owned().to_string(), l); } else if self.env.contains_key(s) { let l = self.env.get(s); self.used_upvars.insert(s.to_owned(), *l.unwrap()); self.nenv += 1; return Access::Env(*l.unwrap()); } else { - let (g, n) = self.global(&Global::Var(name.to_owned())); - return Access::Global(g, n, name.to_owned()); + let (g, n) = self.global(&Global::Var(name.to_owned().to_string())); + return Access::Global(g, n, name.to_owned().to_string()); } } ExprKind::Access(e, f) => { - return Access::Field(e.clone(), f.to_owned()); + return Access::Field(e.clone(), String::from(f.to_owned())); } ExprKind::This => Access::This, ExprKind::ArrayIndex(ea, ei) => { @@ -430,7 +430,7 @@ impl Context { r } }; - self.locals.insert(name.to_owned(), r as _); + self.locals.insert(String::from(name.to_owned()), r as _); r } @@ -583,7 +583,7 @@ impl Context { ExprKind::Access(object, fields) => { let this = self.compile(object, tail); let field = self.new_reg(); - let (s, _) = self.global(&Global::Str(fields.to_owned())); + let (s, _) = self.global(&Global::Str(fields.to_owned().to_string())); let sr = self.new_reg(); self.write(Instruction::LoadGlobal(sr, s as _)); self.write(Instruction::Load(field, this, sr)); @@ -654,9 +654,9 @@ impl Context { pub fn compile_function( &mut self, - params: &[String], + params: &[Ident], e: &Box, - vname: Option, + vname: Option, ) -> u32 { let mut ctx = Context { g: self.g.clone(), @@ -681,15 +681,15 @@ impl Context { ctx.stack += 1; let r = ctx.new_reg(); ctx.write(Instruction::Pop(r)); - ctx.locals.insert(p.to_owned(), r as _); + ctx.locals.insert(String::from(p.to_owned()), r as _); } let gid = ctx.g.borrow().table.len(); if vname.is_some() { - ctx.g - .borrow_mut() - .globals - .insert(Global::Var(vname.as_ref().unwrap().to_owned()), gid as i32); + ctx.g.borrow_mut().globals.insert( + Global::Var(String::from(vname.as_ref().unwrap().to_owned())), + gid as i32, + ); } ctx.g.borrow_mut().table.push(Global::Func(gid as i32, -1)); let r = ctx.compile(e, true); @@ -704,7 +704,9 @@ impl Context { ctx.pos.clone(), gid as i32, params.len() as i32, - vname.unwrap_or(String::from("")), + vname + .map(String::from) + .unwrap_or(String::from("")), )); if ctx.nenv > 0 { diff --git a/src/main.rs b/src/main.rs index 56f1328..dac38cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,11 +8,11 @@ fn main() { let start_time = std::time::Instant::now(); let mut ast = vec![]; let r = Reader::from_string( - " + " ", ); let mut p = Parser::new(r, &mut ast); - p.parse().unwrap(); + //p.parse().unwrap(); let mut ctx = compile(ast); ctx.finalize(); let state = jlight_vm::util::arc::Arc::new(jlight_vm::runtime::state::State::new()); diff --git a/src/parser.rs b/src/parser.rs index 297d800..3a98a8a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,30 @@ +use crate::ast::Ident; use crate::ast::*; use crate::lexer::*; use crate::msg::*; use crate::reader::Reader; use crate::token::*; +use nom::combinator::all_consuming; +use nom::combinator::map_opt; +use nom::combinator::map_parser; +use nom::combinator::not; +use nom::combinator::recognize; +use nom::combinator::value; +use nom::AsChar; +use nom::InputTakeAtPosition; +use nom::{ + branch::alt, + bytes::complete::{escaped, tag}, + character::complete::{anychar, none_of, one_of}, + combinator::{map, opt}, + multi::{many0, separated_list}, + number::complete::double, + sequence::{pair, preceded, terminated, tuple}, + Err, IResult, +}; +use nom_locate::LocatedSpanEx; +use nom_recursive::{recursive_parser, RecursiveInfo}; +use nom_packrat::{init, packrat_parser, storage, HasExtraState}; use std::mem; pub struct Parser<'a> { @@ -19,487 +41,465 @@ macro_rules! expr { }) }; } - -type EResult = Result, MsgWithPos>; - -impl<'a> Parser<'a> { - pub fn new(reader: Reader, ast: &'a mut Vec>) -> Parser<'a> { - Self { - lexer: Lexer::new(reader), - token: Token::new(TokenKind::End, Position::new(1, 1)), - ast, - } - } - - fn init(&mut self) -> Result<(), MsgWithPos> { - self.advance_token()?; - - Ok(()) - } - - pub fn parse(&mut self) -> Result<(), MsgWithPos> { - self.init()?; - while !self.token.is_eof() { - self.parse_top_level()?; +macro_rules! exp { + ($e:expr) => { + Expr { + pos: Position::default(), + expr: $e, } - Ok(()) - } + }; +} - fn expect_token(&mut self, kind: TokenKind) -> Result { - if self.token.kind == kind { - let token = self.advance_token()?; +#[derive(Ord, PartialOrd, Eq, PartialEq, Clone)] +pub enum OperatorPrecedence { + None, + Or, + And, + Assign, + Cmp, + Bit, + AddShift, + Mul, +} - Ok(token) - } else { - Err(MsgWithPos::new( - self.token.position, - Msg::ExpectedToken(kind.name().into(), self.token.name()), - )) - } - } +type Span<'a> = LocatedSpanEx<&'a str, Option>; - fn parse_top_level(&mut self) -> Result<(), MsgWithPos> { - let expr = self.parse_expression()?; +type EResult<'a> = IResult, Expr>; - self.ast.push(expr); - Ok(()) - } +fn alphanumeric_underscore0<'b>(input: Span<'b>) -> IResult, Span<'b>> +where + as InputTakeAtPosition>::Item: AsChar, +{ + input.split_at_position_complete(|item| !(item.is_alphanum() || item == '_')) +} - fn parse_function_param(&mut self) -> Result { - let name = self.expect_identifier()?; - Ok(name) - } +fn expect_identifier<'b>(i: Span<'b>) -> IResult, String> { + map( + map_parser( + recognize(tuple(( + map_opt(anychar, |c| { + if c.is_alpha() || c == '_' { + Some(()) + } else { + None + } + }), + alphanumeric_underscore0, + ))), + recognize( + // Filter out lone underscores, because those aren't identifiers. + not(all_consuming(tag("_"))), + ), + ), + |s: Span| s.to_string(), + )(i) +} - fn parse_function(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::Fun)?.position; - let name = if let TokenKind::Identifier(_) = &self.token.kind { - Some(self.expect_identifier()?) - } else { - None - }; - self.expect_token(TokenKind::LParen)?; - let params = if self.token.kind == TokenKind::RParen { - vec![] - } else { - let mut tmp = vec![]; - while !self.token.is(TokenKind::RParen) { - tmp.push(self.expect_identifier()?); - if !self.token.is(TokenKind::RParen) { - self.expect_token(TokenKind::Comma)?; - } - } - tmp - }; - self.expect_token(TokenKind::RParen)?; - let block = self.parse_block()?; - Ok(expr!(ExprKind::Function(name, params, block), pos)) - } +fn parse_nil<'b>(i: Span) -> EResult { + value(exp!(ExprKind::Nil), tag("nil"))(i) +} - fn parse_let(&mut self) -> EResult { - let reassignable = self.token.is(TokenKind::Var); +fn parse_bool_literal<'b>(i: Span) -> EResult { + let parse_true = value(exp!(ExprKind::ConstBool(true)), tag("true")); + let parse_false = value(exp!(ExprKind::ConstBool(false)), tag("false")); - let pos = self.advance_token()?.position; - let ident = self.expect_identifier()?; - let expr = if self.token.is(TokenKind::Eq) { - self.expect_token(TokenKind::Eq)?; - let expr = self.parse_expression()?; - Some(expr) - } else { - None - }; - Ok(expr!(ExprKind::Var(reassignable, ident, expr), pos)) - } + alt((parse_true, parse_false))(i) +} - fn parse_return(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::Return)?.position; - let expr = self.parse_expression()?; - Ok(expr!(ExprKind::Return(Some(expr)), pos)) - } +fn lit_int<'b>(i: Span) -> EResult { + /*let tok = self.advance_token()?; + let pos = tok.position; + if let TokenKind::LitInt(i, _, _) = tok.kind { + Ok(expr!(ExprKind::ConstInt(i.parse().unwrap()), pos)) + } else { + unreachable!() + }*/ + unimplemented!() +} - fn parse_expression(&mut self) -> EResult { - match self.token.kind { - TokenKind::New => { - let pos = self.advance_token()?.position; - let calling = self.parse_expression()?; - Ok(expr!(ExprKind::New(calling), pos)) - } - TokenKind::Fun => self.parse_function(), - TokenKind::Match => self.parse_match(), - TokenKind::Let | TokenKind::Var => self.parse_let(), - TokenKind::LBrace => self.parse_block(), - TokenKind::If => self.parse_if(), - TokenKind::While => self.parse_while(), - TokenKind::Break => self.parse_break(), - TokenKind::Continue => self.parse_continue(), - TokenKind::Return => self.parse_return(), - TokenKind::Throw => self.parse_throw(), - _ => self.parse_binary(0), - } - } +fn lit_char<'b>(i: Span) -> EResult { + map(preceded(tag("'"), terminated(anychar, tag("'"))), |c| { + exp!(ExprKind::ConstChar(c)) + })(i) +} - fn parse_self(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::This)?.position; - Ok(expr!(ExprKind::This, pos)) - } +fn lit_float<'b>(i: Span) -> EResult { + map(double, |f| exp!(ExprKind::ConstFloat(f)))(i) +} - fn parse_break(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::Break)?.position; - Ok(expr!(ExprKind::Break, pos)) - } - fn parse_continue(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::Continue)?.position; - Ok(expr!(ExprKind::Continue, pos)) - } +fn lit_str<'b>(i: Span) -> EResult { + map( + preceded( + tag("\""), + terminated(escaped(none_of("\\\""), '"', one_of("\\\"")), tag("\"")), + ), + |s: Span| exp!(ExprKind::ConstStr(s.to_string())), + )(i) +} - fn parse_throw(&mut self) -> EResult { - let pos = self.token.position; - if let TokenKind::String(s) = self.token.clone().kind { - self.advance_token()?; - return Ok(expr!(ExprKind::Throw(s.clone()), pos)); - } else { - panic!("String expected at {}", pos) - } +pub fn parse<'b>(i: Span) -> Result<(), MsgWithPos> { + /* self.init()?; + while !self.token.is_eof() { + self.parse_top_level()?; } + Ok(())*/ + unimplemented!() +} - fn parse_while(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::While)?.position; - let cond = self.parse_expression()?; - let block = self.parse_block()?; - Ok(expr!(ExprKind::While(cond, block), pos)) - } +fn expect_token<'b>(i: Span, kind: TokenKind) -> Result { + /*if self.token.kind == kind { + let token = self.advance_token()?; - fn parse_match(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::Match)?.position; - let value = self.parse_expression()?; - self.expect_token(TokenKind::LBrace)?; - let mut data = vec![]; - let mut or = None; - while !self.token.is(TokenKind::RBrace) && !self.token.is_eof() { - if self.token.is(TokenKind::Underscore) { - self.expect_token(TokenKind::Underscore)?; - self.expect_token(TokenKind::Arrow)?; - let expr = self.parse_expression()?; - or = Some(expr); - continue; - } - let cond = self.parse_expression()?; - self.expect_token(TokenKind::Arrow)?; - let expr = self.parse_expression()?; - data.push((cond, expr)); - } + Ok(token) + } else { + Err(MsgWithPos::new( + self.token.position, + Msg::ExpectedToken(kind.name().into(), self.token.name()), + )) + }*/ + unimplemented!() +} - self.expect_token(TokenKind::RBrace)?; +fn parse_top_level<'b>(i: Span) -> Result<(), MsgWithPos> { + /*let expr = self.parse_expression()?; - Ok(expr!(ExprKind::Match(value, data, or), pos)) - } + self.ast.push(expr); + Ok(())*/ + unimplemented!() +} - fn parse_if(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::If)?.position; - let cond = self.parse_expression()?; - let then_block = self.parse_expression()?; - let else_block = if self.token.is(TokenKind::Else) { - self.advance_token()?; - - if self.token.is(TokenKind::If) { - let if_block = self.parse_if()?; - let block = expr!(ExprKind::Block(vec![if_block]), if_block.pos); - - Some(block) - } else { - Some(self.parse_expression()?) - } - } else { - None - }; - - Ok(expr!(ExprKind::If(cond, then_block, else_block), pos)) - } +fn parse_function_param<'b>(i: Span) -> Result { + /*let name = self.expect_identifier()?; + Ok(name)*/ + unimplemented!() +} - fn parse_block(&mut self) -> EResult { - let pos = self.expect_token(TokenKind::LBrace)?.position; - let mut exprs = vec![]; - while !self.token.is(TokenKind::RBrace) && !self.token.is_eof() { - let expr = self.parse_expression()?; - exprs.push(expr); - } - self.expect_token(TokenKind::RBrace)?; - Ok(expr!(ExprKind::Block(exprs), pos)) - } +fn parse_function<'b>(i: Span) -> EResult { + let fn_arg_sep = tag(","); + let fn_arg = map(expect_identifier, Ident); + let tup = tuple(( + opt(map(expect_identifier, Ident)), + tag("("), + separated_list(fn_arg_sep, fn_arg), + tag(")"), + parse_block, + )); + map(tup, |(name, _, params, _, block)| { + exp!(ExprKind::Function(name, params, Box::new(block))) + })(i) +} - fn create_binary(&mut self, tok: Token, left: Box, right: Box) -> Box { - let op = match tok.kind { - TokenKind::Eq => return expr!(ExprKind::Assign(left, right), tok.position), - TokenKind::Or => "||", - TokenKind::And => "&&", - TokenKind::BitOr => "|", - TokenKind::BitAnd => "&", - TokenKind::EqEq => "==", - TokenKind::Ne => "!=", - TokenKind::Lt => "<", - TokenKind::Gt => ">", - TokenKind::Le => "<=", - TokenKind::Ge => ">=", - TokenKind::Caret => "^", - TokenKind::Add => "+", - TokenKind::Sub => "-", - TokenKind::Mul => "*", - TokenKind::Div => "/", - TokenKind::LtLt => "<<", - TokenKind::GtGt => ">>", - TokenKind::Mod => "%", - _ => unimplemented!(), - }; - - expr!(ExprKind::BinOp(left, op.to_owned(), right), tok.position) - } +fn parse_let<'b>(i: Span) -> EResult { + //let reassignable = alt((value(true, tag("var")), value(false, tag("let")))); + + let initialization = map( + tuple(( + //reassignable, + alt((value(true, tag("var")), value(false, tag("let")))), + map(expect_identifier, Ident), + tag("="), + map(parse_expression, |expr| Some(Box::new(expr))), + )), + |(r, i, _, e)| exp!(ExprKind::Var(r, i, e)), + ); + let declaration = map( + tuple(( + //reassignable, + alt((value(true, tag("var")), value(false, tag("let")))), + map(expect_identifier, Ident), + )), + |(r, i)| exp!(ExprKind::Var(r, i, None)), + ); + alt((initialization, declaration))(i) +} - fn parse_binary(&mut self, precedence: u32) -> EResult { - let mut left = self.parse_unary()?; - loop { - let right_precedence = match self.token.kind { - TokenKind::Or => 1, - TokenKind::And => 2, - TokenKind::Eq => 3, - TokenKind::EqEq - | TokenKind::Ne - | TokenKind::Lt - | TokenKind::Le - | TokenKind::Gt - | TokenKind::Ge => 4, - TokenKind::BitOr | TokenKind::BitAnd | TokenKind::Caret => 6, - TokenKind::LtLt | TokenKind::GtGt | TokenKind::Add | TokenKind::Sub => 8, - TokenKind::Mul | TokenKind::Div | TokenKind::Mod => 9, - _ => { - return Ok(left); - } - }; - if precedence >= right_precedence { - return Ok(left); - } - - let tok = self.advance_token()?; - left = { - let right = self.parse_binary(right_precedence)?; - self.create_binary(tok, left, right) - }; - } - } +fn parse_return<'b>(i: Span) -> EResult { + map(pair(tag("return"), opt(parse_expression)), |(_, expr)| { + exp!(ExprKind::Return(expr.map(Box::new))) + })(i) +} - pub fn parse_unary(&mut self) -> EResult { - match self.token.kind { - TokenKind::Add | TokenKind::Sub | TokenKind::Not => { - let tok = self.advance_token()?; - let op = match tok.kind { - TokenKind::Add => String::from("+"), - TokenKind::Sub => String::from("-"), - TokenKind::Not => String::from("!"), - _ => unreachable!(), - }; - let expr = self.parse_primary()?; - Ok(expr!(ExprKind::Unop(op, expr), tok.position)) - } - _ => self.parse_primary(), - } - } +fn parse_expression<'b>(i: Span) -> EResult { + let parse_new = preceded(tag("new"), parse_expression); + alt(( + parse_new, + parse_function, + parse_match, + parse_let, + parse_block, + parse_if, + parse_while, + parse_break, + parse_continue, + parse_return, + parse_throw, + map(parse_binary, |(expr, _)| expr), + ))(i) +} - /*pub fn parse_expression(&mut self) -> EResult { - self.parse_binary(0) - }*/ +fn parse_self<'b>(i: Span) -> EResult { + value(exp!(ExprKind::This), tag("self"))(i) +} - fn parse_call(&mut self) -> EResult { - let expr = self.parse_expression()?; +fn parse_break<'b>(i: Span) -> EResult { + value(exp!(ExprKind::Break), tag("break"))(i) +} - self.expect_token(TokenKind::LParen)?; +fn parse_continue<'b>(i: Span) -> EResult { + value(exp!(ExprKind::Continue), tag("continue"))(i) +} - let args = self.parse_comma_list(TokenKind::RParen, |p| p.parse_expression())?; +fn parse_throw<'b>(i: Span) -> EResult { + map(pair(tag("throw"), parse_expression), |(_, expr)| { + exp!(ExprKind::Throw(Box::new(expr))) + })(i) +} - Ok(expr!(ExprKind::Call(expr, args), expr.pos)) - } +fn parse_while<'b>(i: Span) -> EResult { + map( + tuple((tag("while"), parse_expression, parse_block)), + |(_, expr, block)| exp!(ExprKind::While(Box::new(expr), Box::new(block))), + )(i) +} - pub fn parse_primary(&mut self) -> EResult { - let mut left = self.parse_factor()?; - loop { - left = match self.token.kind { - TokenKind::Dot => { - let tok = self.advance_token()?; - let ident = self.expect_identifier()?; - expr!(ExprKind::Access(left, ident), tok.position) - } - TokenKind::LBracket => { - let tok = self.advance_token()?; - let index = self.parse_expression()?; - self.expect_token(TokenKind::RBracket)?; - expr!(ExprKind::ArrayIndex(left, index), tok.position) - } - _ => { - if self.token.is(TokenKind::LParen) { - let expr = left; - - self.expect_token(TokenKind::LParen)?; - - let args = - self.parse_comma_list(TokenKind::RParen, |p| p.parse_expression())?; - - expr!(ExprKind::Call(expr, args), expr.pos) - } else { - return Ok(left); - } - } - } +fn parse_match<'b>(i: Span) -> EResult { + /*let pos = self.expect_token(TokenKind::Match)?.position; + let value = self.parse_expression()?; + self.expect_token(TokenKind::LBrace)?; + let mut data = vec![]; + let mut or = None; + while !self.token.is(TokenKind::RBrace) && !self.token.is_eof() { + if self.token.is(TokenKind::Underscore) { + self.expect_token(TokenKind::Underscore)?; + self.expect_token(TokenKind::Arrow)?; + let expr = self.parse_expression()?; + or = Some(expr); + continue; } + let cond = self.parse_expression()?; + self.expect_token(TokenKind::Arrow)?; + let expr = self.parse_expression()?; + data.push((cond, expr)); } - fn expect_identifier(&mut self) -> Result { - let tok = self.advance_token()?; + self.expect_token(TokenKind::RBrace)?; - if let TokenKind::Identifier(ref value) = tok.kind { - Ok(value.to_owned()) - } else { - Err(MsgWithPos::new( - tok.position, - Msg::ExpectedIdentifier(tok.name()), + Ok(expr!(ExprKind::Match(value, data, or), pos))*/ + unimplemented!() +} + +fn parse_if<'b>(i: Span) -> EResult { + map( + tuple(( + preceded(tag("if"), parse_expression), + preceded(tag("then"), parse_expression), + opt(preceded(tag("else"), parse_expression)), + )), + |(cond, then_block, else_block)| { + exp!(ExprKind::If( + Box::new(cond), + Box::new(then_block), + else_block.map(Box::new) )) - } - } + }, + )(i) +} - fn parse_comma_list( - &mut self, - stop: TokenKind, - mut parse: F, - ) -> Result, MsgWithPos> - where - F: FnMut(&mut Parser) -> Result, - { - let mut data = vec![]; - let mut comma = true; - - while !self.token.is(stop.clone()) && !self.token.is_eof() { - if !comma { - return Err(MsgWithPos::new( - self.token.position, - Msg::ExpectedToken(TokenKind::Comma.name().into(), self.token.name()), - )); - } - - let entry = parse(self)?; - data.push(entry); - - comma = self.token.is(TokenKind::Comma); - if comma { - self.advance_token()?; - } - } +fn parse_block<'b>(i: Span) -> EResult { + map( + preceded( + tag("{"), + terminated( + many0(map(parse_expression, |expr| Box::new(expr))), + tag("}"), + ), + ), + |exprs| exp!(ExprKind::Block(exprs)), + )(i) +} - self.expect_token(stop)?; +fn create_binary(tok: Token, left: Box, right: Box) -> Box { + /*let op = match tok.kind { + TokenKind::Eq => return expr!(ExprKind::Assign(left, right), tok.position), + TokenKind::Or => "||", + TokenKind::And => "&&", + TokenKind::BitOr => "|", + TokenKind::BitAnd => "&", + TokenKind::EqEq => "==", + TokenKind::Ne => "!=", + TokenKind::Lt => "<", + TokenKind::Gt => ">", + TokenKind::Le => "<=", + TokenKind::Ge => ">=", + TokenKind::Caret => "^", + TokenKind::Add => "+", + TokenKind::Sub => "-", + TokenKind::Mul => "*", + TokenKind::Div => "/", + TokenKind::LtLt => "<<", + TokenKind::GtGt => ">>", + TokenKind::Mod => "%", + _ => unimplemented!(), + }; - Ok(data) - } + expr!(ExprKind::BinOp(left, op.to_owned(), right), tok.position)*/ + unimplemented!() +} - fn advance_token(&mut self) -> Result { - let tok = self.lexer.read_token()?; +//#[recursive_parser] +fn parse_binary<'b>(s: Span<'b>) -> IResult, (Expr, OperatorPrecedence)> { + let parse_operator = alt(( + map(tag("||"), |t| (t, OperatorPrecedence::Or)), + map(tag("&&"), |t| (t, OperatorPrecedence::And)), + map(tag("="), |t| (t, OperatorPrecedence::Assign)), + map( + alt(( + tag("=="), + tag("!="), + tag("<"), + tag("<="), + tag(">"), + tag(">="), + )), + |t| (t, OperatorPrecedence::Cmp), + ), + map(alt((tag("|"), tag("&"), tag("^"))), |t| { + (t, OperatorPrecedence::Bit) + }), + map(alt((tag("<<"), tag(">>"), tag("+"), tag("-"))), |t| { + (t, OperatorPrecedence::AddShift) + }), + map(alt((tag("*"), tag("/"), tag("%"))), |t| { + (t, OperatorPrecedence::Mul) + }), + )); + let subexpr = alt(( + map(parse_unary, |expr| (expr, OperatorPrecedence::None)), + parse_binary, + )); + let (s, (left, left_precedence)) = subexpr(s)?; + let (s, (op, precedence)) = parse_operator(s)?; + let (s, (right, right_precedence)) = subexpr(s)?; + Ok(( + s, + ( + exp!(ExprKind::BinOp( + Box::new(left), + op.fragment.to_string(), + Box::new(right) + )), + precedence, + ), + )) +} - Ok(mem::replace(&mut self.token, tok)) - } +pub fn parse_unary<'b>(i: Span<'b>) -> EResult<'b> { + map(pair(one_of("+-!"), parse_primary), |(op, expr)| { + exp!(ExprKind::Unop(op.to_string(), Box::new(expr))) + })(i) +} - fn parse_lambda(&mut self) -> EResult { - let tok = self.advance_token()?; - let params = if tok.kind == TokenKind::Or { - vec![] - } else { - self.parse_comma_list(TokenKind::BitOr, |f| f.parse_function_param())? - }; +/*pub fn parse_expression(&mut self) -> EResult { + self.parse_binary(0) +}*/ + +fn parse_call<'b>( + expr_parser: impl Fn(Span<'b>) -> EResult<'b>, +) -> impl Fn(Span<'b>) -> EResult<'b> { + let fn_arg_sep = tag(","); + let fn_arg = parse_expression; + let tup = tuple(( + expr_parser, + tag("("), + separated_list(fn_arg_sep, map(fn_arg, Box::new)), + tag(")"), + )); + map(tup, |(expr, _, params, _)| { + exp!(ExprKind::Call(Box::new(expr), params)) + }) +} - let block = self.parse_expression()?; - Ok(expr!(ExprKind::Lambda(params, block), tok.position)) - } - pub fn parse_factor(&mut self) -> EResult { - let expr = match self.token.kind { - TokenKind::Fun => self.parse_function(), - TokenKind::LParen => self.parse_parentheses(), - TokenKind::LitChar(_) => self.lit_char(), - TokenKind::LitInt(_, _, _) => self.lit_int(), - TokenKind::LitFloat(_) => self.lit_float(), - TokenKind::String(_) => self.lit_str(), - TokenKind::Identifier(_) => self.ident(), - TokenKind::This => self.parse_self(), - TokenKind::BitOr | TokenKind::Or => self.parse_lambda(), - TokenKind::True => self.parse_bool_literal(), - TokenKind::False => self.parse_bool_literal(), - TokenKind::Nil => self.parse_nil(), - _ => Err(MsgWithPos::new( - self.token.position, - Msg::ExpectedFactor(self.token.name().clone()), +fn parse_primary<'b>(s: Span<'b>) -> EResult<'b> { + alt(( + map( + tuple((parse_factor, preceded(tag("."), ident))), + |(left, ident)| exp!(ExprKind::Access(Box::new(left), ident)), + ), + map( + tuple(( + parse_factor, + preceded(tag("["), terminated(parse_expression, tag("]"))), )), - }; + |(left, index)| exp!(ExprKind::ArrayIndex(Box::new(left), Box::new(index))), + ), + parse_call(parse_factor), + parse_factor, + ))(s) +} - expr - } - fn parse_parentheses(&mut self) -> EResult { - self.advance_token()?; - let expr = self.parse_expression(); - self.expect_token(TokenKind::RParen)?; - expr - } +fn advance_token(/*&mut self*/) -> Result { + /*let tok = self.lexer.read_token()?; - fn parse_nil(&mut self) -> EResult { - let tok = self.advance_token()?; - let pos = tok.position; - if let TokenKind::Nil = tok.kind { - Ok(expr!(ExprKind::Nil, pos)) - } else { - unreachable!() - } - } + Ok(mem::replace(&mut self.token, tok))*/ + unimplemented!() +} - fn parse_bool_literal(&mut self) -> EResult { - let tok = self.advance_token()?; - let value = tok.is(TokenKind::True); - Ok(expr!(ExprKind::ConstBool(value), tok.position)) - } +fn parse_lambda<'b>(i: Span) -> EResult { + let fn_arg_sep = tag(","); + let fn_arg = map(expect_identifier, Ident); + let tup = tuple(( + tag("|"), + separated_list(fn_arg_sep, fn_arg), + tag("|"), + parse_expression, + )); + map(tup, |(_, params, _, block)| { + exp!(ExprKind::Lambda(params, Box::new(block))) + })(i) +} - fn lit_int(&mut self) -> EResult { - let tok = self.advance_token()?; - let pos = tok.position; - if let TokenKind::LitInt(i, _, _) = tok.kind { - Ok(expr!(ExprKind::ConstInt(i.parse().unwrap()), pos)) - } else { - unreachable!() - } - } +pub fn parse_factor<'b>(i: Span) -> EResult { + alt(( + preceded(tag("function"), parse_function), + parse_parentheses, + lit_char, + lit_int, + lit_float, + lit_str, + parse_self, + map(ident, |ident| exp!(ExprKind::Ident(ident))), + parse_lambda, + parse_bool_literal, + parse_bool_literal, + parse_nil, + ))(i) +} - fn lit_char(&mut self) -> EResult { - let tok = self.advance_token()?; - let pos = tok.position; - if let TokenKind::LitChar(c) = tok.kind { - Ok(expr!(ExprKind::ConstChar(c), pos)) - } else { - unreachable!() - } - } - fn lit_float(&mut self) -> EResult { - let tok = self.advance_token()?; - let pos = tok.position; - if let TokenKind::LitFloat(c) = tok.kind { - Ok(expr!(ExprKind::ConstFloat(c.parse().unwrap()), pos)) - } else { - unreachable!() - } - } - fn lit_str(&mut self) -> EResult { - let tok = self.advance_token()?; - let pos = tok.position; - if let TokenKind::String(s) = tok.kind { - Ok(expr!(ExprKind::ConstStr(s), pos)) - } else { - unreachable!() +fn parse_parentheses<'b>(i: Span) -> EResult { + preceded(tag("("), terminated(parse_expression, tag(")")))(i) +} + +fn ident<'b>(i: Span) -> IResult, Ident> { + /*let pos = self.token.position; + let ident = self.expect_identifier()?; + + Ok(expr!(ExprKind::Ident(ident), pos))*/ + unimplemented!() +} + +impl<'a> Parser<'a> { + pub fn new(reader: Reader, ast: &'a mut Vec>) -> Parser<'a> { + Self { + lexer: Lexer::new(reader), + token: Token::new(TokenKind::End, Position::new(1, 1)), + ast, } } - fn ident(&mut self) -> EResult { - let pos = self.token.position; - let ident = self.expect_identifier()?; + fn init(&mut self) -> Result<(), MsgWithPos> { + //self.advance_token()?; - Ok(expr!(ExprKind::Ident(ident), pos)) + Ok(()) } } diff --git a/src/token.rs b/src/token.rs index ac84ed4..d716141 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1,7 +1,7 @@ use std::fmt; use std::result::Result; -#[derive(Clone, Debug, PartialEq, Eq, Copy)] +#[derive(Clone, Debug, PartialEq, Eq, Copy, Default)] pub struct Position { pub line: u32, pub column: u32,