More new grammar stuff
This commit is contained in:
+23
-77
@@ -79,9 +79,21 @@ pub struct Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub enum Lvalue {
|
pub struct Lvalue {
|
||||||
ArrayRef(String, Expr),
|
pub name: String,
|
||||||
Name(String),
|
pub subscripts: Vec<Suffix>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Lvalue {
|
||||||
|
fn from(name: &str) -> Self {
|
||||||
|
Self { name: String::from(name), subscripts: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Lvalue {
|
||||||
|
fn from(name: String) -> Self {
|
||||||
|
Self { name, subscripts: vec![] }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
@@ -95,7 +107,7 @@ 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<Expr>,
|
pub initial: Option<Rvalue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
@@ -157,87 +169,21 @@ pub enum Suffix {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Val(Val),
|
|
||||||
Prefix(Prefix, BoxExpr),
|
|
||||||
Suffix(BoxExpr, Suffix),
|
|
||||||
Infix(BoxExpr, Operator, BoxExpr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[derive(PartialEq, Clone, Debug)]
|
|
||||||
// pub struct Expr {
|
|
||||||
// pub lhs: Val,
|
|
||||||
// pub prefix: Vec<Prefix>,
|
|
||||||
// pub suffix: Vec<Suffix>,
|
|
||||||
// pub op: Option<Operator>,
|
|
||||||
// pub rhs: Option<BoxExpr>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
|
||||||
pub enum Val {
|
|
||||||
Number(i32),
|
Number(i32),
|
||||||
Name(String),
|
Name(String),
|
||||||
Expr(BoxExpr),
|
Expr(BoxExpr),
|
||||||
}
|
Prefix(Prefix, BoxExpr),
|
||||||
|
Suffix(BoxExpr, Suffix),
|
||||||
// impl Val {
|
Infix(BoxExpr, Operator, BoxExpr)
|
||||||
// pub fn is_simple(&self) -> bool {
|
|
||||||
// if let Self::Expr(expr, pre, suf) = &self {
|
|
||||||
// pre.is_empty() && suf.is_empty() && expr.0.op.is_none()
|
|
||||||
// } else {
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn inner_expr(self) -> Option<Expr> {
|
|
||||||
// if let Self::Expr(expr, _, _) = self {
|
|
||||||
// Some(expr.into())
|
|
||||||
// } else { None }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl From<i32> for Val {
|
|
||||||
fn from(val: i32) -> Self {
|
|
||||||
Self::Number(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for Val {
|
|
||||||
fn from(s: &str) -> Self {
|
|
||||||
Self::Name(String::from(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Expr> for Val {
|
|
||||||
fn from(value: Expr) -> Self {
|
|
||||||
Self::Expr(value.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<BoxExpr> for Val {
|
|
||||||
fn from(value: BoxExpr) -> Self {
|
|
||||||
Self::Expr(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Val> for BoxExpr {
|
|
||||||
fn from(value: Val) -> Self {
|
|
||||||
Self::from(Expr::from(value))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct BoxExpr(pub Box<Expr>);
|
pub struct BoxExpr(pub Box<Expr>);
|
||||||
|
|
||||||
impl From<Val> for Expr {
|
|
||||||
fn from(value: Val) -> Self {
|
|
||||||
Self::Val(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i32> for BoxExpr {
|
impl From<i32> for BoxExpr {
|
||||||
fn from(val: i32) -> Self {
|
fn from(val: i32) -> Self {
|
||||||
BoxExpr(Box::from(Expr::from(Val::from(val))))
|
BoxExpr(Box::from(Expr::Number(val)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +195,7 @@ impl From<Expr> for BoxExpr {
|
|||||||
|
|
||||||
impl From<&str> for BoxExpr {
|
impl From<&str> for BoxExpr {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
Expr::Val(Val::Name(String::from(value))).into()
|
Expr::Name(String::from(value)).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,13 +207,13 @@ impl From<BoxExpr> for Expr {
|
|||||||
|
|
||||||
impl From<i32> for Expr {
|
impl From<i32> for Expr {
|
||||||
fn from(value: i32) -> Self {
|
fn from(value: i32) -> Self {
|
||||||
Self::Val(Val::Number(value))
|
Self::Number(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Expr {
|
impl From<&str> for Expr {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
Self::Val(Val::Name(String::from(value)))
|
Self::Name(String::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+233
-229
@@ -221,12 +221,11 @@ impl Compilable for Function {
|
|||||||
Statement::Return(_) => {}
|
Statement::Return(_) => {}
|
||||||
Statement::Assignment(assign) => assign.process(state, Some(&mut sig))?,
|
Statement::Assignment(assign) => assign.process(state, Some(&mut sig))?,
|
||||||
Statement::Expr(expr) => {
|
Statement::Expr(expr) => {
|
||||||
todo!();
|
expr.process(state, Some(&mut sig))?;
|
||||||
// expr.process(state, Some(&mut sig))?;
|
// Every expr leaves a single-word return value on the stack. In an rvalue this
|
||||||
// // Every expr leaves a single-word return value on the stack. In an rvalue this
|
// is useful but in a statement it's garbage (because nothing else is about to
|
||||||
// // is useful but in a statement it's garbage (because nothing else is about to
|
// pick it up) so, drop it:
|
||||||
// // pick it up) so, drop it:
|
sig.emit("pop")
|
||||||
// sig.emit("pop")
|
|
||||||
}
|
}
|
||||||
Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?,
|
Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?,
|
||||||
Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => {
|
Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => {
|
||||||
@@ -259,18 +258,8 @@ impl Compilable for Assignment {
|
|||||||
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
||||||
let Assignment { lvalue, rvalue } = self;
|
let Assignment { lvalue, rvalue } = self;
|
||||||
let sig = sig.expect("Assignment outside function");
|
let sig = sig.expect("Assignment outside function");
|
||||||
|
// First the value, then the address we'll storew it to
|
||||||
// For a normal expr, eval and leave on the stack; for a string literal, add it to
|
rvalue.process(state, Some(sig))?;
|
||||||
// the str table and push the label's address
|
|
||||||
// match rvalue {
|
|
||||||
// Rvalue::Expr(rvalue) => rvalue.process(state, Some(sig))?,
|
|
||||||
// Rvalue::String(string) => {
|
|
||||||
// let label = state.add_string(&string);
|
|
||||||
// sig.emit_arg("push", label);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Then process the lvalue and storew
|
|
||||||
lvalue.process(state, Some(sig))?;
|
lvalue.process(state, Some(sig))?;
|
||||||
sig.emit("storew");
|
sig.emit("storew");
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -281,25 +270,42 @@ impl Compilable for Assignment {
|
|||||||
|
|
||||||
impl Compilable for VarDecl {
|
impl Compilable for VarDecl {
|
||||||
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
||||||
todo!();
|
let mut sig = sig.expect("Var declaration outside function");
|
||||||
// let mut 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")
|
}
|
||||||
// }
|
if let Some(initial) = self.initial {
|
||||||
// if let Some(initial) = self.initial {
|
// If it's got an initial value, we have to compile that before we add
|
||||||
// // If it's got an initial value, we have to compile that before we add
|
// the name to scope, or else UB will ensue if it refers to itself:
|
||||||
// // the name to scope, or else UB will ensue if it refers to itself:
|
initial.process(state, Some(sig))?;
|
||||||
// initial.process(state, Some(sig))?;
|
// But then add it to scope and assign:
|
||||||
// // But then add it to scope and assign:
|
sig.add_local(&self.name)?;
|
||||||
// sig.add_local(&self.name)?;
|
// We'll just whip up an lvalue real quick...
|
||||||
// // We'll just whip up an lvalue real quick...
|
Lvalue::from(self.name).process(state, Some(sig))?;
|
||||||
// Lvalue::Name(self.name).process(state, Some(sig))?;
|
sig.emit("storew"); // And store the initial value there
|
||||||
// sig.emit("storew"); // And store the initial value there
|
} else {
|
||||||
// } else {
|
// Otherwise, just add it to scope and leave garbage in there:
|
||||||
// // Otherwise, just add it to scope and leave garbage in there:
|
sig.add_local(&self.name)?;
|
||||||
// sig.add_local(&self.name)?;
|
}
|
||||||
// }
|
Ok(())
|
||||||
// Ok(())
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl Compilable for Rvalue {
|
||||||
|
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,15 +316,15 @@ impl Compilable for Lvalue {
|
|||||||
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
||||||
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");
|
||||||
match self {
|
|
||||||
Lvalue::ArrayRef(_, _) => todo!("Arrays are not implemented yet"),
|
if !self.subscripts.is_empty() { todo!("Arrays and structs aren't implemented yet") }
|
||||||
Lvalue::Name(name) => {
|
|
||||||
if let Some(var) = lookup(&name, global_scope, &sig.local_scope) {
|
if let Some(var) = lookup(&self.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 {}", name)))
|
Err(CompileError(0, 0, format!("Invalid lvalue {}", self.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,
|
||||||
@@ -337,9 +343,7 @@ impl Compilable for Lvalue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError(0, 0, format!("Unknown name {}", name)))
|
Err(CompileError(0, 0, format!("Unknown name {}", self.name)))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,118 +354,125 @@ impl Compilable for Lvalue {
|
|||||||
/// This recursively evaluates a Node and leaves its value on the stack.
|
/// This recursively evaluates a Node and leaves its value on the stack.
|
||||||
impl Compilable for Expr {
|
impl Compilable for Expr {
|
||||||
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, sig: Option<&mut Signature>) -> Result<(), CompileError> {
|
||||||
todo!();
|
let mut sig = sig.expect("Non-const expression outside a function");
|
||||||
// let mut sig = sig.expect("Non-const expression outside a function");
|
let global_scope = &state.global_scope;
|
||||||
// let global_scope = &state.global_scope;
|
|
||||||
//
|
// First, a sanity check: try and eval_const this. If it's something incredibly basic
|
||||||
// // First, a sanity check: try and eval_const this. If it's something incredibly basic
|
// that just becomes an i32, then we don't need to do anything else:
|
||||||
// // that just becomes an i32, then we don't need to do anything else:
|
if let Ok(val) = eval_const(self.clone(), &state.global_scope) {
|
||||||
// if let Ok(val) = eval_const(self.clone(), &state.global_scope) {
|
sig.emit_arg("push", val);
|
||||||
// sig.emit_arg("push", val);
|
return Ok(());
|
||||||
// return Ok(());
|
}
|
||||||
// }
|
|
||||||
//
|
// Okay, looks like we need something that's in scope. Let's recurse:
|
||||||
// // Okay, looks like we need something that's in scope. Let's recurse:
|
match self {
|
||||||
// match self.val {
|
Expr::Number(n) => {
|
||||||
// Val::Number(n) => {
|
// Numbers are just pushed as literals
|
||||||
// // Numbers are just pushed as literals
|
sig.body.push(format!("push {}", n));
|
||||||
// sig.body.push(format!("push {}", n));
|
Ok(())
|
||||||
// Ok(())
|
}
|
||||||
// }
|
Expr::Name(name) => {
|
||||||
// Val::Name(name) => match lookup(&name, global_scope, &sig.local_scope) {
|
match lookup(&name, global_scope, &sig.local_scope) {
|
||||||
// // Names are treated differently depending on what they are
|
// Names are treated differently depending on what they are
|
||||||
// Some(Variable::Literal(val)) => {
|
Some(Variable::Literal(val)) => {
|
||||||
// // Names of constants are just that number
|
// Names of constants are just that number
|
||||||
// sig.emit_arg("push", *val);
|
sig.emit_arg("push", *val);
|
||||||
// Ok(())
|
Ok(())
|
||||||
// }
|
}
|
||||||
// Some(Variable::IndirectLabel(label)) => {
|
Some(Variable::IndirectLabel(label)) => {
|
||||||
// // Names pointing at labels are loaded (rvalue; for lvalues they aren't)
|
// Names pointing at labels are loaded (rvalue; for lvalues they aren't)
|
||||||
// // Indirect labels are the address of where the value is stored (a var, .db)
|
// Indirect labels are the address of where the value is stored (a var, .db)
|
||||||
// sig.emit_arg("loadw", label.clone());
|
sig.emit_arg("loadw", label.clone());
|
||||||
// Ok(())
|
Ok(())
|
||||||
// }
|
}
|
||||||
// Some(Variable::DirectLabel(label)) => {
|
Some(Variable::DirectLabel(label)) => {
|
||||||
// // Direct labels are like functions, the label itself is the value, so just
|
// Direct labels are like functions, the label itself is the value, so just
|
||||||
// // push it:
|
// push it:
|
||||||
// sig.emit_arg("push", label.clone());
|
sig.emit_arg("push", label.clone());
|
||||||
// Ok(())
|
Ok(())
|
||||||
// }
|
}
|
||||||
// Some(Variable::Local(offset)) => {
|
Some(Variable::Local(offset)) => {
|
||||||
// // Names of locals are added from the frame pointer
|
// Names of locals are added from the frame pointer
|
||||||
// let offset = *offset;
|
let offset = *offset;
|
||||||
// sig.emit("loadw frame");
|
sig.emit("loadw frame");
|
||||||
// if offset > 0 {
|
if offset > 0 {
|
||||||
// sig.emit_arg("add", offset);
|
sig.emit_arg("add", offset);
|
||||||
// sig.emit("loadw");
|
sig.emit("loadw");
|
||||||
// }
|
}
|
||||||
// Ok(())
|
Ok(())
|
||||||
// }
|
}
|
||||||
// None => Err(CompileError(0, 0, format!("Unknown name {}", name))),
|
None => Err(CompileError(0, 0, format!("Unknown name {}", name))),
|
||||||
// },
|
}
|
||||||
// Val::Expr(node) => {
|
}
|
||||||
// todo!();
|
Expr::Expr(e) => {
|
||||||
// // // Recurse on expressions, handling operators
|
// Just an expr containing an expr, recurse
|
||||||
// // lhs.0.process(state, Some(&mut sig))?;
|
(*e.0).process(state, Some(sig))?;
|
||||||
// // rhs.0.process(state, Some(&mut sig))?;
|
Ok(())
|
||||||
// // match op {
|
}
|
||||||
// // // Basic math
|
Expr::Prefix(pre, e) => {
|
||||||
// // Operator::Add => sig.emit("add"),
|
(*e.0).process(state, Some(sig))?;
|
||||||
// // Operator::Sub => sig.emit("sub"),
|
match pre {
|
||||||
// // Operator::Mul => sig.emit("mul"),
|
Prefix::Neg => {
|
||||||
// // Operator::Div => sig.emit("div"),
|
// To arithmetically negate something, invert and increment (2s complement)
|
||||||
// // Operator::Mod => sig.emit("mod"),
|
sig.emit("xor -1");
|
||||||
// // Operator::And => {
|
sig.emit("add 1");
|
||||||
// // // Vulcan "and" is bitwise, so we need to flag-ify both args to make it logical
|
}
|
||||||
// // sig.emit("gt 0");
|
Prefix::Not => sig.emit("not"),
|
||||||
// // sig.emit("swap");
|
Prefix::Address => { todo!() }
|
||||||
// // sig.emit("gt 0");
|
}
|
||||||
// // sig.emit("and");
|
Ok(())
|
||||||
// // }
|
}
|
||||||
// // Operator::Or => {
|
Expr::Suffix(_, _) => {todo!()}
|
||||||
// // // Same as and, flag-ify both args
|
Expr::Infix(lhs, op, rhs) => {
|
||||||
// // sig.emit("gt 0");
|
// Recurse on expressions, handling operators
|
||||||
// // sig.emit("swap");
|
(*lhs.0).process(state, Some(&mut sig))?;
|
||||||
// // sig.emit("gt 0");
|
(*rhs.0).process(state, Some(&mut sig))?;
|
||||||
// // sig.emit("or");
|
match op {
|
||||||
// // }
|
// Basic math
|
||||||
// // Operator::BitAnd => sig.emit("and"),
|
Operator::Add => sig.emit("add"),
|
||||||
// // Operator::BitOr => sig.emit("or"),
|
Operator::Sub => sig.emit("sub"),
|
||||||
// // Operator::Xor => sig.emit("xor"),
|
Operator::Mul => sig.emit("mul"),
|
||||||
// // Operator::Lt => sig.emit("alt"),
|
Operator::Div => sig.emit("div"),
|
||||||
// // Operator::Le => {
|
Operator::Mod => sig.emit("mod"),
|
||||||
// // // LE and GE are the inverses of GT and LT (arithmetic versions)
|
Operator::And => {
|
||||||
// // sig.emit("agt");
|
// Vulcan "and" is bitwise, so we need to flag-ify both args to make it logical
|
||||||
// // sig.emit("not");
|
sig.emit("gt 0");
|
||||||
// // }
|
sig.emit("swap");
|
||||||
// // Operator::Gt => sig.emit("agt"),
|
sig.emit("gt 0");
|
||||||
// // Operator::Ge => {
|
sig.emit("and");
|
||||||
// // sig.emit("alt");
|
}
|
||||||
// // sig.emit("not");
|
Operator::Or => {
|
||||||
// // }
|
// Same as and, flag-ify both args
|
||||||
// // Operator::Eq => {
|
sig.emit("gt 0");
|
||||||
// // sig.emit("xor");
|
sig.emit("swap");
|
||||||
// // sig.emit("not");
|
sig.emit("gt 0");
|
||||||
// // }
|
sig.emit("or");
|
||||||
// // Operator::Ne => sig.emit("xor"),
|
}
|
||||||
// // Operator::Lshift => sig.emit("lshift"),
|
Operator::BitAnd => sig.emit("and"),
|
||||||
// // Operator::Rshift => sig.emit("arshift"),
|
Operator::BitOr => sig.emit("or"),
|
||||||
// // }
|
Operator::Xor => sig.emit("xor"),
|
||||||
// // Ok(())
|
Operator::Lt => sig.emit("alt"),
|
||||||
// }
|
Operator::Le => {
|
||||||
// // Node::Prefix(prefix, node) => {
|
// LE and GE are the inverses of GT and LT (arithmetic versions)
|
||||||
// // node.0.process(state, Some(sig))?;
|
sig.emit("agt");
|
||||||
// // match prefix {
|
sig.emit("not");
|
||||||
// // Prefix::Neg => {
|
}
|
||||||
// // // To arithmetically negate something, invert and increment (2s complement)
|
Operator::Gt => sig.emit("agt"),
|
||||||
// // sig.emit("xor -1");
|
Operator::Ge => {
|
||||||
// // sig.emit("add 1");
|
sig.emit("alt");
|
||||||
// // }
|
sig.emit("not");
|
||||||
// // Prefix::Not => sig.emit("not"),
|
}
|
||||||
// // }
|
Operator::Eq => {
|
||||||
// // Ok(())
|
sig.emit("xor");
|
||||||
// // }
|
sig.emit("not");
|
||||||
// }
|
}
|
||||||
|
Operator::Ne => sig.emit("xor"),
|
||||||
|
Operator::Lshift => sig.emit("lshift"),
|
||||||
|
Operator::Rshift => sig.emit("arshift"),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,18 +491,17 @@ impl Compilable for Global {
|
|||||||
|
|
||||||
impl Compilable for Const {
|
impl Compilable for Const {
|
||||||
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
|
fn process(self, state: &mut State, _: Option<&mut Signature>) -> Result<(), CompileError> {
|
||||||
todo!()
|
let var = if self.string.is_some() {
|
||||||
// let var = if self.string.is_some() {
|
// If it's a string, add it to the string table
|
||||||
// // If it's a string, add it to the string table
|
Variable::DirectLabel(state.add_string(&self.string.unwrap()))
|
||||||
// Variable::DirectLabel(state.add_string(&self.string.unwrap()))
|
} else if let Some(expr) = self.value {
|
||||||
// } else if let Some(expr) = self.value {
|
// Otherwise eval_const it
|
||||||
// // Otherwise eval_const it
|
Variable::Literal(eval_const(expr, &state.global_scope)?)
|
||||||
// Variable::Literal(eval_const(expr, &state.global_scope)?)
|
} else {
|
||||||
// } else {
|
unreachable!()
|
||||||
// unreachable!()
|
};
|
||||||
// };
|
// Add it to the global namespace
|
||||||
// // Add it to the global namespace
|
state.add_global(&self.name, |_| var.clone())
|
||||||
// state.add_global(&self.name, |_| var.clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,62 +517,48 @@ fn to_flag(val: bool) -> i32 {
|
|||||||
|
|
||||||
/// Evaluate a node in a static context, for const definitions and array sizes, that sort of thing.
|
/// Evaluate a node in a static context, for const definitions and array sizes, that sort of thing.
|
||||||
pub fn eval_const(expr: Expr, scope: &Scope) -> Result<i32, CompileError> {
|
pub fn eval_const(expr: Expr, scope: &Scope) -> Result<i32, CompileError> {
|
||||||
todo!()
|
match expr {
|
||||||
// match expr.lhs {
|
Expr::Number(n) => Ok(n), // That was easy
|
||||||
// Val::Number(n) => Ok(n),
|
Expr::Name(n) => if let Some(Variable::Literal(val)) = scope.get(&n) {
|
||||||
// // Node::Address(_) | Node::ArrayRef(_) | Node::Call(_) => Err(CompileError(
|
Ok(*val)
|
||||||
// // 0,
|
} else {
|
||||||
// // 0,
|
Err(CompileError(0, 0, format!("Unknown const {}", n)))
|
||||||
// // String::from("Constants must be statically defined"),
|
}
|
||||||
// // )),
|
Expr::Expr(e) => eval_const(*e.0, scope),
|
||||||
//
|
Expr::Prefix(pre, e) => {
|
||||||
// Val::Name(n) => {
|
let val = eval_const(*e.0, scope)?;
|
||||||
// if let Some(Variable::Literal(val)) = scope.get(&n) {
|
match pre {
|
||||||
// Ok(*val)
|
Prefix::Neg => Ok(-val),
|
||||||
// } else {
|
Prefix::Not => Ok(if val != 0 { 0 } else { 1 }),
|
||||||
// Err(CompileError(0, 0, format!("Unknown const {}", n)))
|
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"))),
|
||||||
// Val::Expr(node) => {
|
Expr::Infix(lhs, op, rhs) => {
|
||||||
// todo!()
|
let lhs = eval_const(*lhs.0, scope)?;
|
||||||
// // let lhs = eval_const(lhs.into(), scope)?;
|
let rhs = eval_const(*rhs.0, scope)?;
|
||||||
// // let rhs = eval_const(rhs.into(), scope)?;
|
match op {
|
||||||
// // match op {
|
Operator::Add => Ok(lhs + rhs),
|
||||||
// // Operator::Add => Ok(lhs + rhs),
|
Operator::Sub => Ok(lhs - rhs),
|
||||||
// // Operator::Sub => Ok(lhs - rhs),
|
Operator::Mul => Ok(lhs * rhs),
|
||||||
// // Operator::Mul => Ok(lhs * rhs),
|
Operator::Div => Ok(lhs / rhs),
|
||||||
// // Operator::Div => Ok(lhs / rhs),
|
Operator::Mod => Ok(lhs % rhs),
|
||||||
// // Operator::Mod => Ok(lhs % rhs),
|
Operator::And => Ok(to_flag(lhs != 0 && rhs != 0)),
|
||||||
// // Operator::And => Ok(to_flag(lhs != 0 && rhs != 0)),
|
Operator::Or => Ok(to_flag(lhs != 0 || rhs != 0)),
|
||||||
// // Operator::Or => Ok(to_flag(lhs != 0 || rhs != 0)),
|
Operator::BitAnd => Ok(lhs & rhs),
|
||||||
// // Operator::BitAnd => Ok(lhs & rhs),
|
Operator::BitOr => Ok(lhs | rhs),
|
||||||
// // Operator::BitOr => Ok(lhs | rhs),
|
Operator::Xor => Ok(lhs ^ rhs),
|
||||||
// // Operator::Xor => Ok(lhs ^ rhs),
|
Operator::Lt => Ok(to_flag(lhs < rhs)),
|
||||||
// // Operator::Lt => Ok(to_flag(lhs < rhs)),
|
Operator::Le => Ok(to_flag(lhs <= rhs)),
|
||||||
// // Operator::Le => Ok(to_flag(lhs <= rhs)),
|
Operator::Gt => Ok(to_flag(lhs > rhs)),
|
||||||
// // Operator::Gt => Ok(to_flag(lhs > rhs)),
|
Operator::Ge => Ok(to_flag(lhs >= rhs)),
|
||||||
// // Operator::Ge => Ok(to_flag(lhs >= rhs)),
|
Operator::Eq => Ok(to_flag(lhs == rhs)),
|
||||||
// // Operator::Eq => Ok(to_flag(lhs == rhs)),
|
Operator::Ne => Ok(to_flag(lhs != rhs)),
|
||||||
// // Operator::Ne => Ok(to_flag(lhs != rhs)),
|
Operator::Lshift => Ok(lhs << rhs),
|
||||||
// // Operator::Lshift => Ok(lhs << rhs),
|
Operator::Rshift => Ok(lhs >> rhs),
|
||||||
// // Operator::Rshift => Ok(lhs >> rhs),
|
}
|
||||||
// // }
|
}
|
||||||
// }
|
}
|
||||||
// // Node::Prefix(p, child) => {
|
|
||||||
// // let val = eval_const(child.into(), scope)?;
|
|
||||||
// // match p {
|
|
||||||
// // Prefix::Neg => Ok(-val),
|
|
||||||
// // Prefix::Not => {
|
|
||||||
// // if val == 0 {
|
|
||||||
// // Ok(1)
|
|
||||||
// // } else {
|
|
||||||
// // Ok(0)
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -687,7 +683,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_literal_strings() {
|
fn test_literal_strings() {
|
||||||
let mut state = State::default();
|
let mut state = State::default();
|
||||||
parse("const s1 = \"foo\"; fn blah() { var x; x = \"bar\"; }")
|
parse("const s1 = \"foo\"; fn blah() { var x; x = \"bar\"; var y = \"norp\"; }")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.process(&mut state, None)
|
.process(&mut state, None)
|
||||||
.expect("Failed to compile");
|
.expect("Failed to compile");
|
||||||
@@ -696,12 +692,20 @@ mod test {
|
|||||||
state.strings,
|
state.strings,
|
||||||
vec![
|
vec![
|
||||||
("_gensym_1".into(), "foo".into()),
|
("_gensym_1".into(), "foo".into()),
|
||||||
("_gensym_3".into(), "bar".into()) // gensym 2 is the entrypoint of blah()
|
("_gensym_3".into(), "bar".into()), // gensym 2 is the entrypoint of blah()
|
||||||
|
("_gensym_4".into(), "norp".into())
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
body,
|
body,
|
||||||
vec!["push _gensym_3", "loadw frame", "storew"].join("\n")
|
vec![
|
||||||
) // todo we want to allow strings in initializers also
|
"push _gensym_3",
|
||||||
|
"loadw frame",
|
||||||
|
"storew", // the assignment for x
|
||||||
|
"push _gensym_4",
|
||||||
|
"loadw frame",
|
||||||
|
"add 3", // the address of y (frame + 3) and put gensym_4 in it
|
||||||
|
"storew"].join("\n")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+59
-129
@@ -31,7 +31,6 @@ use crate::ast::*;
|
|||||||
use pest::error::{Error, LineColLocation};
|
use pest::error::{Error, LineColLocation};
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use crate::ast::Suffix::{Arglist, Subscript};
|
|
||||||
|
|
||||||
pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>;
|
pub(crate) type Pair<'a> = pest::iterators::Pair<'a, Rule>;
|
||||||
pub(crate) type Pairs<'i, R = Rule> = pest::iterators::Pairs<'i, R>;
|
pub(crate) type Pairs<'i, R = Rule> = pest::iterators::Pairs<'i, R>;
|
||||||
@@ -325,13 +324,7 @@ impl AstNode for Assignment {
|
|||||||
const RULE: Rule = Rule::assignment;
|
const RULE: Rule = Rule::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_pair = pairs.next().unwrap();
|
let lvalue = Lvalue::from_pair(pairs.next().unwrap());
|
||||||
let lvalue = Lvalue::from_pair(lvalue_pair);
|
|
||||||
// let lvalue = match lvalue_pair.as_rule() {
|
|
||||||
// Rule::subscript => Lvalue::ArrayRef(Subscript::from_pair(lvalue_pair)),
|
|
||||||
// Rule::name => Lvalue::Name(String::from(lvalue_pair.as_str())),
|
|
||||||
// _ => unreachable!(),
|
|
||||||
// };
|
|
||||||
let rvalue = Rvalue::from_pair(pairs.next().unwrap());
|
let rvalue = Rvalue::from_pair(pairs.next().unwrap());
|
||||||
Self { lvalue, rvalue }
|
Self { lvalue, rvalue }
|
||||||
}
|
}
|
||||||
@@ -343,9 +336,13 @@ 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 = pairs.next().unwrap().as_str();
|
let name = String::from(pairs.next().unwrap().as_str());
|
||||||
pairs.next().map_or(Lvalue::Name(String::from(name)),
|
let subscripts: Vec<_> = pairs.map(|p| match p.as_rule() {
|
||||||
|subscript| Lvalue::ArrayRef(String::from(name), Expr::from_pair(subscript.first())))
|
Rule::subscript => Suffix::Subscript(Expr::from_pair(p.first()).into()),
|
||||||
|
Rule::member => Suffix::Member(String::from(p.as_str())),
|
||||||
|
_ => unreachable!()
|
||||||
|
}).collect();
|
||||||
|
Self { name, subscripts }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +369,7 @@ impl AstNode for VarDecl {
|
|||||||
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(Expr::from_pair);
|
let initial = inner.next().map(Rvalue::from_pair);
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
typename,
|
typename,
|
||||||
@@ -446,7 +443,7 @@ impl AstNode for Expr {
|
|||||||
// expr = { prefix* ~ val ~ suffix* ~ (operator ~ prefix* ~ val ~ suffix*)* }
|
// expr = { prefix* ~ val ~ suffix* ~ (operator ~ prefix* ~ val ~ suffix*)* }
|
||||||
// Each of these map methods turns a thing into an expr. Which means expr HAS
|
// Each of these map methods turns a thing into an expr. Which means expr HAS
|
||||||
// to be an enum with the different possible forms these things can take:
|
// to be an enum with the different possible forms these things can take:
|
||||||
// - if it's a val, it goes into map_primary and returns an Expr::Val
|
// - if it's a term, it goes into map_primary and returns an Expr::Number or Name
|
||||||
// - If it's a prefix or suffix, it goes into map_prefix or map_postfix, and
|
// - If it's a prefix or suffix, it goes into map_prefix or map_postfix, and
|
||||||
// returns an Expr::Prefix or Expr::Suffix
|
// returns an Expr::Prefix or Expr::Suffix
|
||||||
// - Operators go into map_infix along with two exprs for the left and right
|
// - Operators go into map_infix along with two exprs for the left and right
|
||||||
@@ -454,13 +451,12 @@ impl AstNode for Expr {
|
|||||||
// The output of all this is an Expr, containing a tree of other Exprs of
|
// The output of all this is an Expr, containing a tree of other Exprs of
|
||||||
// various forms.
|
// various forms.
|
||||||
PRATT_PARSER
|
PRATT_PARSER
|
||||||
.map_primary(|val| {
|
.map_primary(|term| {
|
||||||
let val = Val::from_pair(val);
|
match term.as_rule() {
|
||||||
// If the val is a parenthesized expr, just unwrap it
|
Rule::number => Expr::Number(term.into_number()),
|
||||||
if let Val::Expr(expr) = val {
|
Rule::name => Expr::Name(String::from(term.as_str())),
|
||||||
*expr.0
|
Rule::expr => Expr::from_pair(term).into(),
|
||||||
} else {
|
_ => unreachable!()
|
||||||
Expr::Val(val)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_infix(|lhs, op, rhs|
|
.map_infix(|lhs, op, rhs|
|
||||||
@@ -485,7 +481,6 @@ impl Expr {
|
|||||||
|
|
||||||
impl AstNode for Operator {
|
impl AstNode for Operator {
|
||||||
const RULE: Rule = Rule::operator;
|
const RULE: Rule = Rule::operator;
|
||||||
// also term_op
|
|
||||||
fn from_pair(pair: Pair) -> Self {
|
fn from_pair(pair: Pair) -> Self {
|
||||||
match pair.as_str() {
|
match pair.as_str() {
|
||||||
"+" => Self::Add,
|
"+" => Self::Add,
|
||||||
@@ -532,10 +527,10 @@ impl AstNode for Suffix {
|
|||||||
fn from_pair(pair: Pair) -> Self {
|
fn from_pair(pair: Pair) -> Self {
|
||||||
let first = pair.first();
|
let first = pair.first();
|
||||||
match first.as_rule() {
|
match first.as_rule() {
|
||||||
Rule::subscript => Subscript(Expr::from_pair(first.first()).into()),
|
Rule::subscript => Self::Subscript(Expr::from_pair(first.first()).into()),
|
||||||
Rule::member => Self::Member(first.first_as_string()),
|
Rule::member => Self::Member(first.first_as_string()),
|
||||||
Rule::arglist => Arglist(first.into_inner().map(Rvalue::from_pair).collect()),
|
Rule::arglist => Self::Arglist(first.into_inner().map(Rvalue::from_pair).collect()),
|
||||||
_ => unreachable!()
|
rule => unreachable!("Expected a subscript, member, or arglist, got a {:?}", rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -558,33 +553,10 @@ impl AstNode for Program {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl AstNode for Val {
|
|
||||||
const RULE: Rule = Rule::val;
|
|
||||||
|
|
||||||
fn from_pair(pair: Pair) -> Self {
|
|
||||||
let val = pair.first();
|
|
||||||
match val.as_rule() {
|
|
||||||
Rule::number => Self::Number(val.into_number()),
|
|
||||||
Rule::name => Self::Name(String::from(val.as_str())),
|
|
||||||
Rule::expr => Self::Expr(Expr::from_pair(val).into()),
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_vals() {
|
|
||||||
// Basic vals with no extras:
|
|
||||||
assert_eq!(Val::from_str("10"), Ok(10.into()));
|
|
||||||
assert_eq!(Val::from_str("blah"), Ok(Val::Name("blah".into())));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_globals() {
|
fn parse_globals() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -768,7 +740,7 @@ mod test {
|
|||||||
// A very, very basic expression
|
// A very, very basic expression
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::from_str("23"),
|
Expr::from_str("23"),
|
||||||
Ok(Expr::Val(Val::Number(23)))
|
Ok(Expr::Number(23))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Two vals with an operator
|
// Two vals with an operator
|
||||||
@@ -879,47 +851,11 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_arrayrefs() {
|
|
||||||
// use crate::ast::ArrayRef as AR;
|
|
||||||
// use Val::*;
|
|
||||||
// use Operator::*;
|
|
||||||
//
|
|
||||||
// // Normal numbers
|
|
||||||
// assert_eq!(
|
|
||||||
// AR::from_str("foo[7]"),
|
|
||||||
// Ok(AR {
|
|
||||||
// name: "foo".into(),
|
|
||||||
// subscript: Number(7).into()
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// // Full exprs (this is the last one of these; the full expr test above covers it
|
|
||||||
// assert_eq!(
|
|
||||||
// AR::from_str("foo[7+x]"),
|
|
||||||
// Ok(AR {
|
|
||||||
// name: "foo".into(),
|
|
||||||
// subscript: Node::from_str("7+x").unwrap().into()
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Exprs that are actually arrayrefs
|
|
||||||
// assert_eq!(
|
|
||||||
// Node::from_str("foo[7]"),
|
|
||||||
// Ok(ArrayRef(AR {
|
|
||||||
// name: "foo".into(),
|
|
||||||
// subscript: Number(7).into()
|
|
||||||
// }))
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_calls() {
|
fn parse_calls() {
|
||||||
use Val::Number;
|
|
||||||
|
|
||||||
let blah = Expr::Suffix(
|
let blah = Expr::Suffix(
|
||||||
"blah".into(),
|
"blah".into(),
|
||||||
Arglist(vec![])
|
Suffix::Arglist(vec![])
|
||||||
);
|
);
|
||||||
|
|
||||||
// Can Node parse a call?
|
// Can Node parse a call?
|
||||||
@@ -933,7 +869,7 @@ mod test {
|
|||||||
Expr::from_str("blah(1, 2)"),
|
Expr::from_str("blah(1, 2)"),
|
||||||
Ok(Expr::Suffix(
|
Ok(Expr::Suffix(
|
||||||
"blah".into(),
|
"blah".into(),
|
||||||
Arglist(vec![1.into(), 2.into()])))
|
Suffix::Arglist(vec![1.into(), 2.into()])))
|
||||||
);
|
);
|
||||||
|
|
||||||
//Calls with strings
|
//Calls with strings
|
||||||
@@ -941,7 +877,7 @@ mod test {
|
|||||||
Expr::from_str("blah(\"foo\", 2)"),
|
Expr::from_str("blah(\"foo\", 2)"),
|
||||||
Ok(Expr::Suffix(
|
Ok(Expr::Suffix(
|
||||||
"blah".into(),
|
"blah".into(),
|
||||||
Arglist(vec!["foo".into(), 2.into()])))
|
Suffix::Arglist(vec!["foo".into(), 2.into()])))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -963,7 +899,7 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
Statement::from_str("foo = 7;"),
|
Statement::from_str("foo = 7;"),
|
||||||
Ok(Statement::Assignment(Assignment {
|
Ok(Statement::Assignment(Assignment {
|
||||||
lvalue: Lvalue::Name("foo".into()),
|
lvalue: "foo".into(),
|
||||||
rvalue: Rvalue::Expr(7.into()),
|
rvalue: Rvalue::Expr(7.into()),
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
@@ -971,7 +907,7 @@ mod test {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
Assignment::from_str("foo[45] = 7"),
|
Assignment::from_str("foo[45] = 7"),
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
lvalue: Lvalue::ArrayRef("foo".into(), 45.into()),
|
lvalue: Lvalue { name: String::from("foo"), subscripts: vec![Suffix::Subscript(45.into())] },
|
||||||
rvalue: Rvalue::Expr(7.into()),
|
rvalue: Rvalue::Expr(7.into()),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -1000,22 +936,16 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn parse_block() {
|
fn parse_block() {
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// Block::from_str("{ foo(); bar(); }"),
|
Block::from_str("{ foo(); bar(); }"),
|
||||||
// Ok(Block(vec![
|
Ok(Block(vec![
|
||||||
// Statement::Call(Call {
|
Statement::Expr(Expr::Suffix("foo".into(), Suffix::Arglist(vec![]))),
|
||||||
// name: "foo".into(),
|
Statement::Expr(Expr::Suffix("bar".into(), Suffix::Arglist(vec![]))),
|
||||||
// args: vec![]
|
]))
|
||||||
// }),
|
);
|
||||||
// Statement::Call(Call {
|
}
|
||||||
// name: "bar".into(),
|
|
||||||
// args: vec![]
|
|
||||||
// }),
|
|
||||||
// ]))
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_conditional() {
|
fn parse_conditional() {
|
||||||
@@ -1051,33 +981,33 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_repeat_loops() {
|
fn parse_repeat_loops() {
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// Statement::from_str("repeat(10) x { foo(x); }"),
|
Statement::from_str("repeat(10) x { foo(x); }"),
|
||||||
// Ok(Statement::RepeatLoop(RepeatLoop {
|
Ok(Statement::RepeatLoop(RepeatLoop {
|
||||||
// count: Node::Number(10),
|
count: 10.into(),
|
||||||
// name: Some("x".into()),
|
name: Some("x".into()),
|
||||||
// body: Block::from_str("{ foo(x); }").unwrap(),
|
body: Block::from_str("{ foo(x); }").unwrap(),
|
||||||
// }))
|
}))
|
||||||
// );
|
);
|
||||||
//
|
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// Statement::from_str("repeat(10) { foo(); }"),
|
Statement::from_str("repeat(10) { foo(); }"),
|
||||||
// Ok(Statement::RepeatLoop(RepeatLoop {
|
Ok(Statement::RepeatLoop(RepeatLoop {
|
||||||
// count: Node::Number(10),
|
count: 10.into(),
|
||||||
// name: None,
|
name: None,
|
||||||
// body: Block::from_str("{ foo(); }").unwrap(),
|
body: Block::from_str("{ foo(); }").unwrap(),
|
||||||
// }))
|
}))
|
||||||
// );
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_program() {
|
fn parse_program() {
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// Program::from_str("global foo; struct Point { x, y }"),
|
Program::from_str("global foo; struct Point { x, y }"),
|
||||||
// Ok(Program(vec![
|
Ok(Program(vec![
|
||||||
// Declaration::from_str("global foo;").unwrap(),
|
Declaration::from_str("global foo;").unwrap(),
|
||||||
// Declaration::from_str("struct Point { x, y }").unwrap(),
|
Declaration::from_str("struct Point { x, y }").unwrap(),
|
||||||
// ]))
|
]))
|
||||||
// )
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ string_inner = ${ !("\"" | "\\") ~ ANY | escape }
|
|||||||
string = ${ "\"" ~ string_inner* ~ "\"" }
|
string = ${ "\"" ~ string_inner* ~ "\"" }
|
||||||
|
|
||||||
assignment = { lvalue ~ "=" ~ rvalue }
|
assignment = { lvalue ~ "=" ~ rvalue }
|
||||||
lvalue = { name ~ subscript? }
|
lvalue = { name ~ (modifier)* }
|
||||||
rvalue = { expr | string }
|
rvalue = { expr | string }
|
||||||
|
|
||||||
add = { "+" }
|
add = { "+" }
|
||||||
@@ -64,10 +64,11 @@ operator = _{
|
|||||||
| ne
|
| ne
|
||||||
}
|
}
|
||||||
|
|
||||||
expr = { prefix* ~ val ~ suffix* ~ (operator ~ prefix* ~ val ~ suffix*)* }
|
expr = { prefix* ~ term ~ suffix* ~ (operator ~ prefix* ~ term ~ suffix*)* }
|
||||||
val = { number | name | "(" ~ expr ~ ")" }
|
term = _{ number | name | "(" ~ expr ~ ")" }
|
||||||
|
|
||||||
suffix = { subscript | arglist | member }
|
suffix = { modifier | arglist }
|
||||||
|
modifier = _{ subscript | member }
|
||||||
subscript = { "[" ~ expr ~ "]" }
|
subscript = { "[" ~ expr ~ "]" }
|
||||||
arglist = { "(" ~ (rvalue ~ ("," ~ rvalue)*)? ~ ")" }
|
arglist = { "(" ~ (rvalue ~ ("," ~ rvalue)*)? ~ ")" }
|
||||||
member = { "." ~ name }
|
member = { "." ~ name }
|
||||||
@@ -91,7 +92,7 @@ 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 ~ ("=" ~ expr)? }
|
var_decl = { "var" ~ name ~ varinfo ~ ("=" ~ rvalue)? }
|
||||||
global = { "global" ~ name ~ varinfo ~ ";" }
|
global = { "global" ~ name ~ varinfo ~ ";" }
|
||||||
typename = { ":" ~ name }
|
typename = { ":" ~ name }
|
||||||
size = { "[" ~ expr ~ "]" }
|
size = { "[" ~ expr ~ "]" }
|
||||||
|
|||||||
Reference in New Issue
Block a user