Strings are just another kind of expr
This commit is contained in:
+4
-21
@@ -75,7 +75,7 @@ pub struct Return(pub Option<Expr>);
|
|||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct Assignment {
|
pub struct Assignment {
|
||||||
pub lvalue: Lvalue,
|
pub lvalue: Lvalue,
|
||||||
pub rvalue: Rvalue,
|
pub rvalue: Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
// An lvalue is just a tag on an expr. Any expr parses just fine as an lvalue... not all exprs
|
// An lvalue is just a tag on an expr. Any expr parses just fine as an lvalue... not all exprs
|
||||||
@@ -103,18 +103,12 @@ impl From<Expr> for Lvalue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
|
||||||
pub enum Rvalue {
|
|
||||||
Expr(Expr),
|
|
||||||
String(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct VarDecl {
|
pub struct VarDecl {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub typename: Option<String>,
|
pub typename: Option<String>,
|
||||||
pub size: Option<Expr>,
|
pub size: Option<Expr>,
|
||||||
pub initial: Option<Rvalue>,
|
pub initial: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
@@ -174,10 +168,11 @@ pub enum Expr {
|
|||||||
Neg(BoxExpr),
|
Neg(BoxExpr),
|
||||||
Deref(BoxExpr),
|
Deref(BoxExpr),
|
||||||
Address(Lvalue),
|
Address(Lvalue),
|
||||||
Call(BoxExpr, Vec<Rvalue>),
|
Call(BoxExpr, Vec<Expr>),
|
||||||
Subscript(BoxExpr, BoxExpr),
|
Subscript(BoxExpr, BoxExpr),
|
||||||
Member(BoxExpr, String),
|
Member(BoxExpr, String),
|
||||||
Infix(BoxExpr, Operator, BoxExpr),
|
Infix(BoxExpr, Operator, BoxExpr),
|
||||||
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -225,15 +220,3 @@ impl From<&str> for Expr {
|
|||||||
Self::Name(String::from(value))
|
Self::Name(String::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i32> for Rvalue {
|
|
||||||
fn from(value: i32) -> Self {
|
|
||||||
Self::Expr(value.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for Rvalue {
|
|
||||||
fn from(value: &str) -> Self {
|
|
||||||
Self::String(value.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+13
-21
@@ -270,7 +270,7 @@ impl Compilable for Assignment {
|
|||||||
|
|
||||||
impl Compilable for VarDecl {
|
impl Compilable for VarDecl {
|
||||||
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
|
||||||
let mut sig = sig.expect("Var declaration outside function");
|
let sig = sig.expect("Var declaration outside function");
|
||||||
if self.typename.is_some() || self.size.is_some() {
|
if self.typename.is_some() || self.size.is_some() {
|
||||||
todo!("Structs and arrays are not yet supported")
|
todo!("Structs and arrays are not yet supported")
|
||||||
}
|
}
|
||||||
@@ -293,24 +293,6 @@ impl Compilable for VarDecl {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl Compilable for Rvalue {
|
|
||||||
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
|
|
||||||
let sig = sig.expect("Assignment outside function");
|
|
||||||
// For a normal expr, eval and leave on the stack; for a string literal, add it to
|
|
||||||
// the str table and push the label's address
|
|
||||||
match self {
|
|
||||||
Rvalue::Expr(e) => e.process(state, Some(sig)),
|
|
||||||
Rvalue::String(string) => {
|
|
||||||
let label = state.add_string(&string);
|
|
||||||
sig.emit_arg("push", label);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/// Evaluate an lvalue and leave its address on the stack (ready to be consumed by storew)
|
/// Evaluate an lvalue and leave its address on the stack (ready to be consumed by storew)
|
||||||
impl Compilable for Lvalue {
|
impl Compilable for Lvalue {
|
||||||
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
|
||||||
@@ -324,7 +306,8 @@ impl Compilable for Lvalue {
|
|||||||
Expr::Not(_) |
|
Expr::Not(_) |
|
||||||
Expr::Address(_) |
|
Expr::Address(_) |
|
||||||
Expr::Call(_, _) |
|
Expr::Call(_, _) |
|
||||||
Expr::Infix(_, _, _) => {
|
Expr::Infix(_, _, _) |
|
||||||
|
Expr::String(_) => {
|
||||||
Err(CompileError(0, 0, String::from("Not a valid lvalue")))
|
Err(CompileError(0, 0, String::from("Not a valid lvalue")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,6 +427,11 @@ impl Compilable for Expr {
|
|||||||
sig.emit("loadw");
|
sig.emit("loadw");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Expr::String(string) => {
|
||||||
|
let label = state.add_string(&string);
|
||||||
|
sig.emit_arg("push", label);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Expr::Call(_, _) => todo!(),
|
Expr::Call(_, _) => todo!(),
|
||||||
Expr::Subscript(_, _) => todo!("Structs and arrays are not yen supported"),
|
Expr::Subscript(_, _) => todo!("Structs and arrays are not yen supported"),
|
||||||
Expr::Member(_, _) => todo!("Structs and arrays are not yen supported"),
|
Expr::Member(_, _) => todo!("Structs and arrays are not yen supported"),
|
||||||
@@ -558,7 +546,11 @@ pub fn eval_const(expr: Expr, scope: &Scope) -> Result<i32, CompileError> {
|
|||||||
let val = eval_const(*e.0, scope)?;
|
let val = eval_const(*e.0, scope)?;
|
||||||
Ok(if val != 0 { 0 } else { 1 })
|
Ok(if val != 0 { 0 } else { 1 })
|
||||||
}
|
}
|
||||||
Expr::Address(_) | Expr::Deref(_) => Err(CompileError(
|
// A note about Expr::String here: 'const foo="banana"' won't hit this point; it'll be
|
||||||
|
// (currently) parsed as a special case of const. The only things that will hit this are
|
||||||
|
// const expressions that include strings, like '"foo"[2]' or something. Those can't be
|
||||||
|
// (generally) calculated at compile time, so, they're an error.
|
||||||
|
Expr::Address(_) | Expr::Deref(_) | Expr::String(_) => Err(CompileError(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
String::from("Addresses are not known at compile time"),
|
String::from("Addresses are not known at compile time"),
|
||||||
|
|||||||
@@ -323,58 +323,20 @@ impl AstNode for Assignment {
|
|||||||
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 lvalue = Expr::from_pair(pairs.next().unwrap()).into();
|
let lvalue = Expr::from_pair(pairs.next().unwrap()).into();
|
||||||
let rvalue = Rvalue::from_pair(pairs.next().unwrap());
|
let rvalue = Expr::from_pair(pairs.next().unwrap());
|
||||||
Self { lvalue, rvalue }
|
Self { lvalue, rvalue }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// 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 Rvalue {
|
|
||||||
const RULE: Rule = Rule::rvalue;
|
|
||||||
|
|
||||||
fn from_pair(pair: Pair) -> Self {
|
|
||||||
let pair = pair.first();
|
|
||||||
match pair.as_rule() {
|
|
||||||
Rule::string => Self::String(pair.into_quoted_string()),
|
|
||||||
Rule::expr => Self::Expr(Expr::from_pair(pair)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
impl AstNode for VarDecl {
|
impl AstNode for VarDecl {
|
||||||
const RULE: Rule = Rule::var_decl;
|
const RULE: Rule = Rule::var_decl;
|
||||||
fn from_pair(pair: Pair) -> Self {
|
fn from_pair(pair: Pair) -> Self {
|
||||||
let mut inner = pair.into_inner();
|
let mut inner = pair.into_inner();
|
||||||
let name = String::from(inner.next().unwrap().as_str());
|
let name = String::from(inner.next().unwrap().as_str());
|
||||||
let Varinfo { typename, size } = Varinfo::from_pair(inner.next().unwrap());
|
let Varinfo { typename, size } = Varinfo::from_pair(inner.next().unwrap());
|
||||||
let initial = inner.next().map(Rvalue::from_pair);
|
let initial = inner.next().map(Expr::from_pair);
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
typename,
|
typename,
|
||||||
@@ -460,6 +422,7 @@ impl AstNode for Expr {
|
|||||||
Rule::number => Expr::Number(term.into_number()),
|
Rule::number => Expr::Number(term.into_number()),
|
||||||
Rule::name => Expr::Name(String::from(term.as_str())),
|
Rule::name => Expr::Name(String::from(term.as_str())),
|
||||||
Rule::expr => Expr::from_pair(term),
|
Rule::expr => Expr::from_pair(term),
|
||||||
|
Rule::string => Self::String(term.into_quoted_string()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
.map_infix(|lhs, op, rhs| Expr::Infix(lhs.into(), Operator::from_pair(op), rhs.into()))
|
.map_infix(|lhs, op, rhs| Expr::Infix(lhs.into(), Operator::from_pair(op), rhs.into()))
|
||||||
@@ -473,7 +436,7 @@ impl AstNode for Expr {
|
|||||||
.map_postfix(|expr, suffix| match suffix.as_rule() {
|
.map_postfix(|expr, suffix| match suffix.as_rule() {
|
||||||
Rule::arglist => Expr::Call(
|
Rule::arglist => Expr::Call(
|
||||||
expr.into(),
|
expr.into(),
|
||||||
suffix.into_inner().map(Rvalue::from_pair).collect(),
|
suffix.into_inner().map(Expr::from_pair).collect(),
|
||||||
),
|
),
|
||||||
Rule::subscript => {
|
Rule::subscript => {
|
||||||
Expr::Subscript(expr.into(), Expr::from_pair(suffix.first()).into())
|
Expr::Subscript(expr.into(), Expr::from_pair(suffix.first()).into())
|
||||||
@@ -901,7 +864,7 @@ mod test {
|
|||||||
//Calls with strings
|
//Calls with strings
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::from_str("blah(\"foo\", 2)"),
|
Expr::from_str("blah(\"foo\", 2)"),
|
||||||
Ok(Expr::Call("blah".into(), vec!["foo".into(), 2.into()]))
|
Ok(Expr::Call("blah".into(), vec![Expr::String("foo".into()), 2.into()]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,7 +887,7 @@ mod test {
|
|||||||
Statement::from_str("foo = 7;"),
|
Statement::from_str("foo = 7;"),
|
||||||
Ok(Statement::Assignment(Assignment {
|
Ok(Statement::Assignment(Assignment {
|
||||||
lvalue: "foo".into(),
|
lvalue: "foo".into(),
|
||||||
rvalue: Rvalue::Expr(7.into()),
|
rvalue: 7.into(),
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -932,7 +895,7 @@ mod test {
|
|||||||
Assignment::from_str("foo[45] = 7"),
|
Assignment::from_str("foo[45] = 7"),
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
lvalue: Expr::Subscript("foo".into(), 45.into()).into(),
|
lvalue: Expr::Subscript("foo".into(), 45.into()).into(),
|
||||||
rvalue: Rvalue::Expr(7.into()),
|
rvalue: 7.into(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -940,7 +903,7 @@ mod test {
|
|||||||
Assignment::from_str("*foo = 12"),
|
Assignment::from_str("*foo = 12"),
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
lvalue: Expr::Deref("foo".into()).into(),
|
lvalue: Expr::Deref("foo".into()).into(),
|
||||||
rvalue: Rvalue::Expr(12.into())
|
rvalue: 12.into()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ escape = @{ "\\" ~ ("t" | "r" | "n" | "0" | "\\" | "\"") }
|
|||||||
string_inner = ${ !("\"" | "\\") ~ ANY | escape }
|
string_inner = ${ !("\"" | "\\") ~ ANY | escape }
|
||||||
string = ${ "\"" ~ string_inner* ~ "\"" }
|
string = ${ "\"" ~ string_inner* ~ "\"" }
|
||||||
|
|
||||||
assignment = { expr ~ "=" ~ rvalue }
|
assignment = { expr ~ "=" ~ expr }
|
||||||
rvalue = { expr | string }
|
|
||||||
|
|
||||||
add = { "+" }
|
add = { "+" }
|
||||||
sub = { "-" }
|
sub = { "-" }
|
||||||
@@ -64,12 +63,12 @@ operator = _{
|
|||||||
}
|
}
|
||||||
|
|
||||||
expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* }
|
expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* }
|
||||||
term = _{ number | name | "(" ~ expr ~ ")" }
|
term = _{ number | name | "(" ~ expr ~ ")" | string }
|
||||||
|
|
||||||
suffix = _{ modifier | arglist }
|
suffix = _{ modifier | arglist }
|
||||||
modifier = _{ subscript | member }
|
modifier = _{ subscript | member }
|
||||||
subscript = { "[" ~ expr ~ "]" }
|
subscript = { "[" ~ expr ~ "]" }
|
||||||
arglist = { "(" ~ (rvalue ~ ("," ~ rvalue)*)? ~ ")" }
|
arglist = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
|
||||||
member = { "." ~ name }
|
member = { "." ~ name }
|
||||||
|
|
||||||
statement = { asm | ((return_stmt | var_decl | assignment | expr) ~ ";") | conditional | while_loop | repeat_loop }
|
statement = { asm | ((return_stmt | var_decl | assignment | expr) ~ ";") | conditional | while_loop | repeat_loop }
|
||||||
@@ -91,11 +90,11 @@ return_stmt = { "return" ~ expr? }
|
|||||||
conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? }
|
conditional = { "if" ~ "(" ~ expr ~ ")" ~ block ~ ("else" ~ block)? }
|
||||||
while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block }
|
while_loop = { "while" ~ "(" ~ expr ~ ")" ~ block }
|
||||||
repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block }
|
repeat_loop = { "repeat" ~ "(" ~ expr ~ ")" ~ name? ~ block }
|
||||||
var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ rvalue)? }
|
var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ expr)? }
|
||||||
global = { "global" ~ name ~ varinfo ~ ";" }
|
global = { "global" ~ name ~ varinfo ~ ";" }
|
||||||
typename = { ":" ~ name }
|
typename = { ":" ~ name }
|
||||||
size = { "[" ~ expr ~ "]" }
|
size = { "[" ~ expr ~ "]" }
|
||||||
const_decl = { "const" ~ name ~ "=" ~ (expr | string) ~ ";" }
|
const_decl = { "const" ~ name ~ "=" ~ (string | expr) ~ ";" }
|
||||||
|
|
||||||
struct_decl = { "struct" ~ name ~ "{" ~ members ~ "}" }
|
struct_decl = { "struct" ~ name ~ "{" ~ members ~ "}" }
|
||||||
member_decl = { name ~ varinfo }
|
member_decl = { name ~ varinfo }
|
||||||
|
|||||||
Reference in New Issue
Block a user