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,
}
// 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<Suffix>)
}
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<String> for Lvalue {
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 {
fn from(expr: BoxExpr) -> Self {
*(expr.0)
+18 -7
View File
@@ -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")))
}
}
}
}
+30 -31
View File
@@ -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())
})
);
+3 -4
View File
@@ -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 }