More refactoring and addresses working

This commit is contained in:
2023-08-04 21:38:09 -05:00
parent 3b612114f5
commit 63d63a1f68
4 changed files with 171 additions and 118 deletions
+12 -11
View File
@@ -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
View File
@@ -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")
)
}
}
+93 -82
View File
@@ -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()),
})
);
+2 -2
View File
@@ -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 }