diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index 2a85490..be45fab 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -86,13 +86,19 @@ pub struct Lvalue { impl From<&str> for Lvalue { fn from(name: &str) -> Self { - Self { name: String::from(name), subscripts: vec![] } + Self { + name: String::from(name), + subscripts: vec![], + } } } impl From for Lvalue { fn from(name: String) -> Self { - Self { name, subscripts: vec![] } + Self { + name, + subscripts: vec![], + } } } @@ -153,13 +159,6 @@ pub enum Operator { Rshift, } -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum Prefix { - Neg, - Not, - Address -} - #[derive(Debug, PartialEq, Clone)] pub enum Suffix { Subscript(BoxExpr), @@ -172,9 +171,11 @@ pub enum Expr { Number(i32), Name(String), Expr(BoxExpr), - Prefix(Prefix, BoxExpr), + Not(BoxExpr), + Neg(BoxExpr), + Address(Lvalue), Suffix(BoxExpr, Suffix), - Infix(BoxExpr, Operator, BoxExpr) + Infix(BoxExpr, Operator, BoxExpr), } #[repr(transparent)] diff --git a/forge_core/src/compiler.rs b/forge_core/src/compiler.rs index 06343e8..9a84d62 100644 --- a/forge_core/src/compiler.rs +++ b/forge_core/src/compiler.rs @@ -317,7 +317,9 @@ impl Compilable for Lvalue { let global_scope = &state.global_scope; let mut sig = sig.expect("lvalue outside a function"); - if !self.subscripts.is_empty() { todo!("Arrays and structs aren't implemented yet") } + 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 { @@ -409,20 +411,23 @@ impl Compilable for Expr { (*e.0).process(state, Some(sig))?; Ok(()) } - Expr::Prefix(pre, e) => { + Expr::Neg(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!() } - } + // To arithmetically negate something, invert and increment (2s complement) + sig.emit("xor -1"); + sig.emit("add 1"); Ok(()) } - Expr::Suffix(_, _) => {todo!()} + Expr::Not(e) => { + (*e.0).process(state, Some(sig))?; + sig.emit("not"); + Ok(()) + } + // Handling addresses is very easy because processing an lvalue leaves the address on the stack + Expr::Address(lvalue) => lvalue.process(state, Some(sig)), + Expr::Suffix(_, _) => { + todo!() + } Expr::Infix(lhs, op, rhs) => { // Recurse on expressions, handling operators (*lhs.0).process(state, Some(&mut sig))?; @@ -519,21 +524,32 @@ fn to_flag(val: bool) -> i32 { pub fn eval_const(expr: Expr, scope: &Scope) -> Result { match expr { Expr::Number(n) => Ok(n), // That was easy - Expr::Name(n) => if let Some(Variable::Literal(val)) = scope.get(&n) { + 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::Expr(e) => eval_const(*e.0, scope), + Expr::Neg(e) => { + let val = eval_const(*e.0, scope)?; + Ok(-val) + } + Expr::Not(e) => { + let val = eval_const(*e.0, scope)?; + Ok(if val != 0 { 0 } else { 1 }) + } + Expr::Address(_) => Err(CompileError( + 0, + 0, + String::from("Addresses are not known 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)?; @@ -705,7 +721,32 @@ mod test { "push _gensym_4", "loadw frame", "add 3", // the address of y (frame + 3) and put gensym_4 in it - "storew"].join("\n") + "storew" + ] + .join("\n") + ) + } + + #[test] + fn test_addresses() { + let mut state = State::default(); + parse("fn blah() { var x = 3; var y = &x; }") + .unwrap() + .process(&mut state, None) + .expect("Failed to compile"); + let body = body_as_string(state.functions.get("blah").unwrap()); + assert_eq!( + body, + vec![ + "push 3", + "loadw frame", + "storew", // the assignment for x + "loadw frame", // The addr of x + "loadw frame", + "add 3", // the address of y (frame + 3) and put the addr of x (frame) in it + "storew" + ] + .join("\n") ) } } diff --git a/forge_core/src/forge_parser.rs b/forge_core/src/forge_parser.rs index a17d3c3..5e27f47 100644 --- a/forge_core/src/forge_parser.rs +++ b/forge_core/src/forge_parser.rs @@ -270,11 +270,7 @@ impl AstNode for Function { let body = Block::from_pair(inner.next().unwrap()); - Self { - name, - args, - body, - } + Self { name, args, body } } } @@ -337,11 +333,13 @@ impl AstNode for Lvalue { fn from_pair(pair: Pair) -> Self { let mut pairs = pair.into_inner(); 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(); + let subscripts: Vec<_> = pairs + .map(|p| match p.as_rule() { + Rule::subscript => Suffix::Subscript(Expr::from_pair(p.first()).into()), + Rule::member => Suffix::Member(p.first_as_string()), + _ => unreachable!(), + }) + .collect(); Self { name, subscripts } } } @@ -451,22 +449,20 @@ 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(|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_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), + Rule::lvalue => Expr::Address(Lvalue::from_pair(term)), + _ => unreachable!(), }) - .map_infix(|lhs, op, rhs| - Expr::Infix(lhs.into(), Operator::from_pair(op), rhs.into()) - ) - .map_prefix(|prefix, expr| - Expr::Prefix(Prefix::from_pair(prefix), expr.into()) - ) - .map_postfix(|expr, suffix| - Expr::Suffix(expr.into(), Suffix::from_pair(suffix))) + .map_infix(|lhs, op, rhs| Expr::Infix(lhs.into(), Operator::from_pair(op), rhs.into())) + .map_prefix(|prefix, expr| match prefix.as_str() { + "-" => Expr::Neg(expr.into()), + "!" => Expr::Not(expr.into()), + _ => unreachable!(), + }) + .map_postfix(|expr, suffix| Expr::Suffix(expr.into(), Suffix::from_pair(suffix))) .parse(pair.into_inner()) } } @@ -506,19 +502,6 @@ impl AstNode for Operator { } } -impl AstNode for Prefix { - const RULE: Rule = Rule::prefix; - - fn from_pair(pair: Pair) -> Self { - match pair.as_str() { - "!" => Self::Not, - "-" => Self::Neg, - "&" => Self::Address, - _ => unreachable!(), - } - } -} - /////////////////////////////////////////////////////////////////////////////////////////// impl AstNode for Suffix { @@ -530,7 +513,7 @@ impl AstNode for Suffix { Rule::subscript => Self::Subscript(Expr::from_pair(first.first()).into()), Rule::member => Self::Member(first.first_as_string()), Rule::arglist => Self::Arglist(first.into_inner().map(Rvalue::from_pair).collect()), - rule => unreachable!("Expected a subscript, member, or arglist, got a {:?}", rule) + rule => unreachable!("Expected a subscript, member, or arglist, got a {:?}", rule), } } } @@ -615,7 +598,7 @@ mod test { Const::from_str("const a = -7;"), Ok(Const { name: "a".into(), - value: Some(Expr::Prefix(Prefix::Neg, 7.into()).into()), + value: Some(Expr::Neg(7.into()).into()), string: None, }) ); @@ -658,7 +641,7 @@ mod test { name: "bar".into(), typename: None, size: Some(100.into()), - }, ], + },], }) ); @@ -670,7 +653,7 @@ mod test { name: "bar".into(), typename: Some("Thing".into()), size: Some(100.into()), - }, ], + },], }) ); } @@ -732,16 +715,12 @@ mod test { #[test] fn parse_exprs() { - use Operator::*; - use Prefix::*; - use Suffix::*; use Expr::Infix; + use Operator::*; + use Suffix::*; // A very, very basic expression - assert_eq!( - Expr::from_str("23"), - Ok(Expr::Number(23)) - ); + assert_eq!(Expr::from_str("23"), Ok(Expr::Number(23))); // Two vals with an operator assert_eq!( @@ -756,14 +735,13 @@ mod test { ); // Simple prefix - assert_eq!(Expr::from_str("-5"), - Ok(Expr::Prefix(Neg, 5.into()))); + assert_eq!(Expr::from_str("-5"), Ok(Expr::Neg(5.into()))); // Multiple prefixes assert_eq!( - Expr::from_str("!&foo"), - Ok(Expr::Prefix(Not, - Expr::Prefix(Address, "foo".into()).into()))); + Expr::from_str("!-foo"), + Ok(Expr::Not(Expr::Neg("foo".into()).into())) + ); // Simple suffix assert_eq!( @@ -776,7 +754,8 @@ mod test { Expr::from_str("foo[10].bar"), Ok(Expr::Suffix( Expr::Suffix("foo".into(), Subscript(10.into())).into(), - Member("bar".into()))) + Member("bar".into()) + )) ); // Higher precedence levels @@ -785,10 +764,7 @@ mod test { Ok(Infix(1.into(), Add, Infix(2.into(), Mul, 3.into()).into())) ); - assert_eq!( - Expr::from_str("2 * 3"), - Ok(Infix(2.into(), Mul, 3.into())) - ); + assert_eq!(Expr::from_str("2 * 3"), Ok(Infix(2.into(), Mul, 3.into()))); assert_eq!( Expr::from_str("2 * 3 + 4"), @@ -803,22 +779,30 @@ mod test { assert_eq!( Expr::from_str("2 && &blah"), - Ok(Infix(2.into(), And, Expr::Prefix(Address, "blah".into()).into())) + Ok(Infix(2.into(), And, Expr::Address("blah".into()).into())) ); assert_eq!( Expr::from_str("2 & &blah"), - Ok(Infix(2.into(), BitAnd, Expr::Prefix(Address, "blah".into()).into())) + Ok(Infix(2.into(), BitAnd, Expr::Address("blah".into()).into())) ); assert_eq!( Expr::from_str("1 | 2 ^ 3"), - Ok(Infix(1.into(), BitOr, Infix(2.into(), Xor, 3.into()).into())) + Ok(Infix( + 1.into(), + BitOr, + Infix(2.into(), Xor, 3.into()).into() + )) ); assert_eq!( Expr::from_str("x == y > z"), - Ok(Infix("x".into(), Eq, Infix("y".into(), Gt, "z".into()).into())) + Ok(Infix( + "x".into(), + Eq, + Infix("y".into(), Gt, "z".into()).into() + )) ); assert_eq!( @@ -828,35 +812,57 @@ mod test { assert_eq!( Expr::from_str("!a - -3"), - Ok(Infix(Expr::Prefix(Not, "a".into()).into(), Sub, Expr::Prefix(Neg, 3.into()).into())) + Ok(Infix( + Expr::Not("a".into()).into(), + Sub, + Expr::Neg(3.into()).into() + )) ); assert_eq!( Expr::from_str("-(4 * 5)"), - Ok(Expr::Prefix(Neg, - Infix(4.into(), Mul, 5.into()).into() - )) + Ok(Expr::Neg(Infix(4.into(), Mul, 5.into()).into())) ); // Parens assert_eq!( Expr::from_str("(1 + 2) * 3"), - Ok( - Infix( - Infix(1.into(), Add, 2.into()).into(), - Mul, - 3.into() - ) - ) + Ok(Infix(Infix(1.into(), Add, 2.into()).into(), Mul, 3.into())) ); + + // Addresses + assert_eq!( + Expr::from_str("&foo.bar"), + Ok(Expr::Address(Lvalue { + name: "foo".into(), + subscripts: vec![Suffix::Member("bar".into())] + })) + ); + + assert_eq!( + Expr::from_str("&foo + 7"), + Ok(Expr::Infix( + Expr::Address("foo".into()).into(), + Add, + 7.into() + )) + ); + + // This is godawful but legal _as long as it parses like this._ The arglist suffix on the end + // goes on the "&foo" expression as a whole, so, it "calls" the address of foo. Essentially: + // "push foo; call" rather than "loadw foo; call" + assert_eq!( + Expr::from_str("&foo()"), + Ok(Expr::Suffix( + Expr::Address("foo".into()).into(), + Suffix::Arglist(vec![]) + )) + ) } #[test] fn parse_calls() { - let blah = Expr::Suffix( - "blah".into(), - Suffix::Arglist(vec![]) - ); + let blah = Expr::Suffix("blah".into(), Suffix::Arglist(vec![])); // Can Node parse a call? assert_eq!(Expr::from_str("blah()"), Ok(blah.clone())); @@ -869,7 +875,8 @@ mod test { Expr::from_str("blah(1, 2)"), Ok(Expr::Suffix( "blah".into(), - Suffix::Arglist(vec![1.into(), 2.into()]))) + Suffix::Arglist(vec![1.into(), 2.into()]) + )) ); //Calls with strings @@ -877,9 +884,10 @@ mod test { Expr::from_str("blah(\"foo\", 2)"), Ok(Expr::Suffix( "blah".into(), - Suffix::Arglist(vec!["foo".into(), 2.into()]))) + Suffix::Arglist(vec!["foo".into(), 2.into()]) + )) ); - } + } #[test] fn parse_return() { @@ -907,7 +915,10 @@ mod test { assert_eq!( Assignment::from_str("foo[45] = 7"), Ok(Assignment { - lvalue: Lvalue { name: String::from("foo"), subscripts: vec![Suffix::Subscript(45.into())] }, + lvalue: Lvalue { + name: String::from("foo"), + subscripts: vec![Suffix::Subscript(45.into())] + }, rvalue: Rvalue::Expr(7.into()), }) ); diff --git a/forge_core/src/new.pest b/forge_core/src/new.pest index 707c401..248a9d1 100644 --- a/forge_core/src/new.pest +++ b/forge_core/src/new.pest @@ -41,7 +41,7 @@ eq = { "==" } ne = { "!=" } lshift = { "<<" } rshift = { ">>" } -prefix = { "-" | "!" | "&" } +prefix = { "-" | "!" } operator = _{ add @@ -65,7 +65,7 @@ operator = _{ } expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* } -term = _{ number | name | "(" ~ expr ~ ")" } +term = _{ number | name | "(" ~ expr ~ ")" | "&" ~ lvalue } suffix = { modifier | arglist } modifier = _{ subscript | member }