From a6b3519f48d8d63da4992c1bcca77dd7a7200719 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Tue, 15 Aug 2023 01:30:35 -0500 Subject: [PATCH] Asm statements implemented --- forge_core/src/ast.rs | 8 ++++++- forge_core/src/compiler.rs | 42 +++++++++++++++++++++++++++------- forge_core/src/forge_parser.rs | 32 ++++++++++++++++++++++++++ forge_core/src/new.pest | 2 +- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index 00fabac..891e8ca 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -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, + 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), Subscript(BoxExpr, BoxExpr), - Member(BoxExpr, String), Infix(BoxExpr, Operator, BoxExpr), String(String), } diff --git a/forge_core/src/compiler.rs b/forge_core/src/compiler.rs index 0e85752..af9c327 100644 --- a/forge_core/src/compiler.rs +++ b/forge_core/src/compiler.rs @@ -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 { 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") + ) + + } } diff --git a/forge_core/src/forge_parser.rs b/forge_core/src/forge_parser.rs index 3defe3c..369b443 100644 --- a/forge_core/src/forge_parser.rs +++ b/forge_core/src/forge_parser.rs @@ -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!( diff --git a/forge_core/src/new.pest b/forge_core/src/new.pest index 7ccbf3e..1f91654 100644 --- a/forge_core/src/new.pest +++ b/forge_core/src/new.pest @@ -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* ~ "}" }