From 3b612114f5ba07ea19b014e004c11ae965a4039b Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Fri, 4 Aug 2023 17:27:28 -0500 Subject: [PATCH] More new grammar stuff --- forge_core/src/ast.rs | 100 ++----- forge_core/src/compiler.rs | 500 +++++++++++++++++---------------- forge_core/src/forge_parser.rs | 188 ++++--------- forge_core/src/new.pest | 11 +- 4 files changed, 340 insertions(+), 459 deletions(-) diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index 2517003..2a85490 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -79,9 +79,21 @@ pub struct Assignment { } #[derive(PartialEq, Clone, Debug)] -pub enum Lvalue { - ArrayRef(String, Expr), - Name(String), +pub struct Lvalue { + pub name: String, + pub subscripts: Vec, +} + +impl From<&str> for Lvalue { + fn from(name: &str) -> Self { + Self { name: String::from(name), subscripts: vec![] } + } +} + +impl From for Lvalue { + fn from(name: String) -> Self { + Self { name, subscripts: vec![] } + } } #[derive(PartialEq, Clone, Debug)] @@ -95,7 +107,7 @@ pub struct VarDecl { pub name: String, pub typename: Option, pub size: Option, - pub initial: Option, + pub initial: Option, } #[derive(PartialEq, Clone, Debug)] @@ -157,87 +169,21 @@ pub enum Suffix { #[derive(Debug, PartialEq, Clone)] pub enum Expr { - Val(Val), - Prefix(Prefix, BoxExpr), - Suffix(BoxExpr, Suffix), - Infix(BoxExpr, Operator, BoxExpr) -} - -// #[derive(PartialEq, Clone, Debug)] -// pub struct Expr { -// pub lhs: Val, -// pub prefix: Vec, -// pub suffix: Vec, -// pub op: Option, -// pub rhs: Option, -// } - -#[derive(PartialEq, Clone, Debug)] -pub enum Val { Number(i32), Name(String), Expr(BoxExpr), -} - -// 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 for Val { - fn from(val: i32) -> Self { - Self::Number(val) - } -} - -impl From<&str> for Val { - fn from(s: &str) -> Self { - Self::Name(String::from(s)) - } -} - -impl From for Val { - fn from(value: Expr) -> Self { - Self::Expr(value.into()) - } -} - -impl From for Val { - fn from(value: BoxExpr) -> Self { - Self::Expr(value) - } -} - -impl From for BoxExpr { - fn from(value: Val) -> Self { - Self::from(Expr::from(value)) - } + Prefix(Prefix, BoxExpr), + Suffix(BoxExpr, Suffix), + Infix(BoxExpr, Operator, BoxExpr) } #[repr(transparent)] #[derive(PartialEq, Clone, Debug)] pub struct BoxExpr(pub Box); -impl From for Expr { - fn from(value: Val) -> Self { - Self::Val(value) - } -} - impl From for BoxExpr { fn from(val: i32) -> Self { - BoxExpr(Box::from(Expr::from(Val::from(val)))) + BoxExpr(Box::from(Expr::Number(val))) } } @@ -249,7 +195,7 @@ impl From for BoxExpr { impl From<&str> for BoxExpr { fn from(value: &str) -> Self { - Expr::Val(Val::Name(String::from(value))).into() + Expr::Name(String::from(value)).into() } } @@ -261,13 +207,13 @@ impl From for Expr { impl From for Expr { fn from(value: i32) -> Self { - Self::Val(Val::Number(value)) + Self::Number(value) } } impl From<&str> for Expr { fn from(value: &str) -> Self { - Self::Val(Val::Name(String::from(value))) + Self::Name(String::from(value)) } } diff --git a/forge_core/src/compiler.rs b/forge_core/src/compiler.rs index 189029d..06343e8 100644 --- a/forge_core/src/compiler.rs +++ b/forge_core/src/compiler.rs @@ -221,12 +221,11 @@ impl Compilable for Function { Statement::Return(_) => {} Statement::Assignment(assign) => assign.process(state, Some(&mut sig))?, 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") + 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(_) => { @@ -259,18 +258,8 @@ impl Compilable for Assignment { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { let Assignment { lvalue, rvalue } = self; let sig = sig.expect("Assignment outside function"); - - // 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); - // } - // } - - // Then process the lvalue and storew + // First the value, then the address we'll storew it to + rvalue.process(state, Some(sig))?; lvalue.process(state, Some(sig))?; sig.emit("storew"); Ok(()) @@ -281,25 +270,42 @@ impl Compilable for Assignment { impl Compilable for VarDecl { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { - 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(()) + 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::from(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(()) + } +} + +/////////////////////////////////////////////////////////// + +impl Compilable for Rvalue { + fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { + let sig = sig.expect("Assignment outside function"); + // 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 self { + Rvalue::Expr(e) => e.process(state, Some(sig)), + Rvalue::String(string) => { + let label = state.add_string(&string); + sig.emit_arg("push", label); + Ok(()) + } + } } } @@ -310,36 +316,34 @@ impl Compilable for Lvalue { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { let global_scope = &state.global_scope; let mut sig = sig.expect("lvalue outside a function"); - match self { - Lvalue::ArrayRef(_, _) => todo!("Arrays are not implemented yet"), - Lvalue::Name(name) => { - if let Some(var) = lookup(&name, global_scope, &sig.local_scope) { - match var { - Variable::Literal(_) | Variable::DirectLabel(_) => { - // Direct labels are (probably) functions, the important part is the - // label itself, which we can't alter, so, error: - Err(CompileError(0, 0, format!("Invalid lvalue {}", name))) - } - Variable::IndirectLabel(label) => { - // Indirect labels are variables, the label is where the data is stored, - // so we push that label so we can store stuff there - let label = label.clone(); - sig.emit_arg("push", label); - Ok(()) - } - Variable::Local(offset) => { - let offset = *offset; - sig.emit_arg("loadw", "frame"); - if offset > 0 { - sig.emit_arg("add", offset); - } - Ok(()) - } + + if !self.subscripts.is_empty() { todo!("Arrays and structs aren't implemented yet") } + + if let Some(var) = lookup(&self.name, global_scope, &sig.local_scope) { + match var { + Variable::Literal(_) | Variable::DirectLabel(_) => { + // Direct labels are (probably) functions, the important part is the + // label itself, which we can't alter, so, error: + Err(CompileError(0, 0, format!("Invalid lvalue {}", self.name))) + } + Variable::IndirectLabel(label) => { + // Indirect labels are variables, the label is where the data is stored, + // so we push that label so we can store stuff there + let label = label.clone(); + sig.emit_arg("push", label); + Ok(()) + } + Variable::Local(offset) => { + let offset = *offset; + sig.emit_arg("loadw", "frame"); + if offset > 0 { + sig.emit_arg("add", offset); } - } else { - Err(CompileError(0, 0, format!("Unknown name {}", name))) + Ok(()) } } + } else { + Err(CompileError(0, 0, format!("Unknown name {}", self.name))) } } } @@ -350,118 +354,125 @@ impl Compilable for Lvalue { /// This recursively evaluates a Node and leaves its value on the stack. impl Compilable for Expr { fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> { - 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(()) - // // } - // } + 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 { + Expr::Number(n) => { + // Numbers are just pushed as literals + sig.body.push(format!("push {}", n)); + Ok(()) + } + Expr::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))), + } + } + Expr::Expr(e) => { + // Just an expr containing an expr, recurse + (*e.0).process(state, Some(sig))?; + Ok(()) + } + Expr::Prefix(pre, e) => { + (*e.0).process(state, Some(sig))?; + match pre { + Prefix::Neg => { + // To arithmetically negate something, invert and increment (2s complement) + sig.emit("xor -1"); + sig.emit("add 1"); + } + Prefix::Not => sig.emit("not"), + Prefix::Address => { todo!() } + } + Ok(()) + } + Expr::Suffix(_, _) => {todo!()} + Expr::Infix(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(()) + } + } } } @@ -480,18 +491,17 @@ impl Compilable for Global { impl Compilable for Const { fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> { - 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()) + 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()) } } @@ -507,62 +517,48 @@ 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: 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) - // // } - // // } - // // } - // // } - // } + match expr { + Expr::Number(n) => Ok(n), // That was easy + Expr::Name(n) => if let Some(Variable::Literal(val)) = scope.get(&n) { + Ok(*val) + } else { + Err(CompileError(0, 0, format!("Unknown const {}", n))) + } + Expr::Expr(e) => eval_const(*e.0, scope), + Expr::Prefix(pre, e) => { + let val = eval_const(*e.0, scope)?; + match pre { + Prefix::Neg => Ok(-val), + Prefix::Not => Ok(if val != 0 { 0 } else { 1 }), + Prefix::Address => Err(CompileError(0, 0, String::from("Addresses are not know at compile time"))) + } + } + Expr::Suffix(_, _) => Err(CompileError(0, 0, String::from("Constants must be statically defined"))), + Expr::Infix(lhs, op, rhs) => { + let lhs = eval_const(*lhs.0, scope)?; + let rhs = eval_const(*rhs.0, 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), + } + } + } } #[cfg(test)] @@ -687,7 +683,7 @@ mod test { #[test] fn test_literal_strings() { let mut state = State::default(); - parse("const s1 = \"foo\"; fn blah() { var x; x = \"bar\"; }") + parse("const s1 = \"foo\"; fn blah() { var x; x = \"bar\"; var y = \"norp\"; }") .unwrap() .process(&mut state, None) .expect("Failed to compile"); @@ -696,12 +692,20 @@ mod test { state.strings, vec![ ("_gensym_1".into(), "foo".into()), - ("_gensym_3".into(), "bar".into()) // gensym 2 is the entrypoint of blah() + ("_gensym_3".into(), "bar".into()), // gensym 2 is the entrypoint of blah() + ("_gensym_4".into(), "norp".into()) ] ); assert_eq!( body, - vec!["push _gensym_3", "loadw frame", "storew"].join("\n") - ) // todo we want to allow strings in initializers also + vec![ + "push _gensym_3", + "loadw frame", + "storew", // the assignment for x + "push _gensym_4", + "loadw frame", + "add 3", // the address of y (frame + 3) and put gensym_4 in it + "storew"].join("\n") + ) } } diff --git a/forge_core/src/forge_parser.rs b/forge_core/src/forge_parser.rs index edae646..a17d3c3 100644 --- a/forge_core/src/forge_parser.rs +++ b/forge_core/src/forge_parser.rs @@ -31,7 +31,6 @@ 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>; @@ -325,13 +324,7 @@ impl AstNode for Assignment { const RULE: Rule = Rule::assignment; fn from_pair(pair: Pair) -> Self { let mut pairs = pair.into_inner(); - let lvalue_pair = pairs.next().unwrap(); - let lvalue = Lvalue::from_pair(lvalue_pair); - // let lvalue = match lvalue_pair.as_rule() { - // Rule::subscript => Lvalue::ArrayRef(Subscript::from_pair(lvalue_pair)), - // Rule::name => Lvalue::Name(String::from(lvalue_pair.as_str())), - // _ => unreachable!(), - // }; + let lvalue = Lvalue::from_pair(pairs.next().unwrap()); let rvalue = Rvalue::from_pair(pairs.next().unwrap()); Self { lvalue, rvalue } } @@ -343,9 +336,13 @@ impl AstNode for Lvalue { const RULE: Rule = Rule::lvalue; fn from_pair(pair: Pair) -> Self { let mut pairs = pair.into_inner(); - let name = pairs.next().unwrap().as_str(); - pairs.next().map_or(Lvalue::Name(String::from(name)), - |subscript| Lvalue::ArrayRef(String::from(name), Expr::from_pair(subscript.first()))) + let name = String::from(pairs.next().unwrap().as_str()); + let subscripts: Vec<_> = pairs.map(|p| match p.as_rule() { + Rule::subscript => Suffix::Subscript(Expr::from_pair(p.first()).into()), + Rule::member => Suffix::Member(String::from(p.as_str())), + _ => unreachable!() + }).collect(); + Self { name, subscripts } } } @@ -372,7 +369,7 @@ impl AstNode for VarDecl { 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(Expr::from_pair); + let initial = inner.next().map(Rvalue::from_pair); Self { name, typename, @@ -446,7 +443,7 @@ impl AstNode for Expr { // expr = { prefix* ~ val ~ suffix* ~ (operator ~ prefix* ~ val ~ suffix*)* } // Each of these map methods turns a thing into an expr. Which means expr HAS // to be an enum with the different possible forms these things can take: - // - if it's a val, it goes into map_primary and returns an Expr::Val + // - if it's a term, it goes into map_primary and returns an Expr::Number or Name // - If it's a prefix or suffix, it goes into map_prefix or map_postfix, and // returns an Expr::Prefix or Expr::Suffix // - Operators go into map_infix along with two exprs for the left and right @@ -454,13 +451,12 @@ impl AstNode for Expr { // The output of all this is an Expr, containing a tree of other Exprs of // various forms. PRATT_PARSER - .map_primary(|val| { - let val = Val::from_pair(val); - // If the val is a parenthesized expr, just unwrap it - if let Val::Expr(expr) = val { - *expr.0 - } else { - Expr::Val(val) + .map_primary(|term| { + match term.as_rule() { + Rule::number => Expr::Number(term.into_number()), + Rule::name => Expr::Name(String::from(term.as_str())), + Rule::expr => Expr::from_pair(term).into(), + _ => unreachable!() } }) .map_infix(|lhs, op, rhs| @@ -485,7 +481,6 @@ impl Expr { impl AstNode for Operator { const RULE: Rule = Rule::operator; - // also term_op fn from_pair(pair: Pair) -> Self { match pair.as_str() { "+" => Self::Add, @@ -532,10 +527,10 @@ impl AstNode for Suffix { fn from_pair(pair: Pair) -> Self { let first = pair.first(); match first.as_rule() { - Rule::subscript => Subscript(Expr::from_pair(first.first()).into()), + Rule::subscript => Self::Subscript(Expr::from_pair(first.first()).into()), Rule::member => Self::Member(first.first_as_string()), - Rule::arglist => Arglist(first.into_inner().map(Rvalue::from_pair).collect()), - _ => unreachable!() + Rule::arglist => Self::Arglist(first.into_inner().map(Rvalue::from_pair).collect()), + rule => unreachable!("Expected a subscript, member, or arglist, got a {:?}", rule) } } } @@ -558,33 +553,10 @@ impl AstNode for Program { /////////////////////////////////////////////////////////////////////////////////////////// -impl AstNode for Val { - const RULE: Rule = Rule::val; - - fn from_pair(pair: Pair) -> Self { - let val = pair.first(); - match val.as_rule() { - Rule::number => Self::Number(val.into_number()), - Rule::name => Self::Name(String::from(val.as_str())), - Rule::expr => Self::Expr(Expr::from_pair(val).into()), - _ => 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()))); - } - #[test] fn parse_globals() { assert_eq!( @@ -768,7 +740,7 @@ mod test { // A very, very basic expression assert_eq!( Expr::from_str("23"), - Ok(Expr::Val(Val::Number(23))) + Ok(Expr::Number(23)) ); // Two vals with an operator @@ -879,47 +851,11 @@ mod test { ); } - #[test] - fn parse_arrayrefs() { - // 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() - // })) - // ); - } - #[test] fn parse_calls() { - use Val::Number; - let blah = Expr::Suffix( "blah".into(), - Arglist(vec![]) + Suffix::Arglist(vec![]) ); // Can Node parse a call? @@ -933,7 +869,7 @@ mod test { Expr::from_str("blah(1, 2)"), Ok(Expr::Suffix( "blah".into(), - Arglist(vec![1.into(), 2.into()]))) + Suffix::Arglist(vec![1.into(), 2.into()]))) ); //Calls with strings @@ -941,7 +877,7 @@ mod test { Expr::from_str("blah(\"foo\", 2)"), Ok(Expr::Suffix( "blah".into(), - Arglist(vec!["foo".into(), 2.into()]))) + Suffix::Arglist(vec!["foo".into(), 2.into()]))) ); } @@ -963,7 +899,7 @@ mod test { assert_eq!( Statement::from_str("foo = 7;"), Ok(Statement::Assignment(Assignment { - lvalue: Lvalue::Name("foo".into()), + lvalue: "foo".into(), rvalue: Rvalue::Expr(7.into()), })) ); @@ -971,7 +907,7 @@ mod test { assert_eq!( Assignment::from_str("foo[45] = 7"), Ok(Assignment { - lvalue: Lvalue::ArrayRef("foo".into(), 45.into()), + lvalue: Lvalue { name: String::from("foo"), subscripts: vec![Suffix::Subscript(45.into())] }, rvalue: Rvalue::Expr(7.into()), }) ); @@ -1000,22 +936,16 @@ mod test { ); } - // #[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::Expr(Expr::Suffix("foo".into(), Suffix::Arglist(vec![]))), + Statement::Expr(Expr::Suffix("bar".into(), Suffix::Arglist(vec![]))), + ])) + ); + } #[test] fn parse_conditional() { @@ -1051,33 +981,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: 10.into(), + name: Some("x".into()), + body: Block::from_str("{ foo(x); }").unwrap(), + })) + ); + + assert_eq!( + Statement::from_str("repeat(10) { foo(); }"), + Ok(Statement::RepeatLoop(RepeatLoop { + count: 10.into(), + 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 620bef5..707c401 100644 --- a/forge_core/src/new.pest +++ b/forge_core/src/new.pest @@ -20,7 +20,7 @@ string_inner = ${ !("\"" | "\\") ~ ANY | escape } string = ${ "\"" ~ string_inner* ~ "\"" } assignment = { lvalue ~ "=" ~ rvalue } -lvalue = { name ~ subscript? } +lvalue = { name ~ (modifier)* } rvalue = { expr | string } add = { "+" } @@ -64,10 +64,11 @@ operator = _{ | ne } -expr = { prefix* ~ val ~ suffix* ~ (operator ~ prefix* ~ val ~ suffix*)* } -val = { number | name | "(" ~ expr ~ ")" } +expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* } +term = _{ number | name | "(" ~ expr ~ ")" } -suffix = { subscript | arglist | member } +suffix = { modifier | arglist } +modifier = _{ subscript | member } subscript = { "[" ~ expr ~ "]" } arglist = { "(" ~ (rvalue ~ ("," ~ rvalue)*)? ~ ")" } member = { "." ~ name } @@ -91,7 +92,7 @@ return_stmt = { "return" ~ expr? } conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? } while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block } repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block } -var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ expr)? } +var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ rvalue)? } global = { "global" ~ name ~ varinfo ~ ";" } typename = { ":" ~ name } size = { "[" ~ expr ~ "]" }