Refactored lvalues into just another expr
This commit is contained in:
+19
-6
@@ -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)
|
||||
|
||||
@@ -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")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
})
|
||||
);
|
||||
|
||||
@@ -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 }
|
||||
|
||||
Reference in New Issue
Block a user