Prefix dereferences as lvalues
This commit is contained in:
+5
-11
@@ -79,26 +79,20 @@ pub struct Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct Lvalue {
|
pub enum Lvalue {
|
||||||
pub name: String,
|
Expr(BoxExpr),
|
||||||
pub subscripts: Vec<Suffix>,
|
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 {
|
Self::Name(String::from(name), vec![])
|
||||||
name: String::from(name),
|
|
||||||
subscripts: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Lvalue {
|
impl From<String> for Lvalue {
|
||||||
fn from(name: String) -> Self {
|
fn from(name: String) -> Self {
|
||||||
Self {
|
Self::Name(name, vec![])
|
||||||
name,
|
|
||||||
subscripts: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -317,16 +317,18 @@ 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");
|
||||||
|
|
||||||
if !self.subscripts.is_empty() {
|
match self {
|
||||||
|
Self::Name(name, subscripts) => {
|
||||||
|
if !subscripts.is_empty() {
|
||||||
todo!("Arrays and structs aren't implemented yet")
|
todo!("Arrays and structs aren't implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(var) = lookup(&self.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(_) => {
|
||||||
// Direct labels are (probably) functions, the important part is the
|
// Direct labels are (probably) functions, the important part is the
|
||||||
// label itself, which we can't alter, so, error:
|
// label itself, which we can't alter, so, error:
|
||||||
Err(CompileError(0, 0, format!("Invalid lvalue {}", self.name)))
|
Err(CompileError(0, 0, format!("Invalid lvalue {}", name)))
|
||||||
}
|
}
|
||||||
Variable::IndirectLabel(label) => {
|
Variable::IndirectLabel(label) => {
|
||||||
// Indirect labels are variables, the label is where the data is stored,
|
// Indirect labels are variables, the label is where the data is stored,
|
||||||
@@ -345,7 +347,13 @@ impl Compilable for Lvalue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError(0, 0, format!("Unknown name {}", self.name)))
|
Err(CompileError(0, 0, format!("Unknown name {}", name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Expr(BoxExpr(expr)) => {
|
||||||
|
// Just compile the expression and that's the address to write to
|
||||||
|
(*expr).process(state, Some(sig))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -748,4 +756,28 @@ mod test {
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_derefs() {
|
||||||
|
let mut state = State::default();
|
||||||
|
parse("fn blah() { var x = 3; *1000 = *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", // Now we're compiling *x, so load x's value, which is 3
|
||||||
|
"loadw", // Then load the value at 3
|
||||||
|
"push 1000", // Push the addr 1000, for the lvalue
|
||||||
|
"storew" // Store whatever's at 3 to 1000
|
||||||
|
]
|
||||||
|
.join("\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,7 +334,11 @@ 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 name = String::from(pairs.next().unwrap().as_str());
|
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
|
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()),
|
||||||
@@ -342,7 +346,8 @@ impl AstNode for Lvalue {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Self { name, subscripts }
|
Self::Name(name, subscripts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,10 +851,7 @@ mod test {
|
|||||||
// Addresses
|
// Addresses
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::from_str("&foo.bar"),
|
Expr::from_str("&foo.bar"),
|
||||||
Ok(Expr::Address(Lvalue {
|
Ok(Expr::Address(Lvalue::Name("foo".into(), vec![Suffix::Member("bar".into())])))
|
||||||
name: "foo".into(),
|
|
||||||
subscripts: vec![Suffix::Member("bar".into())]
|
|
||||||
}))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -930,13 +932,18 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
Assignment::from_str("foo[45] = 7"),
|
Assignment::from_str("foo[45] = 7"),
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
lvalue: Lvalue {
|
lvalue: Lvalue::Name("foo".into(), vec![Suffix::Subscript(45.into())]),
|
||||||
name: String::from("foo"),
|
|
||||||
subscripts: vec![Suffix::Subscript(45.into())]
|
|
||||||
},
|
|
||||||
rvalue: Rvalue::Expr(7.into()),
|
rvalue: Rvalue::Expr(7.into()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Assignment::from_str("*foo = 12"),
|
||||||
|
Ok(Assignment {
|
||||||
|
lvalue: Lvalue::Expr("foo".into()),
|
||||||
|
rvalue: Rvalue::Expr(12.into())
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ string_inner = ${ !("\"" | "\\") ~ ANY | escape }
|
|||||||
string = ${ "\"" ~ string_inner* ~ "\"" }
|
string = ${ "\"" ~ string_inner* ~ "\"" }
|
||||||
|
|
||||||
assignment = { lvalue ~ "=" ~ rvalue }
|
assignment = { lvalue ~ "=" ~ rvalue }
|
||||||
lvalue = { name ~ (modifier)* }
|
lvalue = { (name ~ (modifier)*) | ("*" ~ expr) }
|
||||||
rvalue = { expr | string }
|
rvalue = { expr | string }
|
||||||
|
|
||||||
add = { "+" }
|
add = { "+" }
|
||||||
|
|||||||
Reference in New Issue
Block a user