From c6aea2f78f9d607703ce86b9482bc59438cc3b94 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Sun, 13 Aug 2023 23:55:49 -0500 Subject: [PATCH] Refactored lvalues into just another expr --- forge_core/src/ast.rs | 25 ++++++++++---- forge_core/src/compiler.rs | 25 ++++++++++---- forge_core/src/forge_parser.rs | 61 +++++++++++++++++----------------- forge_core/src/new.pest | 7 ++-- 4 files changed, 70 insertions(+), 48 deletions(-) diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index f278f6a..006dbda 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -78,21 +78,28 @@ pub struct Assignment { pub rvalue: Rvalue, } +// An lvalue is just a tag on an expr. Any expr parses just fine as an lvalue... not all exprs +// will compile as lvalues. But this saves us essentially having to define the expr grammar twice: +// in the compiler we can tell whether it makes sense for a given lvalue to compile into code that +// yields an address or if it can only yield a value. #[derive(PartialEq, Clone, Debug)] -pub enum Lvalue { - Expr(BoxExpr), - Name(String, Vec) -} +pub struct Lvalue(pub BoxExpr); impl From<&str> for Lvalue { fn from(name: &str) -> Self { - Self::Name(String::from(name), vec![]) + Self(name.into()) } } impl From for Lvalue { fn from(name: String) -> Self { - Self::Name(name, vec![]) + Self(name.into()) + } +} + +impl From for Lvalue { + fn from(value: Expr) -> Self { + Self(value.into()) } } @@ -195,6 +202,12 @@ impl From<&str> for BoxExpr { } } +impl From for BoxExpr { + fn from(value: String) -> Self { + Expr::Name(value).into() + } +} + impl From for Expr { fn from(expr: BoxExpr) -> Self { *(expr.0) diff --git a/forge_core/src/compiler.rs b/forge_core/src/compiler.rs index 0c8fbcb..26dccb2 100644 --- a/forge_core/src/compiler.rs +++ b/forge_core/src/compiler.rs @@ -317,12 +317,19 @@ impl Compilable for Lvalue { let global_scope = &state.global_scope; let mut sig = sig.expect("lvalue outside a function"); - match self { - Self::Name(name, subscripts) => { - if !subscripts.is_empty() { - todo!("Arrays and structs aren't implemented yet") - } + match *(self.0.0) { + // A bunch of different things that aren't allowed + Expr::Number(_) | + Expr::Neg(_) | + Expr::Not(_) | + Expr::Address(_) | + Expr::Call(_, _) | + Expr::Infix(_, _, _) => { + Err(CompileError(0, 0, String::from("Not a valid lvalue"))) + } + // Names we look up and leave the address on the stack: + Expr::Name(name) => { if let Some(var) = lookup(&name, global_scope, &sig.local_scope) { match var { Variable::Literal(_) | Variable::DirectLabel(_) => { @@ -350,10 +357,14 @@ impl Compilable for Lvalue { Err(CompileError(0, 0, format!("Unknown name {}", name))) } } - Self::Expr(BoxExpr(expr)) => { - // Just compile the expression and that's the address to write to + // Derefs are just evaluating the expr and leaving its value (an address) on the stack + Expr::Deref(BoxExpr(expr)) => { (*expr).process(state, Some(sig)) } + Expr::Subscript(_, _) | + Expr::Member(_, _) => { + Err(CompileError(0, 0, String::from("Arrays and structs are not yet supported"))) + } } } } diff --git a/forge_core/src/forge_parser.rs b/forge_core/src/forge_parser.rs index 410208b..0648c80 100644 --- a/forge_core/src/forge_parser.rs +++ b/forge_core/src/forge_parser.rs @@ -1,4 +1,4 @@ -use pest::pratt_parser::{Op, PrattParser}; +use pest::pratt_parser::PrattParser; use pest::Parser; #[derive(Parser)] @@ -322,7 +322,7 @@ impl AstNode for Assignment { const RULE: Rule = Rule::assignment; fn from_pair(pair: Pair) -> Self { let mut pairs = pair.into_inner(); - let lvalue = Lvalue::from_pair(pairs.next().unwrap()); + let lvalue = Expr::from_pair(pairs.next().unwrap()).into(); let rvalue = Rvalue::from_pair(pairs.next().unwrap()); Self { lvalue, rvalue } } @@ -330,26 +330,26 @@ impl AstNode for Assignment { /////////////////////////////////////////////////////////////////////////////////////////// -impl AstNode for Lvalue { - const RULE: Rule = Rule::lvalue; - fn from_pair(pair: Pair) -> Self { - let mut pairs = pair.into_inner(); - let first = pairs.next().unwrap(); - if first.as_rule() == Rule::expr { - Self::Expr(Expr::from_pair(first).into()) - } else { - let name = String::from(first.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(p.first_as_string()), - _ => unreachable!(), - }) - .collect(); - Self::Name(name, subscripts) - } - } -} +// impl AstNode for Lvalue { +// const RULE: Rule = Rule::lvalue; +// fn from_pair(pair: Pair) -> Self { +// let mut pairs = pair.into_inner(); +// let first = pairs.next().unwrap(); +// if first.as_rule() == Rule::expr { +// Self::Expr(Expr::from_pair(first).into()) +// } else { +// let name = String::from(first.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(p.first_as_string()), +// _ => unreachable!(), +// }) +// .collect(); +// Self::Name(name, subscripts) +// } +// } +// } /////////////////////////////////////////////////////////////////////////////////////////// @@ -460,7 +460,6 @@ impl AstNode for Expr { 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())) @@ -468,6 +467,7 @@ impl AstNode for Expr { "-" => Expr::Neg(expr.into()), "!" => Expr::Not(expr.into()), "*" => Expr::Deref(expr.into()), + "&" => Expr::Address(expr.into()), _ => unreachable!(), }) .map_postfix(|expr, suffix| match suffix.as_rule() { @@ -735,7 +735,6 @@ mod test { fn parse_exprs() { use Expr::Infix; use Operator::*; - use Suffix::*; // A very, very basic expression assert_eq!(Expr::from_str("23"), Ok(Expr::Number(23))); @@ -851,7 +850,7 @@ mod test { // Addresses assert_eq!( Expr::from_str("&foo.bar"), - Ok(Expr::Address(Lvalue::Name("foo".into(), vec![Suffix::Member("bar".into())]))) + Ok(Expr::Address(Expr::Member("foo".into(), "bar".into()).into())) ); assert_eq!( @@ -863,12 +862,12 @@ mod test { )) ); - // This is godawful but legal _as long as it parses like this._ The arglist 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" + // This is an example of a thing that will parse but not compile. This parses as an address + // of a call, which doesn't make sense, but because Expr::Address contains an Lvalue the + // compiler can detect this and error at that stage. assert_eq!( Expr::from_str("&foo()"), - Ok(Expr::Call(Expr::Address("foo".into()).into(), vec![])) + Ok(Expr::Address(Expr::Call("foo".into(), vec![]).into())) ); // Dereferencing @@ -932,7 +931,7 @@ mod test { assert_eq!( Assignment::from_str("foo[45] = 7"), Ok(Assignment { - lvalue: Lvalue::Name("foo".into(), vec![Suffix::Subscript(45.into())]), + lvalue: Expr::Subscript("foo".into(), 45.into()).into(), rvalue: Rvalue::Expr(7.into()), }) ); @@ -940,7 +939,7 @@ mod test { assert_eq!( Assignment::from_str("*foo = 12"), Ok(Assignment { - lvalue: Lvalue::Expr("foo".into()), + lvalue: Expr::Deref("foo".into()).into(), rvalue: Rvalue::Expr(12.into()) }) ); diff --git a/forge_core/src/new.pest b/forge_core/src/new.pest index d06ed32..fe6fb04 100644 --- a/forge_core/src/new.pest +++ b/forge_core/src/new.pest @@ -19,8 +19,7 @@ escape = @{ "\\" ~ ("t" | "r" | "n" | "0" | "\\" | "\"") } string_inner = ${ !("\"" | "\\") ~ ANY | escape } string = ${ "\"" ~ string_inner* ~ "\"" } -assignment = { lvalue ~ "=" ~ rvalue } -lvalue = { (name ~ (modifier)*) | ("*" ~ expr) } +assignment = { expr ~ "=" ~ rvalue } rvalue = { expr | string } add = { "+" } @@ -41,7 +40,7 @@ eq = { "==" } ne = { "!=" } lshift = { "<<" } rshift = { ">>" } -prefix = { "*" | "-" | "!" } +prefix = { "*" | "-" | "!" | "&" } operator = _{ add @@ -65,7 +64,7 @@ operator = _{ } expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* } -term = _{ number | name | "(" ~ expr ~ ")" | "&" ~ lvalue } +term = _{ number | name | "(" ~ expr ~ ")" } suffix = _{ modifier | arglist } modifier = _{ subscript | member }