diff --git a/Cargo.lock b/Cargo.lock index 9028fe2..bca5a85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,25 +83,13 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block-buffer" -version = "0.7.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "block-padding", - "byte-tools", - "byteorder", "generic-array", ] -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - [[package]] name = "bstr" version = "0.2.17" @@ -117,12 +105,6 @@ version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "bytemuck" version = "1.9.1" @@ -196,7 +178,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.92", ] [[package]] @@ -337,6 +319,25 @@ dependencies = [ "objc", ] +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "cty" version = "0.2.2" @@ -375,7 +376,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.92", ] [[package]] @@ -386,16 +387,17 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.92", ] [[package]] name = "digest" -version = "0.8.1" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "generic-array", + "block-buffer", + "crypto-common", ] [[package]] @@ -419,12 +421,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fnv" version = "1.0.7" @@ -450,6 +446,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" name = "forge_core" version = "0.1.0" dependencies = [ + "lazy_static", "pest", "pest_derive", "vcore", @@ -466,11 +463,12 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.12.4" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", + "version_check", ] [[package]] @@ -700,12 +698,6 @@ dependencies = [ "libc", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "memchr" version = "2.5.0" @@ -798,7 +790,7 @@ checksum = "dd3dfb62b95873e3d7aa9a691905287992628e3c10cadce5ed88f15134e3b0ce" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.92", ] [[package]] @@ -863,7 +855,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.92", ] [[package]] @@ -931,7 +923,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.92", ] [[package]] @@ -959,12 +951,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "os_str_bytes" version = "6.4.1" @@ -1004,18 +990,19 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pest" -version = "2.1.3" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" dependencies = [ + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" dependencies = [ "pest", "pest_generator", @@ -1023,26 +1010,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.3" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.27", ] [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" dependencies = [ - "maplit", + "once_cell", "pest", - "sha-1", + "sha2", ] [[package]] @@ -1096,7 +1083,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.92", "version_check", ] @@ -1113,11 +1100,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1128,9 +1115,9 @@ checksum = "9145ac0af1d93c638c98c40cf7d25665f427b2a44ad0a99b1dccf3e2f25bb987" [[package]] name = "quote" -version = "1.0.18" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -1273,7 +1260,7 @@ checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.92", ] [[package]] @@ -1288,15 +1275,14 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.8.2" +name = "sha2" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ - "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", "digest", - "fake-simd", - "opaque-debug", ] [[package]] @@ -1360,6 +1346,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn" +version = "2.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -1377,22 +1374,22 @@ checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.27", ] [[package]] @@ -1412,9 +1409,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "ucd-trie" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "ultraviolet" @@ -1425,6 +1422,12 @@ dependencies = [ "wide", ] +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + [[package]] name = "unicode-width" version = "0.1.9" @@ -1551,7 +1554,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.92", "wasm-bindgen-shared", ] @@ -1585,7 +1588,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.92", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index d1065e9..c88db86 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -12,14 +12,14 @@ pub enum Declaration { #[derive(PartialEq, Clone, Debug, Default)] pub struct Varinfo { pub typename: Option, - pub size: Option, + pub size: Option, } #[derive(PartialEq, Clone, Debug)] pub struct Global { pub name: String, pub typename: Option, - pub size: Option, + pub size: Option, } #[derive(PartialEq, Clone, Debug)] @@ -32,13 +32,13 @@ pub struct Struct { pub struct Member { pub name: String, pub typename: Option, - pub size: Option, + pub size: Option, } #[derive(PartialEq, Clone, Debug)] pub struct Const { pub name: String, - pub value: Option, + pub value: Option, pub string: Option, } @@ -48,9 +48,6 @@ pub struct Block(pub Vec); #[derive(PartialEq, Clone, Debug)] pub struct Function { pub name: String, - pub org: Option, - pub typename: Option, - pub inline: bool, pub args: Vec, pub body: Block, } @@ -65,7 +62,7 @@ pub struct Argname { pub enum Statement { Return(Return), Assignment(Assignment), - Call(Call), + Expr(Expr), VarDecl(VarDecl), Conditional(Conditional), WhileLoop(WhileLoop), @@ -73,7 +70,7 @@ pub enum Statement { } #[derive(PartialEq, Clone, Debug)] -pub struct Return(pub Option); +pub struct Return(pub Option); #[derive(PartialEq, Clone, Debug)] pub struct Assignment { @@ -81,12 +78,6 @@ pub struct Assignment { pub rvalue: Rvalue, } -#[derive(PartialEq, Clone, Debug)] -pub struct Call { - pub name: String, - pub args: Vec, -} - #[derive(PartialEq, Clone, Debug)] pub enum Lvalue { ArrayRef(ArrayRef), @@ -95,7 +86,7 @@ pub enum Lvalue { #[derive(PartialEq, Clone, Debug)] pub enum Rvalue { - Expr(Node), + Expr(Expr), String(String), } @@ -103,26 +94,26 @@ pub enum Rvalue { pub struct VarDecl { pub name: String, pub typename: Option, - pub size: Option, - pub initial: Option, + pub size: Option, + pub initial: Option, } #[derive(PartialEq, Clone, Debug)] pub struct Conditional { - pub condition: Node, + pub condition: Expr, pub body: Block, pub alternative: Option, } #[derive(PartialEq, Clone, Debug)] pub struct WhileLoop { - pub condition: Node, + pub condition: Expr, pub body: Block, } #[derive(PartialEq, Clone, Debug)] pub struct RepeatLoop { - pub count: Node, + pub count: Expr, pub name: Option, pub body: Block, } @@ -154,55 +145,114 @@ pub enum Operator { pub enum Prefix { Neg, Not, + Address +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Suffix { + Subscript(Expr), + Arglist(Vec), + Member(String), } #[derive(PartialEq, Clone, Debug)] -pub enum Node { - Number(i32), - Call(Call), - ArrayRef(ArrayRef), - Name(String), - Address(String), - Expr(BoxNode, Operator, BoxNode), - Prefix(Prefix, BoxNode), +pub struct Expr { + pub lhs: Val, + pub op: Option, + pub rhs: Option, } -impl From for Node { - fn from(val: i32) -> Self { - Self::Number(val) +#[derive(PartialEq, Clone, Debug)] +pub enum Val { + Number(i32, Vec, Vec), + Name(String, Vec, Vec), + Expr(BoxExpr, Vec, Vec), +} + +impl Val { + pub fn is_simple(&self) -> bool { + if let Self::Expr(expr, pre, suf) = &self { + pre.is_empty() && suf.is_empty() && expr.0.op.is_none() + } else { + false + } + } + + pub fn inner_expr(self) -> Option { + if let Self::Expr(expr, _, _) = self { + Some(expr.into()) + } else { None } } } -impl From<&str> for Node { +impl From for Val { + fn from(val: i32) -> Self { + Self::Number(val, vec![], vec![]) + } +} + +impl From<&str> for Val { fn from(s: &str) -> Self { - Self::Name(String::from(s)) + Self::Name(String::from(s), vec![], vec![]) + } +} + +impl From for Val { + fn from(value: Expr) -> Self { + Self::Expr(value.into(), vec![], vec![]) + } +} + +impl From for Val { + fn from(value: BoxExpr) -> Self { + Self::Expr(value, vec![], vec![]) } } #[repr(transparent)] #[derive(PartialEq, Clone, Debug)] -pub struct BoxNode(pub Box); +pub struct BoxExpr(pub Box); -impl From for BoxNode { +impl From for Expr { + fn from(value: Val) -> Self { + Self { + lhs: value, + op: None, + rhs: None + } + } +} + +impl From for BoxExpr { fn from(val: i32) -> Self { - BoxNode(Box::from(Node::Number(val))) + BoxExpr(Box::from(Expr::from(Val::from(val)))) } } -impl From for BoxNode { - fn from(val: Node) -> Self { - BoxNode(Box::from(val)) +impl From for BoxExpr { + fn from(val: Expr) -> Self { + BoxExpr(Box::from(val)) } } -impl From for Node { - fn from(val: BoxNode) -> Self { +impl From for Expr { + fn from(val: BoxExpr) -> Self { *(val.0) } } +impl From for Expr { + fn from(value: i32) -> Self { + Self { + lhs: Val::Number(value, vec![], vec![]), + op: None, + rhs: None + } + } +} + #[derive(PartialEq, Clone, Debug)] pub struct ArrayRef { pub name: String, - pub subscript: BoxNode, + pub subscript: BoxExpr, } diff --git a/forge_core/src/compiler.rs b/forge_core/src/compiler.rs index 294ddca..506db5f 100644 --- a/forge_core/src/compiler.rs +++ b/forge_core/src/compiler.rs @@ -193,13 +193,6 @@ impl Compilable for Declaration { impl Compilable for Function { fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> { - if self.typename.is_some() { - todo!("Structs are not yet supported") - } - if self.org.is_some() || self.inline { - todo!("Attributes are not yet supported") - } - // The signature for this function, which will eventually get added to the state let mut sig = Signature { label: state.gensym(), @@ -227,12 +220,13 @@ impl Compilable for Function { match stmt { Statement::Return(_) => {} Statement::Assignment(assign) => assign.process(state, Some(&mut sig))?, - Statement::Call(call) => { - call.process(state, Some(&mut sig))?; - // Every call leaves a single-word return value on the stack. In an rvalue this - // is useful but in a statement it's garbage (because nothing else is about to - // pick it up) so, drop it: - sig.emit("pop") + Statement::Expr(expr) => { + todo!(); + // expr.process(state, Some(&mut sig))?; + // // Every expr leaves a single-word return value on the stack. In an rvalue this + // // is useful but in a statement it's garbage (because nothing else is about to + // // pick it up) so, drop it: + // sig.emit("pop") } Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?, Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => { @@ -268,13 +262,13 @@ impl Compilable for Assignment { // For a normal expr, eval and leave on the stack; for a string literal, add it to // the str table and push the label's address - match rvalue { - Rvalue::Expr(rvalue) => rvalue.process(state, Some(sig))?, - Rvalue::String(string) => { - let label = state.add_string(&string); - sig.emit_arg("push", label); - } - } + // match rvalue { + // Rvalue::Expr(rvalue) => rvalue.process(state, Some(sig))?, + // Rvalue::String(string) => { + // let label = state.add_string(&string); + // sig.emit_arg("push", label); + // } + // } // Then process the lvalue and storew lvalue.process(state, Some(sig))?; @@ -285,36 +279,27 @@ impl Compilable for Assignment { /////////////////////////////////////////////////////////// -impl Compilable for Call { - fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { - // todo arity check - - todo!() - } -} - -/////////////////////////////////////////////////////////// - impl Compilable for VarDecl { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { - let mut sig = sig.expect("Var declaration outside function"); - if self.typename.is_some() || self.size.is_some() { - todo!("Structs and arrays are not yet supported") - } - if let Some(initial) = self.initial { - // If it's got an initial value, we have to compile that before we add - // the name to scope, or else UB will ensue if it refers to itself: - initial.process(state, Some(sig))?; - // But then add it to scope and assign: - sig.add_local(&self.name)?; - // We'll just whip up an lvalue real quick... - Lvalue::Name(self.name).process(state, Some(sig))?; - sig.emit("storew"); // And store the initial value there - } else { - // Otherwise, just add it to scope and leave garbage in there: - sig.add_local(&self.name)?; - } - Ok(()) + todo!(); + // let mut sig = sig.expect("Var declaration outside function"); + // if self.typename.is_some() || self.size.is_some() { + // todo!("Structs and arrays are not yet supported") + // } + // if let Some(initial) = self.initial { + // // If it's got an initial value, we have to compile that before we add + // // the name to scope, or else UB will ensue if it refers to itself: + // initial.process(state, Some(sig))?; + // // But then add it to scope and assign: + // sig.add_local(&self.name)?; + // // We'll just whip up an lvalue real quick... + // Lvalue::Name(self.name).process(state, Some(sig))?; + // sig.emit("storew"); // And store the initial value there + // } else { + // // Otherwise, just add it to scope and leave garbage in there: + // sig.add_local(&self.name)?; + // } + // Ok(()) } } @@ -363,119 +348,120 @@ impl Compilable for Lvalue { /// Evaluate an expression in the context of a local scope. The runtime brother to eval_const. /// This recursively evaluates a Node and leaves its value on the stack. -impl Compilable for Node { +impl Compilable for Expr { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { - let mut sig = sig.expect("Non-const expression outside a function"); - let global_scope = &state.global_scope; - - // First, a sanity check: try and eval_const this. If it's something incredibly basic - // that just becomes an i32, then we don't need to do anything else: - if let Ok(val) = eval_const(self.clone(), &state.global_scope) { - sig.emit_arg("push", val); - return Ok(()); - } - - // Okay, looks like we need something that's in scope. Let's recurse: - match self { - Node::Number(n) => { - // Numbers are just pushed as literals - sig.body.push(format!("push {}", n)); - Ok(()) - } - Node::Call(_) | Node::ArrayRef(_) | Node::Address(_) => todo!(), - Node::Name(name) => match lookup(&name, global_scope, &sig.local_scope) { - // Names are treated differently depending on what they are - Some(Variable::Literal(val)) => { - // Names of constants are just that number - sig.emit_arg("push", *val); - Ok(()) - } - Some(Variable::IndirectLabel(label)) => { - // Names pointing at labels are loaded (rvalue; for lvalues they aren't) - // Indirect labels are the address of where the value is stored (a var, .db) - sig.emit_arg("loadw", label.clone()); - Ok(()) - } - Some(Variable::DirectLabel(label)) => { - // Direct labels are like functions, the label itself is the value, so just - // push it: - sig.emit_arg("push", label.clone()); - Ok(()) - } - Some(Variable::Local(offset)) => { - // Names of locals are added from the frame pointer - let offset = *offset; - sig.emit("loadw frame"); - if offset > 0 { - sig.emit_arg("add", offset); - sig.emit("loadw"); - } - Ok(()) - } - None => Err(CompileError(0, 0, format!("Unknown name {}", name))), - }, - Node::Expr(lhs, op, rhs) => { - // Recurse on expressions, handling operators - lhs.0.process(state, Some(&mut sig))?; - rhs.0.process(state, Some(&mut sig))?; - match op { - // Basic math - Operator::Add => sig.emit("add"), - Operator::Sub => sig.emit("sub"), - Operator::Mul => sig.emit("mul"), - Operator::Div => sig.emit("div"), - Operator::Mod => sig.emit("mod"), - Operator::And => { - // Vulcan "and" is bitwise, so we need to flag-ify both args to make it logical - sig.emit("gt 0"); - sig.emit("swap"); - sig.emit("gt 0"); - sig.emit("and"); - } - Operator::Or => { - // Same as and, flag-ify both args - sig.emit("gt 0"); - sig.emit("swap"); - sig.emit("gt 0"); - sig.emit("or"); - } - Operator::BitAnd => sig.emit("and"), - Operator::BitOr => sig.emit("or"), - Operator::Xor => sig.emit("xor"), - Operator::Lt => sig.emit("alt"), - Operator::Le => { - // LE and GE are the inverses of GT and LT (arithmetic versions) - sig.emit("agt"); - sig.emit("not"); - } - Operator::Gt => sig.emit("agt"), - Operator::Ge => { - sig.emit("alt"); - sig.emit("not"); - } - Operator::Eq => { - sig.emit("xor"); - sig.emit("not"); - } - Operator::Ne => sig.emit("xor"), - Operator::Lshift => sig.emit("lshift"), - Operator::Rshift => sig.emit("arshift"), - } - Ok(()) - } - Node::Prefix(prefix, node) => { - node.0.process(state, Some(sig))?; - match prefix { - Prefix::Neg => { - // To arithmetically negate something, invert and increment (2s complement) - sig.emit("xor -1"); - sig.emit("add 1"); - } - Prefix::Not => sig.emit("not"), - } - Ok(()) - } - } + todo!(); + // let mut sig = sig.expect("Non-const expression outside a function"); + // let global_scope = &state.global_scope; + // + // // First, a sanity check: try and eval_const this. If it's something incredibly basic + // // that just becomes an i32, then we don't need to do anything else: + // if let Ok(val) = eval_const(self.clone(), &state.global_scope) { + // sig.emit_arg("push", val); + // return Ok(()); + // } + // + // // Okay, looks like we need something that's in scope. Let's recurse: + // match self.val { + // Val::Number(n) => { + // // Numbers are just pushed as literals + // sig.body.push(format!("push {}", n)); + // Ok(()) + // } + // Val::Name(name) => match lookup(&name, global_scope, &sig.local_scope) { + // // Names are treated differently depending on what they are + // Some(Variable::Literal(val)) => { + // // Names of constants are just that number + // sig.emit_arg("push", *val); + // Ok(()) + // } + // Some(Variable::IndirectLabel(label)) => { + // // Names pointing at labels are loaded (rvalue; for lvalues they aren't) + // // Indirect labels are the address of where the value is stored (a var, .db) + // sig.emit_arg("loadw", label.clone()); + // Ok(()) + // } + // Some(Variable::DirectLabel(label)) => { + // // Direct labels are like functions, the label itself is the value, so just + // // push it: + // sig.emit_arg("push", label.clone()); + // Ok(()) + // } + // Some(Variable::Local(offset)) => { + // // Names of locals are added from the frame pointer + // let offset = *offset; + // sig.emit("loadw frame"); + // if offset > 0 { + // sig.emit_arg("add", offset); + // sig.emit("loadw"); + // } + // Ok(()) + // } + // None => Err(CompileError(0, 0, format!("Unknown name {}", name))), + // }, + // Val::Expr(node) => { + // todo!(); + // // // Recurse on expressions, handling operators + // // lhs.0.process(state, Some(&mut sig))?; + // // rhs.0.process(state, Some(&mut sig))?; + // // match op { + // // // Basic math + // // Operator::Add => sig.emit("add"), + // // Operator::Sub => sig.emit("sub"), + // // Operator::Mul => sig.emit("mul"), + // // Operator::Div => sig.emit("div"), + // // Operator::Mod => sig.emit("mod"), + // // Operator::And => { + // // // Vulcan "and" is bitwise, so we need to flag-ify both args to make it logical + // // sig.emit("gt 0"); + // // sig.emit("swap"); + // // sig.emit("gt 0"); + // // sig.emit("and"); + // // } + // // Operator::Or => { + // // // Same as and, flag-ify both args + // // sig.emit("gt 0"); + // // sig.emit("swap"); + // // sig.emit("gt 0"); + // // sig.emit("or"); + // // } + // // Operator::BitAnd => sig.emit("and"), + // // Operator::BitOr => sig.emit("or"), + // // Operator::Xor => sig.emit("xor"), + // // Operator::Lt => sig.emit("alt"), + // // Operator::Le => { + // // // LE and GE are the inverses of GT and LT (arithmetic versions) + // // sig.emit("agt"); + // // sig.emit("not"); + // // } + // // Operator::Gt => sig.emit("agt"), + // // Operator::Ge => { + // // sig.emit("alt"); + // // sig.emit("not"); + // // } + // // Operator::Eq => { + // // sig.emit("xor"); + // // sig.emit("not"); + // // } + // // Operator::Ne => sig.emit("xor"), + // // Operator::Lshift => sig.emit("lshift"), + // // Operator::Rshift => sig.emit("arshift"), + // // } + // // Ok(()) + // } + // // Node::Prefix(prefix, node) => { + // // node.0.process(state, Some(sig))?; + // // match prefix { + // // Prefix::Neg => { + // // // To arithmetically negate something, invert and increment (2s complement) + // // sig.emit("xor -1"); + // // sig.emit("add 1"); + // // } + // // Prefix::Not => sig.emit("not"), + // // } + // // Ok(()) + // // } + // } } } @@ -494,17 +480,18 @@ impl Compilable for Global { impl Compilable for Const { fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> { - let var = if self.string.is_some() { - // If it's a string, add it to the string table - Variable::DirectLabel(state.add_string(&self.string.unwrap())) - } else if let Some(expr) = self.value { - // Otherwise eval_const it - Variable::Literal(eval_const(expr, &state.global_scope)?) - } else { - unreachable!() - }; - // Add it to the global namespace - state.add_global(&self.name, |_| var.clone()) + todo!() + // let var = if self.string.is_some() { + // // If it's a string, add it to the string table + // Variable::DirectLabel(state.add_string(&self.string.unwrap())) + // } else if let Some(expr) = self.value { + // // Otherwise eval_const it + // Variable::Literal(eval_const(expr, &state.global_scope)?) + // } else { + // unreachable!() + // }; + // // Add it to the global namespace + // state.add_global(&self.name, |_| var.clone()) } } @@ -519,61 +506,63 @@ fn to_flag(val: bool) -> i32 { } /// Evaluate a node in a static context, for const definitions and array sizes, that sort of thing. -pub fn eval_const(expr: Node, scope: &Scope) -> Result { - match expr { - Node::Number(n) => Ok(n), - Node::Address(_) | Node::ArrayRef(_) | Node::Call(_) => Err(CompileError( - 0, - 0, - String::from("Constants must be statically defined"), - )), - - Node::Name(n) => { - if let Some(Variable::Literal(val)) = scope.get(&n) { - Ok(*val) - } else { - Err(CompileError(0, 0, format!("Unknown const {}", n))) - } - } - - Node::Expr(lhs, op, rhs) => { - let lhs = eval_const(lhs.into(), scope)?; - let rhs = eval_const(rhs.into(), scope)?; - match op { - Operator::Add => Ok(lhs + rhs), - Operator::Sub => Ok(lhs - rhs), - Operator::Mul => Ok(lhs * rhs), - Operator::Div => Ok(lhs / rhs), - Operator::Mod => Ok(lhs % rhs), - Operator::And => Ok(to_flag(lhs != 0 && rhs != 0)), - Operator::Or => Ok(to_flag(lhs != 0 || rhs != 0)), - Operator::BitAnd => Ok(lhs & rhs), - Operator::BitOr => Ok(lhs | rhs), - Operator::Xor => Ok(lhs ^ rhs), - Operator::Lt => Ok(to_flag(lhs < rhs)), - Operator::Le => Ok(to_flag(lhs <= rhs)), - Operator::Gt => Ok(to_flag(lhs > rhs)), - Operator::Ge => Ok(to_flag(lhs >= rhs)), - Operator::Eq => Ok(to_flag(lhs == rhs)), - Operator::Ne => Ok(to_flag(lhs != rhs)), - Operator::Lshift => Ok(lhs << rhs), - Operator::Rshift => Ok(lhs >> rhs), - } - } - Node::Prefix(p, child) => { - let val = eval_const(child.into(), scope)?; - match p { - Prefix::Neg => Ok(-val), - Prefix::Not => { - if val == 0 { - Ok(1) - } else { - Ok(0) - } - } - } - } - } +pub fn eval_const(expr: Expr, scope: &Scope) -> Result { + todo!() + // match expr.lhs { + // Val::Number(n) => Ok(n), + // // Node::Address(_) | Node::ArrayRef(_) | Node::Call(_) => Err(CompileError( + // // 0, + // // 0, + // // String::from("Constants must be statically defined"), + // // )), + // + // Val::Name(n) => { + // if let Some(Variable::Literal(val)) = scope.get(&n) { + // Ok(*val) + // } else { + // Err(CompileError(0, 0, format!("Unknown const {}", n))) + // } + // } + // + // Val::Expr(node) => { + // todo!() + // // let lhs = eval_const(lhs.into(), scope)?; + // // let rhs = eval_const(rhs.into(), scope)?; + // // match op { + // // Operator::Add => Ok(lhs + rhs), + // // Operator::Sub => Ok(lhs - rhs), + // // Operator::Mul => Ok(lhs * rhs), + // // Operator::Div => Ok(lhs / rhs), + // // Operator::Mod => Ok(lhs % rhs), + // // Operator::And => Ok(to_flag(lhs != 0 && rhs != 0)), + // // Operator::Or => Ok(to_flag(lhs != 0 || rhs != 0)), + // // Operator::BitAnd => Ok(lhs & rhs), + // // Operator::BitOr => Ok(lhs | rhs), + // // Operator::Xor => Ok(lhs ^ rhs), + // // Operator::Lt => Ok(to_flag(lhs < rhs)), + // // Operator::Le => Ok(to_flag(lhs <= rhs)), + // // Operator::Gt => Ok(to_flag(lhs > rhs)), + // // Operator::Ge => Ok(to_flag(lhs >= rhs)), + // // Operator::Eq => Ok(to_flag(lhs == rhs)), + // // Operator::Ne => Ok(to_flag(lhs != rhs)), + // // Operator::Lshift => Ok(lhs << rhs), + // // Operator::Rshift => Ok(lhs >> rhs), + // // } + // } + // // Node::Prefix(p, child) => { + // // let val = eval_const(child.into(), scope)?; + // // match p { + // // Prefix::Neg => Ok(-val), + // // Prefix::Not => { + // // if val == 0 { + // // Ok(1) + // // } else { + // // Ok(0) + // // } + // // } + // // } + // // } + // } } #[cfg(test)] @@ -584,12 +573,12 @@ mod test { #[test] fn test_eval_const() { let empty_scope = Scope::new(); - let to_node = |s| Node::parse(s).unwrap(); + let to_expr = |s| Expr::parse(s).unwrap(); // Basic arithmetic - assert_eq!(eval_const(to_node("2 * 3 + 4"), &empty_scope), Ok(10)); - assert_eq!(eval_const(to_node("1 + -2"), &empty_scope), Ok(-1)); - assert_eq!(eval_const(to_node("1 << 3"), &empty_scope), Ok(8)); + assert_eq!(eval_const(to_expr("2 * 3 + 4"), &empty_scope), Ok(10)); + assert_eq!(eval_const(to_expr("1 + -2"), &empty_scope), Ok(-1)); + assert_eq!(eval_const(to_expr("1 << 3"), &empty_scope), Ok(8)); // Names let scope: Scope = [ @@ -597,12 +586,12 @@ mod test { ("bar".into(), Variable::Literal(5)), ] .into(); - assert_eq!(eval_const(to_node("foo + 5"), &scope), Ok(15)); - assert_eq!(eval_const(to_node("bar * foo"), &scope), Ok(50)); + assert_eq!(eval_const(to_expr("foo + 5"), &scope), Ok(15)); + assert_eq!(eval_const(to_expr("bar * foo"), &scope), Ok(50)); // Error assert_eq!( - eval_const(to_node("nope"), &scope), + eval_const(to_expr("nope"), &scope), Err(CompileError(0, 0, String::from("Unknown const nope"))) ); } diff --git a/forge_core/src/forge_parser.rs b/forge_core/src/forge_parser.rs index 6a74d80..2f44df1 100644 --- a/forge_core/src/forge_parser.rs +++ b/forge_core/src/forge_parser.rs @@ -2,7 +2,7 @@ use pest::pratt_parser::PrattParser; use pest::Parser; #[derive(Parser)] -#[grammar = "forge.pest"] +#[grammar = "new.pest"] struct ForgeParser; lazy_static::lazy_static! { @@ -30,6 +30,7 @@ use crate::ast::*; use pest::error::{Error, LineColLocation}; use std::iter::Peekable; use std::str::FromStr; +use crate::ast::Suffix::{Arglist, Subscript}; pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>; pub(crate) type Pairs<'i, R = Rule> = pest::iterators::Pairs<'i, R>; @@ -179,7 +180,7 @@ impl AstNode for Varinfo { .map(|t| String::from(t.first().as_str())); let size = children .next_if_rule(Rule::size) - .map(|s| Node::from_pair(s.first())); + .map(|s| Expr::from_pair(s.first())); Self { typename, size } } } @@ -246,7 +247,7 @@ impl AstNode for Const { Rule::expr => Const { name, string: None, - value: Some(Node::from_pair(value)), + value: Some(Expr::from_pair(value)), }, _ => unreachable!(), } @@ -260,20 +261,6 @@ impl AstNode for Function { fn from_pair(pair: Pair<'_>) -> Self { let mut inner = pair.into_inner().peekable(); let name = String::from(inner.next().unwrap().as_str()); - let mut inline = false; - let mut org = None; - let mut typename = None; - if let Some(annotations) = inner.next_if_rule(Rule::annotations) { - for annotation in annotations.into_inner() { - let annotation = annotation.first(); - match annotation.as_rule() { - Rule::inline_annotation => inline = true, - Rule::org_annotation => org = Some(annotation.first().into_number()), - Rule::type_annotation => typename = Some(annotation.first_as_string()), - _ => unreachable!(), - } - } - } let args: Vec<_> = inner .next() .unwrap() @@ -285,9 +272,6 @@ impl AstNode for Function { Self { name, - org, - typename, - inline, args, body, } @@ -313,7 +297,7 @@ impl AstNode for Statement { match pair.as_rule() { Rule::return_stmt => Self::Return(Return::from_pair(pair)), Rule::assignment => Self::Assignment(Assignment::from_pair(pair)), - Rule::call => Self::Call(Call::from_pair(pair)), + Rule::expr => Self::Expr(Expr::from_pair(pair)), Rule::var_decl => Self::VarDecl(VarDecl::from_pair(pair)), Rule::conditional => Self::Conditional(Conditional::from_pair(pair)), Rule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)), @@ -330,7 +314,7 @@ impl AstNode for Return { fn from_pair(pair: Pair) -> Self { pair.into_inner() .next() - .map_or(Self(None), |expr| Self(Some(Node::from_pair(expr)))) + .map_or(Self(None), |expr| Self(Some(Expr::from_pair(expr)))) } } @@ -342,7 +326,7 @@ impl AstNode for Assignment { let mut pairs = pair.into_inner(); let lvalue_pair = pairs.next().unwrap().first(); let lvalue = match lvalue_pair.as_rule() { - Rule::arrayref => Lvalue::ArrayRef(ArrayRef::from_pair(lvalue_pair)), + //Rule::arrayref => Lvalue::ArrayRef(ArrayRef::from_pair(lvalue_pair)), Rule::name => Lvalue::Name(String::from(lvalue_pair.as_str())), _ => unreachable!(), }; @@ -360,7 +344,7 @@ impl AstNode for Rvalue { let pair = pair.first(); match pair.as_rule() { Rule::string => Self::String(pair.into_quoted_string()), - Rule::expr => Self::Expr(Node::from_pair(pair)), + Rule::expr => Self::Expr(Expr::from_pair(pair)), _ => unreachable!(), } } @@ -368,26 +352,13 @@ impl AstNode for Rvalue { /////////////////////////////////////////////////////////////////////////////////////////// -impl AstNode for Call { - const RULE: Rule = Rule::call; - fn from_pair(pair: Pair) -> Self { - let mut inner = pair.into_inner(); - let name = String::from(inner.next().unwrap().as_str()); - let arg_pairs = inner.next().unwrap().into_inner(); - let args: Vec = arg_pairs.map(Rvalue::from_pair).collect(); - Self { name, args } - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// - impl AstNode for VarDecl { const RULE: Rule = Rule::var_decl; fn from_pair(pair: Pair) -> Self { let mut inner = pair.into_inner(); let name = String::from(inner.next().unwrap().as_str()); let Varinfo { typename, size } = Varinfo::from_pair(inner.next().unwrap()); - let initial = inner.next().map(Node::from_pair); + let initial = inner.next().map(Expr::from_pair); Self { name, typename, @@ -413,7 +384,7 @@ impl AstNode for Conditional { const RULE: Rule = Rule::conditional; fn from_pair(pair: Pair) -> Self { let mut inner = pair.into_inner(); - let condition = Node::from_pair(inner.next().unwrap()); + let condition = Expr::from_pair(inner.next().unwrap()); let body = Block::from_pair(inner.next().unwrap()); let alternative = inner.next().map(Block::from_pair); Self { @@ -431,7 +402,7 @@ impl AstNode for WhileLoop { fn from_pair(pair: Pair) -> Self { let mut inner = pair.into_inner(); Self { - condition: Node::from_pair(inner.next().unwrap()), + condition: Expr::from_pair(inner.next().unwrap()), body: Block::from_pair(inner.next().unwrap()), } } @@ -443,7 +414,7 @@ impl AstNode for RepeatLoop { const RULE: Rule = Rule::repeat_loop; fn from_pair(pair: Pair) -> Self { let mut inner = pair.into_inner().peekable(); - let count = Node::from_pair(inner.next().unwrap()); + let count = Expr::from_pair(inner.next().unwrap()); let name = inner .next_if_rule(Rule::name) .map(|p| String::from(p.as_str())); @@ -454,29 +425,28 @@ impl AstNode for RepeatLoop { /////////////////////////////////////////////////////////////////////////////////////////// -impl AstNode for Node { - const RULE: Rule = Rule::expr; // Also used for vals / terms / the whole tree +impl AstNode for Expr { + const RULE: Rule = Rule::expr; fn from_pair(pair: Pair) -> Self { PRATT_PARSER .map_primary(|val| { - let primary = val.first(); - match primary.as_rule() { - Rule::number => Node::Number(primary.into_number()), - Rule::name => Node::Name(String::from(primary.as_str())), - Rule::call => Node::Call(Call::from_pair(primary)), - Rule::arrayref => Node::ArrayRef(ArrayRef::from_pair(primary)), - Rule::address => Node::Address(primary.first_as_string()), - Rule::expr => Node::from_pair(primary), - rule => unreachable!("Expr::parse expected atom, found {:?}", rule), - } + Expr { + lhs: Val::from_pair(val), + op: None, + rhs: None + } }) - .map_prefix(|op, rhs| Node::Prefix(Prefix::from_pair(op), rhs.into())) - .map_infix(|lhs, op, rhs| Node::Expr(lhs.into(), Operator::from_pair(op), rhs.into())) + .map_infix(|lhs, op, rhs| + Expr { + lhs: Val::from(lhs), + op: Some(Operator::from_pair(op)), + rhs: Some(rhs.into()), + }) .parse(pair.into_inner()) } } -impl Node { +impl Expr { pub(crate) fn parse(src: &str) -> Result { Self::from_str(src) } @@ -485,7 +455,8 @@ impl Node { /////////////////////////////////////////////////////////////////////////////////////////// impl AstNode for Operator { - const RULE: Rule = Rule::operator; // also term_op + const RULE: Rule = Rule::operator; + // also term_op fn from_pair(pair: Pair) -> Self { match pair.as_str() { "+" => Self::Add, @@ -518,6 +489,7 @@ impl AstNode for Prefix { match pair.as_str() { "!" => Self::Not, "-" => Self::Neg, + "&" => Self::Address, _ => unreachable!(), } } @@ -525,16 +497,16 @@ impl AstNode for Prefix { /////////////////////////////////////////////////////////////////////////////////////////// -impl AstNode for ArrayRef { - const RULE: Rule = Rule::arrayref; +impl AstNode for Suffix { + const RULE: Rule = Rule::suffix; fn from_pair(pair: Pair) -> Self { - let mut inner = pair.into_inner(); - let name = String::from(inner.next().unwrap().as_str()); - let subscript = Node::from_pair(inner.next().unwrap().first()); - Self { - name, - subscript: subscript.into(), + let first = pair.first(); + match first.as_rule() { + Rule::subscript => Subscript(Expr::from_pair(first.first())), + Rule::member => Self::Member(first.first_as_string()), + Rule::arglist => Arglist(first.into_inner().map(Rvalue::from_pair).collect()), + _ => unreachable!() } } } @@ -557,10 +529,61 @@ impl AstNode for Program { /////////////////////////////////////////////////////////////////////////////////////////// +impl AstNode for Val { + const RULE: Rule = Rule::val; + + fn from_pair(pair: Pair) -> Self { + let mut suffix = vec![]; + let mut prefix = vec![]; + let mut val = None; + for child in pair.into_inner() { + match child.as_rule() { + Rule::prefix => prefix.push(Prefix::from_pair(child)), + Rule::suffix => suffix.push(Suffix::from_pair(child)), + Rule::number | Rule::name | Rule::expr => val = Some(child), + _ => unreachable!() + } + } + + let val = val.unwrap(); + match val.as_rule() { + Rule::number => Self::Number(val.into_number(), prefix, suffix), + Rule::name => Self::Name(String::from(val.as_str()), prefix, suffix), + Rule::expr => Self::Expr(Expr::from_pair(val).into(), prefix, suffix), + _ => unreachable!() + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// + #[cfg(test)] mod test { use super::*; + #[test] + fn parse_vals() { + // Basic vals with no extras: + assert_eq!(Val::from_str("10"), Ok(10.into())); + assert_eq!(Val::from_str("blah"), Ok(Val::Name("blah".into(), vec![], vec![]))); + + // Simple prefix + assert_eq!(Val::from_str("-5"), + Ok(Val::Number(5, vec![Prefix::Neg], vec![]))); + + // Multiple prefixes + assert_eq!(Val::from_str("!&foo"), + Ok(Val::Name("foo".into(), vec![Prefix::Not, Prefix::Address], vec![]))); + + // Simple suffix + assert_eq!(Val::from_str("foo[10]"), + Ok(Val::Name("foo".into(), vec![], vec![Suffix::Subscript(10.into())]))); + + // Multi-suffix + assert_eq!(Val::from_str("foo[10].bar"), + Ok(Val::Name("foo".into(), vec![], vec![Suffix::Subscript(10.into()), Suffix::Member("bar".into())]))); + } + #[test] fn parse_globals() { assert_eq!( @@ -568,7 +591,7 @@ mod test { Ok(Global { name: "foo".into(), typename: None, - size: None + size: None, }) ); assert_eq!( @@ -576,7 +599,7 @@ mod test { Ok(Global { name: "foo".into(), typename: Some("Thing".into()), - size: None + size: None, }) ); assert_eq!( @@ -584,7 +607,7 @@ mod test { Ok(Global { name: "foo".into(), typename: Some("Thing".into()), - size: Some(Node::Number(10)) + size: Some(10.into()), }) ); assert_eq!( @@ -592,7 +615,7 @@ mod test { Ok(Global { name: "foo".into(), typename: None, - size: Some(Node::Number(10)) + size: Some(10.into()), }) ); } @@ -603,27 +626,24 @@ mod test { Const::from_str("const a = 123;"), Ok(Const { name: "a".into(), - value: Some(Node::Number(123)), - string: None + value: Some(123.into()), + string: None, }) ); assert_eq!( Const::from_str("const a = 0xaa;"), Ok(Const { name: "a".into(), - value: Some(Node::Number(0xaa)), - string: None + value: Some(0xaa.into()), + string: None, }) ); assert_eq!( Const::from_str("const a = -7;"), Ok(Const { name: "a".into(), - value: Some(Node::Prefix( - crate::ast::Prefix::Neg, - Node::Number(7).into() - )), - string: None + value: Some(Val::Number(7, vec![Prefix::Neg], vec![]).into()), + string: None, }) ); assert_eq!( @@ -631,7 +651,7 @@ mod test { Ok(Const { name: "a".into(), value: None, - string: Some("foo bar".into()) + string: Some("foo bar".into()), }) ) } @@ -646,14 +666,14 @@ mod test { Member { name: "x".into(), typename: None, - size: None + size: None, }, Member { name: "y".into(), typename: None, - size: None + size: None, }, - ] + ], }) ); @@ -664,8 +684,8 @@ mod test { members: vec![Member { name: "bar".into(), typename: None, - size: Some(Node::Number(100)) - },] + size: Some(100.into()), + }, ], }) ); @@ -676,8 +696,8 @@ mod test { members: vec![Member { name: "bar".into(), typename: Some("Thing".into()), - size: Some(Node::Number(100)) - },] + size: Some(100.into()), + }, ], }) ); } @@ -688,9 +708,6 @@ mod test { Function::from_str("fn foo() {}"), Ok(Function { name: "foo".into(), - inline: false, - org: None, - typename: None, args: vec![], body: Block(vec![]), }) @@ -699,18 +716,15 @@ mod test { Function::from_str("fn foo(a, b) {}"), Ok(Function { name: "foo".into(), - inline: false, - org: None, - typename: None, args: vec![ Argname { name: "a".into(), - typename: None + typename: None, }, Argname { name: "b".into(), - typename: None - } + typename: None, + }, ], body: Block(vec![]), }) @@ -719,18 +733,15 @@ mod test { Function::from_str("fn foo(a:Blah, b) {}"), Ok(Function { name: "foo".into(), - inline: false, - org: None, - typename: None, args: vec![ Argname { name: "a".into(), - typename: Some("Blah".into()) + typename: Some("Blah".into()), }, Argname { name: "b".into(), - typename: None - } + typename: None, + }, ], body: Block(vec![]), }) @@ -738,9 +749,6 @@ mod test { let func = Function { name: "foo".into(), - inline: true, - org: Some(0x400), - typename: None, args: vec![Argname { name: "a".into(), typename: None, @@ -760,179 +768,181 @@ mod test { #[test] fn parse_exprs() { - use Node::*; use Operator::*; // A very, very basic expression - assert_eq!(Node::from_str("23"), Ok(Number(23))); + // For the rest of these we'll .into() stuff for brevity + //Some(assert_eq!(Expr::from_str("23"), Ok(Expr { lhs: Val::Number(23, vec![], vec![]), op: None, rhs: None }))); // Two vals with an operator assert_eq!( - Node::from_str("23 + 5"), - Ok(Expr(23.into(), Add, Number(5).into())) + Expr::from_str("23 + 5"), + Ok(Expr { lhs: 23.into(), op: Some(Add), rhs: Some(5.into()) }) ); // Multiple terms at the same precedence level assert_eq!( - Node::from_str("1 + 2 + 3"), - Ok(Expr(Expr(1.into(), Add, 2.into()).into(), Add, 3.into())) + Expr::from_str("1 + 2 + 3"), + Ok(Expr { lhs: 1.into(), op: Some(Add), rhs: Some(Expr { lhs: 2.into(), op: Some(Add), rhs: Some(3.into()) }.into()) }) ); - // Higher precedence levels - assert_eq!( - Node::from_str("1 + 2 * 3"), - Ok(Expr(1.into(), Add, Expr(2.into(), Mul, 3.into()).into())) - ); + /* + // Higher precedence levels + assert_eq!( + Node::from_str("1 + 2 * 3"), + Ok(Expr(1.into(), Add, Expr(2.into(), Mul, 3.into()).into())) + ); - assert_eq!(Node::from_str("2 * 3"), Ok(Expr(2.into(), Mul, 3.into()))); + assert_eq!(Node::from_str("2 * 3"), Ok(Expr(2.into(), Mul, 3.into()))); - assert_eq!( - Node::from_str("2 * 3 + 4"), - Ok(Expr(Expr(2.into(), Mul, 3.into()).into(), Add, 4.into())) - ); + assert_eq!( + Node::from_str("2 * 3 + 4"), + Ok(Expr(Expr(2.into(), Mul, 3.into()).into(), Add, 4.into())) + ); - // Various operators - assert_eq!( - Node::from_str("1 || 2 && 3"), - Ok(Expr(1.into(), Or, Expr(2.into(), And, 3.into()).into())) - ); + // Various operators + assert_eq!( + Node::from_str("1 || 2 && 3"), + Ok(Expr(1.into(), Or, Expr(2.into(), And, 3.into()).into())) + ); - assert_eq!( - Node::from_str("2 && &blah"), - Ok(Expr(2.into(), And, Address("blah".into()).into())) - ); + assert_eq!( + Node::from_str("2 && &blah"), + Ok(Expr(2.into(), And, Address("blah".into()).into())) + ); - assert_eq!( - Node::from_str("2 & &blah"), - Ok(Expr(2.into(), BitAnd, Address("blah".into()).into())) - ); + assert_eq!( + Node::from_str("2 & &blah"), + Ok(Expr(2.into(), BitAnd, Address("blah".into()).into())) + ); - assert_eq!( - Node::from_str("1 | 2 ^ 3"), - Ok(Expr(1.into(), BitOr, Expr(2.into(), Xor, 3.into()).into())) - ); + assert_eq!( + Node::from_str("1 | 2 ^ 3"), + Ok(Expr(1.into(), BitOr, Expr(2.into(), Xor, 3.into()).into())) + ); - assert_eq!( - Node::from_str("x == y > z"), - Ok(Expr( - Name("x".into()).into(), - Eq, - Expr(Name("y".into()).into(), Gt, Name("z".into()).into()).into() - )) - ); + assert_eq!( + Node::from_str("x == y > z"), + Ok(Expr( + Name("x".into()).into(), + Eq, + Expr(Name("y".into()).into(), Gt, Name("z".into()).into()).into() + )) + ); - assert_eq!( - Node::from_str("1 << 6"), - Ok(Expr(1.into(), Lshift, 6.into())) - ); + assert_eq!( + Node::from_str("1 << 6"), + Ok(Expr(1.into(), Lshift, 6.into())) + ); - assert_eq!( - Node::from_str("!a - -3"), - Ok(Expr( - Prefix(crate::ast::Prefix::Not, Name("a".into()).into()).into(), - Sub, - Prefix(crate::ast::Prefix::Neg, 3.into()).into() - )) - ); + assert_eq!( + Node::from_str("!a - -3"), + Ok(Expr( + Prefix(crate::ast::Prefix::Not, Name("a".into()).into()).into(), + Sub, + Prefix(crate::ast::Prefix::Neg, 3.into()).into() + )) + ); - assert_eq!( - Node::from_str("-(4 * 5)"), - Ok(Prefix( - crate::ast::Prefix::Neg, - Expr(4.into(), Mul, 5.into()).into() - )) - ); + assert_eq!( + Node::from_str("-(4 * 5)"), + Ok(Prefix( + crate::ast::Prefix::Neg, + Expr(4.into(), Mul, 5.into()).into() + )) + ); - // Parens - assert_eq!( - Node::from_str("(1 + 2) * 3"), - Ok(Expr(Expr(1.into(), Add, 2.into()).into(), Mul, 3.into())) - ); + // Parens + assert_eq!( + Node::from_str("(1 + 2) * 3"), + Ok(Expr(Expr(1.into(), Add, 2.into()).into(), Mul, 3.into())) + ); + */ } #[test] fn parse_arrayrefs() { - use crate::ast::ArrayRef as AR; - use Node::*; - use Operator::*; - - // Normal numbers - assert_eq!( - AR::from_str("foo[7]"), - Ok(AR { - name: "foo".into(), - subscript: Number(7).into() - }) - ); - - // Full exprs (this is the last one of these; the full expr test above covers it - assert_eq!( - AR::from_str("foo[7+x]"), - Ok(AR { - name: "foo".into(), - subscript: Node::from_str("7+x").unwrap().into() - }) - ); + // use crate::ast::ArrayRef as AR; + // use Val::*; + // use Operator::*; + // + // // Normal numbers + // assert_eq!( + // AR::from_str("foo[7]"), + // Ok(AR { + // name: "foo".into(), + // subscript: Number(7).into() + // }) + // ); + // + // // Full exprs (this is the last one of these; the full expr test above covers it + // assert_eq!( + // AR::from_str("foo[7+x]"), + // Ok(AR { + // name: "foo".into(), + // subscript: Node::from_str("7+x").unwrap().into() + // }) + // ); // Exprs that are actually arrayrefs - assert_eq!( - Node::from_str("foo[7]"), - Ok(ArrayRef(AR { - name: "foo".into(), - subscript: Number(7).into() - })) - ); + // assert_eq!( + // Node::from_str("foo[7]"), + // Ok(ArrayRef(AR { + // name: "foo".into(), + // subscript: Number(7).into() + // })) + // ); } #[test] fn parse_addresses() { - assert_eq!(Node::from_str("&foo"), Ok(Node::Address("foo".into()))); + // assert_eq!(Node::from_str("&foo"), Ok(Node::Address("foo".into()))); } - #[test] - fn parse_calls() { - use Node::Number; - - let blah = Call { - name: "blah".into(), - args: vec![], - }; - - // Can Node parse a call? - assert_eq!(Node::from_str("blah()"), Ok(Node::Call(blah.clone()))); - - // Can Statement parse a call? - assert_eq!(Statement::from_str("blah();"), Ok(Statement::Call(blah))); - - // Calls with args - assert_eq!( - Call::from_str("blah(1, 2)"), - Ok(Call { - name: "blah".into(), - args: vec![Rvalue::Expr(Number(1)), Rvalue::Expr(Number(2))] - }) - ); - - // Calls with strings - assert_eq!( - Call::from_str("blah(\"foo\", 2)"), - Ok(Call { - name: "blah".into(), - args: vec![Rvalue::String("foo".into()), Rvalue::Expr(Number(2))] - }) - ); - } + // #[test] + // fn parse_calls() { + // use Val::Number; + // + // let blah = Call { + // name: "blah".into(), + // args: vec![], + // }; + // + // // Can Node parse a call? + // assert_eq!(Node::from_str("blah()"), Ok(Node::Call(blah.clone()))); + // + // // Can Statement parse a call? + // assert_eq!(Statement::from_str("blah();"), Ok(Statement::Call(blah))); + // + // // Calls with args + // // assert_eq!( + // // Call::from_str("blah(1, 2)"), + // // Ok(Call { + // // name: "blah".into(), + // // args: vec![Rvalue::Expr(Number(1)), Rvalue::Expr(Number(2))] + // // }) + // // ); + // + // // Calls with strings + // // assert_eq!( + // // Call::from_str("blah(\"foo\", 2)"), + // // Ok(Call { + // // name: "blah".into(), + // // args: vec![Rvalue::String("foo".into()), Rvalue::Expr(Number(2))] + // // }) + // // ); + // } #[test] fn parse_return() { - assert_eq!( - Statement::from_str("return;"), - Ok(Statement::Return(Return(None))) - ); - - assert_eq!( - Statement::from_str("return 17;"), - Ok(Statement::Return(Return(Some(Node::Number(17))))) - ); + // assert_eq!( + // Statement::from_str("return;"), + // Ok(Statement::Return(Return(None))) + // ); + // + // assert_eq!( + // Statement::from_str("return 17;"), + // Ok(Statement::Return(Return(Some(Node::Number(17))))) + // ); } #[test] @@ -941,7 +951,7 @@ mod test { Statement::from_str("foo = 7;"), Ok(Statement::Assignment(Assignment { lvalue: Lvalue::Name("foo".into()), - rvalue: Rvalue::Expr(Node::Number(7)) + rvalue: Rvalue::Expr(7.into()), })) ); @@ -950,9 +960,9 @@ mod test { Ok(Assignment { lvalue: Lvalue::ArrayRef(ArrayRef { name: "foo".into(), - subscript: Node::Number(45).into(), + subscript: 45.into(), }), - rvalue: Rvalue::Expr(Node::Number(7)) + rvalue: Rvalue::Expr(7.into()), }) ); } @@ -974,44 +984,44 @@ mod test { Ok(VarDecl { name: "blah".into(), typename: Some("Foo".into()), - size: Some(Node::Number(7)), - initial: Some(Node::Number(35)), + size: Some(7.into()), + initial: Some(35.into()), }) ); } - #[test] - fn parse_block() { - assert_eq!( - Block::from_str("{ foo(); bar(); }"), - Ok(Block(vec![ - Statement::Call(Call { - name: "foo".into(), - args: vec![] - }), - Statement::Call(Call { - name: "bar".into(), - args: vec![] - }), - ])) - ); - } + // #[test] + // fn parse_block() { + // assert_eq!( + // Block::from_str("{ foo(); bar(); }"), + // Ok(Block(vec![ + // Statement::Call(Call { + // name: "foo".into(), + // args: vec![] + // }), + // Statement::Call(Call { + // name: "bar".into(), + // args: vec![] + // }), + // ])) + // ); + // } #[test] fn parse_conditional() { assert_eq!( Statement::from_str("if(cond) { foo(); }"), Ok(Statement::Conditional(Conditional { - condition: Node::from_str("cond").unwrap(), + condition: Expr::from_str("cond").unwrap(), body: Block::from_str("{ foo(); }").unwrap(), - alternative: None + alternative: None, })) ); assert_eq!( Statement::from_str("if(cond) { foo(); } else { bar(); }"), Ok(Statement::Conditional(Conditional { - condition: Node::from_str("cond").unwrap(), + condition: Expr::from_str("cond").unwrap(), body: Block::from_str("{ foo(); }").unwrap(), alternative: Some(Block::from_str("{ bar(); }").unwrap()), })) @@ -1023,7 +1033,7 @@ mod test { assert_eq!( Statement::from_str("while(cond) { foo(); }"), Ok(Statement::WhileLoop(WhileLoop { - condition: Node::from_str("cond").unwrap(), + condition: Expr::from_str("cond").unwrap(), body: Block::from_str("{ foo(); }").unwrap(), })) ); @@ -1031,33 +1041,33 @@ mod test { #[test] fn parse_repeat_loops() { - assert_eq!( - Statement::from_str("repeat(10) x { foo(x); }"), - Ok(Statement::RepeatLoop(RepeatLoop { - count: Node::Number(10), - name: Some("x".into()), - body: Block::from_str("{ foo(x); }").unwrap(), - })) - ); - - assert_eq!( - Statement::from_str("repeat(10) { foo(); }"), - Ok(Statement::RepeatLoop(RepeatLoop { - count: Node::Number(10), - name: None, - body: Block::from_str("{ foo(); }").unwrap(), - })) - ); + // assert_eq!( + // Statement::from_str("repeat(10) x { foo(x); }"), + // Ok(Statement::RepeatLoop(RepeatLoop { + // count: Node::Number(10), + // name: Some("x".into()), + // body: Block::from_str("{ foo(x); }").unwrap(), + // })) + // ); + // + // assert_eq!( + // Statement::from_str("repeat(10) { foo(); }"), + // Ok(Statement::RepeatLoop(RepeatLoop { + // count: Node::Number(10), + // name: None, + // body: Block::from_str("{ foo(); }").unwrap(), + // })) + // ); } #[test] fn parse_program() { - assert_eq!( - Program::from_str("global foo; struct Point { x, y }"), - Ok(Program(vec![ - Declaration::from_str("global foo;").unwrap(), - Declaration::from_str("struct Point { x, y }").unwrap(), - ])) - ) + // assert_eq!( + // Program::from_str("global foo; struct Point { x, y }"), + // Ok(Program(vec![ + // Declaration::from_str("global foo;").unwrap(), + // Declaration::from_str("struct Point { x, y }").unwrap(), + // ])) + // ) } } diff --git a/forge_core/src/new.pest b/forge_core/src/new.pest index d7d151f..d072384 100644 --- a/forge_core/src/new.pest +++ b/forge_core/src/new.pest @@ -64,19 +64,8 @@ operator = _{ | ne } -expr = { prefix? ~ val ~ suffix* ~ (operator ~ prefix? ~ val ~ suffix*)* } -val = { - // These are what get evaluated and left on the stack: - number - | // Literal numbers - ("(" ~ expr ~ ")") - | // Nested parenthesized exprs - // Bare literal ids, fn calls, array references - // (call, or pointer arithmetic, since ids all reference addresses) - // (multiple calls / subscripts aren't allowed; use CALL or collapse to one - // subscript) - name -} +expr = { val ~ (operator ~ val)* } +val = { prefix* ~ (number | name | "(" ~ expr ~ ")") ~ suffix* } suffix = { subscript | arglist | member } subscript = { "[" ~ expr ~ "]" }