Refactored lvalues into just another expr

This commit is contained in:
2023-08-13 23:55:49 -05:00
parent 1de091f269
commit c6aea2f78f
4 changed files with 70 additions and 48 deletions
+19 -6
View File
@@ -78,21 +78,28 @@ pub struct Assignment {
pub rvalue: Rvalue, 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)] #[derive(PartialEq, Clone, Debug)]
pub enum Lvalue { pub struct Lvalue(pub BoxExpr);
Expr(BoxExpr),
Name(String, Vec<Suffix>)
}
impl From<&str> for Lvalue { impl From<&str> for Lvalue {
fn from(name: &str) -> Self { fn from(name: &str) -> Self {
Self::Name(String::from(name), vec![]) Self(name.into())
} }
} }
impl From<String> for Lvalue { impl From<String> for Lvalue {
fn from(name: String) -> Self { fn from(name: String) -> Self {
Self::Name(name, vec![]) Self(name.into())
}
}
impl From<Expr> for Lvalue {
fn from(value: Expr) -> Self {
Self(value.into())
} }
} }
@@ -195,6 +202,12 @@ impl From<&str> for BoxExpr {
} }
} }
impl From<String> for BoxExpr {
fn from(value: String) -> Self {
Expr::Name(value).into()
}
}
impl From<BoxExpr> for Expr { impl From<BoxExpr> for Expr {
fn from(expr: BoxExpr) -> Self { fn from(expr: BoxExpr) -> Self {
*(expr.0) *(expr.0)
+17 -6
View File
@@ -317,12 +317,19 @@ impl Compilable for Lvalue {
let global_scope = &state.global_scope; let global_scope = &state.global_scope;
let mut sig = sig.expect("lvalue outside a function"); let mut sig = sig.expect("lvalue outside a function");
match self { match *(self.0.0) {
Self::Name(name, subscripts) => { // A bunch of different things that aren't allowed
if !subscripts.is_empty() { Expr::Number(_) |
todo!("Arrays and structs aren't implemented yet") 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) { if let Some(var) = lookup(&name, global_scope, &sig.local_scope) {
match var { match var {
Variable::Literal(_) | Variable::DirectLabel(_) => { Variable::Literal(_) | Variable::DirectLabel(_) => {
@@ -350,10 +357,14 @@ impl Compilable for Lvalue {
Err(CompileError(0, 0, format!("Unknown name {}", name))) Err(CompileError(0, 0, format!("Unknown name {}", name)))
} }
} }
Self::Expr(BoxExpr(expr)) => { // Derefs are just evaluating the expr and leaving its value (an address) on the stack
// Just compile the expression and that's the address to write to Expr::Deref(BoxExpr(expr)) => {
(*expr).process(state, Some(sig)) (*expr).process(state, Some(sig))
} }
Expr::Subscript(_, _) |
Expr::Member(_, _) => {
Err(CompileError(0, 0, String::from("Arrays and structs are not yet supported")))
}
} }
} }
} }
+30 -31
View File
@@ -1,4 +1,4 @@
use pest::pratt_parser::{Op, PrattParser}; use pest::pratt_parser::PrattParser;
use pest::Parser; use pest::Parser;
#[derive(Parser)] #[derive(Parser)]
@@ -322,7 +322,7 @@ impl AstNode for Assignment {
const RULE: Rule = Rule::assignment; const RULE: Rule = Rule::assignment;
fn from_pair(pair: Pair) -> Self { fn from_pair(pair: Pair) -> Self {
let mut pairs = pair.into_inner(); 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()); let rvalue = Rvalue::from_pair(pairs.next().unwrap());
Self { lvalue, rvalue } Self { lvalue, rvalue }
} }
@@ -330,26 +330,26 @@ impl AstNode for Assignment {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Lvalue { // impl AstNode for Lvalue {
const RULE: Rule = Rule::lvalue; // const RULE: Rule = Rule::lvalue;
fn from_pair(pair: Pair) -> Self { // fn from_pair(pair: Pair) -> Self {
let mut pairs = pair.into_inner(); // let mut pairs = pair.into_inner();
let first = pairs.next().unwrap(); // let first = pairs.next().unwrap();
if first.as_rule() == Rule::expr { // if first.as_rule() == Rule::expr {
Self::Expr(Expr::from_pair(first).into()) // Self::Expr(Expr::from_pair(first).into())
} else { // } else {
let name = String::from(first.as_str()); // let name = String::from(first.as_str());
let subscripts: Vec<_> = pairs // let subscripts: Vec<_> = pairs
.map(|p| match p.as_rule() { // .map(|p| match p.as_rule() {
Rule::subscript => Suffix::Subscript(Expr::from_pair(p.first()).into()), // Rule::subscript => Suffix::Subscript(Expr::from_pair(p.first()).into()),
Rule::member => Suffix::Member(p.first_as_string()), // Rule::member => Suffix::Member(p.first_as_string()),
_ => unreachable!(), // _ => unreachable!(),
}) // })
.collect(); // .collect();
Self::Name(name, subscripts) // Self::Name(name, subscripts)
} // }
} // }
} // }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@@ -460,7 +460,6 @@ impl AstNode for Expr {
Rule::number => Expr::Number(term.into_number()), Rule::number => Expr::Number(term.into_number()),
Rule::name => Expr::Name(String::from(term.as_str())), Rule::name => Expr::Name(String::from(term.as_str())),
Rule::expr => Expr::from_pair(term), Rule::expr => Expr::from_pair(term),
Rule::lvalue => Expr::Address(Lvalue::from_pair(term)),
_ => unreachable!(), _ => unreachable!(),
}) })
.map_infix(|lhs, op, rhs| Expr::Infix(lhs.into(), Operator::from_pair(op), rhs.into())) .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::Neg(expr.into()),
"!" => Expr::Not(expr.into()), "!" => Expr::Not(expr.into()),
"*" => Expr::Deref(expr.into()), "*" => Expr::Deref(expr.into()),
"&" => Expr::Address(expr.into()),
_ => unreachable!(), _ => unreachable!(),
}) })
.map_postfix(|expr, suffix| match suffix.as_rule() { .map_postfix(|expr, suffix| match suffix.as_rule() {
@@ -735,7 +735,6 @@ mod test {
fn parse_exprs() { fn parse_exprs() {
use Expr::Infix; use Expr::Infix;
use Operator::*; use Operator::*;
use Suffix::*;
// A very, very basic expression // 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)));
@@ -851,7 +850,7 @@ mod test {
// Addresses // Addresses
assert_eq!( assert_eq!(
Expr::from_str("&foo.bar"), 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!( 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 // This is an example of a thing that will parse but not compile. This parses as an address
// on the "&foo" expression as a whole, so, it "calls" the address of foo. Essentially: // of a call, which doesn't make sense, but because Expr::Address contains an Lvalue the
// "push foo; call" rather than "loadw foo; call" // compiler can detect this and error at that stage.
assert_eq!( assert_eq!(
Expr::from_str("&foo()"), Expr::from_str("&foo()"),
Ok(Expr::Call(Expr::Address("foo".into()).into(), vec![])) Ok(Expr::Address(Expr::Call("foo".into(), vec![]).into()))
); );
// Dereferencing // Dereferencing
@@ -932,7 +931,7 @@ mod test {
assert_eq!( assert_eq!(
Assignment::from_str("foo[45] = 7"), Assignment::from_str("foo[45] = 7"),
Ok(Assignment { 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()), rvalue: Rvalue::Expr(7.into()),
}) })
); );
@@ -940,7 +939,7 @@ mod test {
assert_eq!( assert_eq!(
Assignment::from_str("*foo = 12"), Assignment::from_str("*foo = 12"),
Ok(Assignment { Ok(Assignment {
lvalue: Lvalue::Expr("foo".into()), lvalue: Expr::Deref("foo".into()).into(),
rvalue: Rvalue::Expr(12.into()) rvalue: Rvalue::Expr(12.into())
}) })
); );
+3 -4
View File
@@ -19,8 +19,7 @@ escape = @{ "\\" ~ ("t" | "r" | "n" | "0" | "\\" | "\"") }
string_inner = ${ !("\"" | "\\") ~ ANY | escape } string_inner = ${ !("\"" | "\\") ~ ANY | escape }
string = ${ "\"" ~ string_inner* ~ "\"" } string = ${ "\"" ~ string_inner* ~ "\"" }
assignment = { lvalue ~ "=" ~ rvalue } assignment = { expr ~ "=" ~ rvalue }
lvalue = { (name ~ (modifier)*) | ("*" ~ expr) }
rvalue = { expr | string } rvalue = { expr | string }
add = { "+" } add = { "+" }
@@ -41,7 +40,7 @@ eq = { "==" }
ne = { "!=" } ne = { "!=" }
lshift = { "<<" } lshift = { "<<" }
rshift = { ">>" } rshift = { ">>" }
prefix = { "*" | "-" | "!" } prefix = { "*" | "-" | "!" | "&" }
operator = _{ operator = _{
add add
@@ -65,7 +64,7 @@ operator = _{
} }
expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* } expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* }
term = _{ number | name | "(" ~ expr ~ ")" | "&" ~ lvalue } term = _{ number | name | "(" ~ expr ~ ")" }
suffix = _{ modifier | arglist } suffix = _{ modifier | arglist }
modifier = _{ subscript | member } modifier = _{ subscript | member }