More refactoring and addresses working
This commit is contained in:
+12
-11
@@ -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<String> 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)]
|
||||
|
||||
+64
-23
@@ -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<i32, CompileError> {
|
||||
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")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
})
|
||||
);
|
||||
|
||||
@@ -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 }
|
||||
|
||||
Reference in New Issue
Block a user