From 3b7ce3eb2604c50e8a158bc27add9efc467b889b Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Sat, 11 May 2024 01:24:41 -0500 Subject: [PATCH] Added once blocks --- forge_core/src/ast.rs | 11 ++++- forge_core/src/compiler/ast_nodes/block.rs | 5 +- forge_core/src/compiler/ast_nodes/mod.rs | 1 + forge_core/src/compiler/ast_nodes/once.rs | 48 ++++++++++++++++++++ forge_core/src/compiler/mod.rs | 5 ++ forge_core/src/compiler/state.rs | 8 ++++ forge_core/src/parser/ast_nodes/mod.rs | 3 +- forge_core/src/parser/ast_nodes/once.rs | 30 ++++++++++++ forge_core/src/parser/ast_nodes/statement.rs | 1 + forge_core/src/parser/forge.pest | 3 +- forge_core/src/parser/pairs_ext.rs | 24 +--------- vtest/src/forge_tests.rs | 21 +++++++++ 12 files changed, 132 insertions(+), 28 deletions(-) create mode 100644 forge_core/src/compiler/ast_nodes/once.rs create mode 100644 forge_core/src/parser/ast_nodes/once.rs diff --git a/forge_core/src/ast.rs b/forge_core/src/ast.rs index 4acde6e..277cccb 100644 --- a/forge_core/src/ast.rs +++ b/forge_core/src/ast.rs @@ -67,7 +67,8 @@ pub enum Statement { Conditional(Conditional), WhileLoop(WhileLoop), RepeatLoop(RepeatLoop), - Asm(Asm) + Asm(Asm), + Once(Once) } #[derive(PartialEq, Clone, Debug)] @@ -117,6 +118,11 @@ pub struct Conditional { pub alternative: Option, } +#[derive(PartialEq, Clone, Debug)] +pub struct Once { + pub body: Block +} + #[derive(PartialEq, Clone, Debug)] pub struct WhileLoop { pub condition: Expr, @@ -242,7 +248,8 @@ impl Statement { Statement::Conditional(_) => "conditional", Statement::WhileLoop(_) => "whileLoop", Statement::RepeatLoop(_) => "repeatLoop", - Statement::Asm(_) => "asm" + Statement::Asm(_) => "asm", + Statement::Once(_) => "once" } ) } diff --git a/forge_core/src/compiler/ast_nodes/block.rs b/forge_core/src/compiler/ast_nodes/block.rs index 0b84f4f..2093a83 100644 --- a/forge_core/src/compiler/ast_nodes/block.rs +++ b/forge_core/src/compiler/ast_nodes/block.rs @@ -5,7 +5,7 @@ use crate::compiler::CompileError; use crate::compiler::state::State; impl Compilable for Block { - fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, loc: Location) -> Result<(), CompileError> { + fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, _loc: Location) -> Result<(), CompileError> { let sig = sig.expect("Block outside function"); let frame_size_before_block = sig.frame_size(); @@ -66,6 +66,9 @@ impl Compilable for Block { Statement::RepeatLoop(repeat_loop) => { repeat_loop.process(state, Some(sig), loc)?; } + Statement::Once(once) => { + once.process(state, Some(sig), loc)?; + } } } diff --git a/forge_core/src/compiler/ast_nodes/mod.rs b/forge_core/src/compiler/ast_nodes/mod.rs index e4b892b..4443a78 100644 --- a/forge_core/src/compiler/ast_nodes/mod.rs +++ b/forge_core/src/compiler/ast_nodes/mod.rs @@ -14,3 +14,4 @@ mod r#const; mod r#return; mod conditional; mod while_loop; +mod once; diff --git a/forge_core/src/compiler/ast_nodes/once.rs b/forge_core/src/compiler/ast_nodes/once.rs new file mode 100644 index 0000000..2a4cb49 --- /dev/null +++ b/forge_core/src/compiler/ast_nodes/once.rs @@ -0,0 +1,48 @@ +use crate::ast::{Once, Location}; +use crate::compiler::compilable::Compilable; +use crate::compiler::compiled_fn::CompiledFn; +use crate::compiler::CompileError; +use crate::compiler::state::State; + +impl Compilable for Once { + fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, loc: Location) -> Result<(), CompileError> { + let sig = sig.expect("Once block outside function"); + + let Once { body } = self; + let sym = state.add_flag(); + + sig.emit_arg("loadw", sym.clone()); + sig.emit("#if"); + sig.emit_arg("push", 0); + sig.emit_arg("storew", sym); + body.process(state, Some(sig), loc)?; + sig.emit("#end"); + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::compiler::test_utils::*; + + #[test] + fn test_once() { + assert_eq!( + test_body(state_for("fn test() { var x = 0; once { x = 1; } }")), + vec![ + "push 0", + "peekr", + "storew", // x = 0 + "loadw _forge_gensym_3", // Load the once flag + "#if", + "push 0", // clear the once flag + "storew _forge_gensym_3", + "push 1", // x = 1 + "peekr", + "storew", + "#end" // end once block + ] + .join("\n") + ); + } +} \ No newline at end of file diff --git a/forge_core/src/compiler/mod.rs b/forge_core/src/compiler/mod.rs index d921c85..cdfa6cc 100644 --- a/forge_core/src/compiler/mod.rs +++ b/forge_core/src/compiler/mod.rs @@ -94,6 +94,11 @@ pub fn build_boot(src: &str, include_comments: bool) -> Result, Comp asm.push(format!(".org {} + {}", label, size)); } + // Once flags: + for label in state.flags { + asm.push(format!("{}: .db 1", label)); + } + // Final thing is to place a label for the stack: // (this is just a cell with the address of the following word) asm.push("stack: .db 0".into()); diff --git a/forge_core/src/compiler/state.rs b/forge_core/src/compiler/state.rs index 855a0e5..73f3e82 100644 --- a/forge_core/src/compiler/state.rs +++ b/forge_core/src/compiler/state.rs @@ -20,6 +20,8 @@ pub(crate) struct State { pub strings: Vec<(Label, String)>, /// The statically-allocated buffers (size in bytes) pub buffers: Vec<(Label, usize)>, + /// The flags for once blocks + pub flags: Vec