Asm statements implemented

This commit is contained in:
2023-08-15 01:30:35 -05:00
parent 9936e44544
commit a6b3519f48
4 changed files with 74 additions and 10 deletions
+7 -1
View File
@@ -40,6 +40,7 @@ pub enum Statement {
Conditional(Conditional),
WhileLoop(WhileLoop),
RepeatLoop(RepeatLoop),
Asm(Asm)
}
#[derive(PartialEq, Clone, Debug)]
@@ -103,6 +104,12 @@ pub struct RepeatLoop {
pub body: Block,
}
#[derive(PartialEq, Clone, Debug)]
pub struct Asm {
pub args: Vec<BoxExpr>,
pub body: String
}
/// One of the five arithmetical operators
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Operator {
@@ -136,7 +143,6 @@ pub enum Expr {
Address(Lvalue),
Call(BoxExpr, Vec<Expr>),
Subscript(BoxExpr, BoxExpr),
Member(BoxExpr, String),
Infix(BoxExpr, Operator, BoxExpr),
String(String),
}
+34 -8
View File
@@ -1,7 +1,7 @@
use crate::ast::*;
use std::collections::btree_map::Entry::Vacant;
use std::collections::{BTreeMap, HashMap};
use std::collections::{BTreeMap};
use std::fmt::{Display, Formatter};
#[derive(Eq, Clone, PartialEq, Debug)]
@@ -80,7 +80,7 @@ impl CompiledFn {
fn add_local(&mut self, name: &str) -> Result<(), CompileError> {
if let Vacant(e) = self.local_scope.entry(name.into()) {
e.insert(Variable::Local(self.frame_size));
self.frame_size += 3; // todo: variously-sized structs
self.frame_size += 3;
Ok(())
} else {
Err(CompileError(0, 0, format!("Duplicate name {}", name)))
@@ -224,6 +224,14 @@ impl Compilable for Function {
sig.emit("pop")
}
Statement::VarDecl(vardecl) => vardecl.process(state, Some(&mut sig))?,
Statement::Asm(Asm { args, body}) => {
// Process all the args, if any
for a in args {
(*a.0).process(state, Some(&mut sig))?
}
// Emit the body
sig.emit(body.as_str())
}
Statement::Conditional(_) | Statement::WhileLoop(_) | Statement::RepeatLoop(_) => {
todo!()
}
@@ -293,7 +301,7 @@ impl Compilable for VarDecl {
impl Compilable for Lvalue {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>) -> Result<(), CompileError> {
let global_scope = &state.global_scope;
let mut sig = sig.expect("lvalue outside a function");
let sig = sig.expect("lvalue outside a function");
match *(self.0.0) {
// A bunch of different things that aren't allowed
@@ -340,9 +348,8 @@ impl Compilable for Lvalue {
Expr::Deref(BoxExpr(expr)) => {
(*expr).process(state, Some(sig))
}
Expr::Subscript(_, _) |
Expr::Member(_, _) => {
Err(CompileError(0, 0, String::from("Arrays and structs are not yet supported")))
Expr::Subscript(_, _) => {
Err(CompileError(0, 0, String::from("Arrays are not yet supported")))
}
}
}
@@ -430,7 +437,6 @@ impl Compilable for Expr {
}
Expr::Call(_, _) => todo!(),
Expr::Subscript(_, _) => todo!("Structs and arrays are not yen supported"),
Expr::Member(_, _) => todo!("Structs and arrays are not yen supported"),
Expr::Infix(lhs, op, rhs) => {
// Recurse on expressions, handling operators
(*lhs.0).process(state, Some(&mut sig))?;
@@ -551,7 +557,7 @@ pub fn eval_const(expr: Expr, scope: &Scope) -> Result<i32, CompileError> {
0,
String::from("Addresses are not known at compile time"),
)),
Expr::Call(_, _) | Expr::Subscript(_, _) | Expr::Member(_, _) => Err(CompileError(
Expr::Call(_, _) | Expr::Subscript(_, _) => Err(CompileError(
0,
0,
String::from("Constants must be statically defined"),
@@ -812,4 +818,24 @@ mod test {
.join("\n")
)
}
#[test]
fn test_asm_statements() {
let mut state = State::default();
parse("fn blah() { var x; asm(&x) { swap 12\nstorew } }")
.unwrap()
.process(&mut state, None)
.expect("Failed to compile");
let body = body_as_string(state.functions.get("blah").unwrap());
assert_eq!(
body,
vec![
"loadw frame", // Push the addr of x
"swap 12", // The asm body, which swaps 12 behind it and stores it there
"storew"
]
.join("\n")
)
}
}
+32
View File
@@ -232,6 +232,7 @@ impl AstNode for Statement {
Rule::conditional => Self::Conditional(Conditional::from_pair(pair)),
Rule::while_loop => Self::WhileLoop(WhileLoop::from_pair(pair)),
Rule::repeat_loop => Self::RepeatLoop(RepeatLoop::from_pair(pair)),
Rule::asm => Self::Asm(Asm::from_pair(pair)),
_ => unreachable!(),
}
}
@@ -239,6 +240,24 @@ impl AstNode for Statement {
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Asm {
const RULE: Rule = Rule::asm;
fn from_pair(pair: Pair) -> Self {
let mut args = Vec::new();
let mut body = None;
for p in pair.into_inner() {
match p.as_rule() {
Rule::expr => args.push(Expr::from_pair(p).into()),
Rule::asm_body => body = Some(String::from(p.as_str().trim())),
_ => unreachable!()
}
}
Self { args, body: body.unwrap() }
}
}
///////////////////////////////////////////////////////////////////////////////////////////
impl AstNode for Return {
const RULE: Rule = Rule::return_stmt;
fn from_pair(pair: Pair) -> Self {
@@ -813,6 +832,19 @@ mod test {
);
}
#[test]
fn parse_asm() {
assert_eq!(
Asm::from_str("asm { push 34 }"),
Ok(Asm { args: vec![], body: "push 34".into() })
);
assert_eq!(
Asm::from_str("asm (&a) { swap 34\nstorew }"),
Ok(Asm { args: vec![Expr::Address("a".into()).into()], body: "swap 34\nstorew".into() })
);
}
#[test]
fn parse_program() {
assert_eq!(
+1 -1
View File
@@ -72,7 +72,7 @@ arglist = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
statement = { asm | ((return_stmt | var_decl | assignment | expr) ~ ";") | conditional | while_loop | repeat_loop }
asm = { "asm" ~ asm_args? ~ "{" ~ asm_body ~ "}" }
asm_args = { "(" ~ expr ~ ("," ~ expr)* ~ ")" }
asm_args = _{ "(" ~ expr ~ ("," ~ expr)* ~ ")" }
asm_body = { (!"}" ~ ANY)* }
block = { "{" ~ statement* ~ "}" }