A big refactor, step 3.1

This commit is contained in:
2023-11-11 16:35:02 -06:00
parent ac05959042
commit 89560573ec
5 changed files with 147 additions and 103 deletions
+5 -102
View File
@@ -1,4 +1,4 @@
use crate::ast::{Asm, Block, Conditional, Location, Statement, WhileLoop}; use crate::ast::{Asm, Block, Location, Statement};
use crate::compiler::compilable::Compilable; use crate::compiler::compilable::Compilable;
use crate::compiler::compiled_fn::CompiledFn; use crate::compiler::compiled_fn::CompiledFn;
use crate::compiler::CompileError; use crate::compiler::CompileError;
@@ -34,24 +34,11 @@ impl Compilable for Block {
// Emit the body // Emit the body
sig.emit(body.as_str()) sig.emit(body.as_str())
} }
Statement::Conditional(Conditional { condition, body, alternative }) => { Statement::Conditional(cond) => {
// todo split into new file cond.process(state, Some(sig), loc)?;
condition.process(state, Some(sig), loc)?;
sig.emit("#if"); // We went to a lot of trouble making macros, shame not to use them
body.process(state, Some(sig), loc)?;
if let Some(alternative) = alternative {
sig.emit("#else");
alternative.process(state, Some(sig), loc)?;
}
sig.emit("#end")
} }
Statement::WhileLoop(WhileLoop { condition, body }) => { Statement::WhileLoop(while_loop) => {
// todo split into new file while_loop.process(state, Some(sig), loc)?;
sig.emit("#while");
condition.process(state, Some(sig), loc)?;
sig.emit("#do");
body.process(state, Some(sig), loc)?;
sig.emit("#end")
} }
Statement::RepeatLoop(repeat_loop) => { Statement::RepeatLoop(repeat_loop) => {
repeat_loop.process(state, Some(sig), loc)?; repeat_loop.process(state, Some(sig), loc)?;
@@ -86,90 +73,6 @@ mod test {
) )
} }
#[test]
fn test_conditionals() {
assert_eq!(
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } }")),
vec![
"push 3",
"loadw frame",
"storew", // x = 3
"loadw frame",
"loadw",
"push 2",
"agt", // The condition, x > 2
"#if", // The if itself
"push 1",
"loadw frame",
"storew", // The branch, x = 1
"#end"]
.join("\n")
);
assert_eq!(
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } else { x = 7; } }")),
vec![
"push 3",
"loadw frame",
"storew", // x = 3
"loadw frame",
"loadw",
"push 2",
"agt", // The condition, x > 2
"#if", // The if itself
"push 1",
"loadw frame",
"storew", // The affirmative branch, x = 1
"#else", // The alternative
"push 7",
"loadw frame",
"storew", // x = 7
"#end"]
.join("\n")
)
}
#[test]
fn test_while_loops() {
assert_eq!(
test_body(state_for("fn test() { var x = 0; var c = 0; while (c < 10) { x = x + c; c = c + 1; } }")),
vec![
"push 0",
"loadw frame",
"storew", // var x = 0
"push 0",
"loadw frame",
"add 3",
"storew", // var c = 0
"#while", // Start the loop
"loadw frame",
"add 3",
"loadw",
"push 10",
"alt", // c > 10
"#do", // Start loop body
"loadw frame",
"loadw",
"loadw frame",
"add 3",
"loadw",
"add",
"loadw frame",
"storew", // x = x + c
"loadw frame",
"add 3",
"loadw",
"push 1",
"add",
"loadw frame",
"add 3",
"storew", // c = c + 1
"#end", // End the loop body
]
.join("\n")
);
}
#[test] #[test]
fn test_block_scoping() { fn test_block_scoping() {
assert_eq!( assert_eq!(
@@ -0,0 +1,74 @@
use crate::ast::{Conditional, Location};
use crate::compiler::compilable::Compilable;
use crate::compiler::compiled_fn::CompiledFn;
use crate::compiler::CompileError;
use crate::compiler::state::State;
impl Compilable for Conditional {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, loc: Location) -> Result<(), CompileError> {
let sig = sig.expect("Conditional outside function");
let Conditional { condition, body, alternative } = self;
condition.process(state, Some(sig), loc)?;
sig.emit("#if"); // We went to a lot of trouble making macros, shame not to use them
body.process(state, Some(sig), loc)?;
if let Some(alternative) = alternative {
sig.emit("#else");
alternative.process(state, Some(sig), loc)?;
}
sig.emit("#end");
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::compiler::test_utils::*;
#[test]
fn test_conditionals() {
assert_eq!(
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } }")),
vec![
"push 3",
"loadw frame",
"storew", // x = 3
"loadw frame",
"loadw",
"push 2",
"agt", // The condition, x > 2
"#if", // The if itself
"push 1",
"loadw frame",
"storew", // The branch, x = 1
"#end"]
.join("\n")
);
}
#[test]
fn test_if_else() {
assert_eq!(
test_body(state_for("fn test() { var x = 3; if (x > 2) { x = 1; } else { x = 7; } }")),
vec![
"push 3",
"loadw frame",
"storew", // x = 3
"loadw frame",
"loadw",
"push 2",
"agt", // The condition, x > 2
"#if", // The if itself
"push 1",
"loadw frame",
"storew", // The affirmative branch, x = 1
"#else", // The alternative
"push 7",
"loadw frame",
"storew", // x = 7
"#end"]
.join("\n")
)
}
}
+2
View File
@@ -12,3 +12,5 @@ mod expr;
mod global; mod global;
mod r#const; mod r#const;
mod r#return; mod r#return;
mod conditional;
mod while_loop;
@@ -0,0 +1,66 @@
use crate::ast::{Location, WhileLoop};
use crate::compiler::compilable::Compilable;
use crate::compiler::compiled_fn::CompiledFn;
use crate::compiler::CompileError;
use crate::compiler::state::State;
impl Compilable for WhileLoop {
fn process(self, state: &mut State, sig: Option<&mut CompiledFn>, loc: Location) -> Result<(), CompileError> {
let sig = sig.expect("Loop outside function");
let WhileLoop { condition, body } = self;
sig.emit("#while");
condition.process(state, Some(sig), loc)?;
sig.emit("#do");
body.process(state, Some(sig), loc)?;
sig.emit("#end");
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::compiler::test_utils::*;
#[test]
fn test_while_loops() {
assert_eq!(
test_body(state_for("fn test() { var x = 0; var c = 0; while (c < 10) { x = x + c; c = c + 1; } }")),
vec![
"push 0",
"loadw frame",
"storew", // var x = 0
"push 0",
"loadw frame",
"add 3",
"storew", // var c = 0
"#while", // Start the loop
"loadw frame",
"add 3",
"loadw",
"push 10",
"alt", // c > 10
"#do", // Start loop body
"loadw frame",
"loadw",
"loadw frame",
"add 3",
"loadw",
"add",
"loadw frame",
"storew", // x = x + c
"loadw frame",
"add 3",
"loadw",
"push 1",
"add",
"loadw frame",
"add 3",
"storew", // c = c + 1
"#end", // End the loop body
]
.join("\n")
);
}
}
-1
View File
@@ -83,7 +83,6 @@ pub fn parse(src: &str) -> Result<Program, ParseError> {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// todo: can this die? it's only used in compiler tests but needs to be here for visibility reasons
#[cfg(test)] #[cfg(test)]
impl Expr { impl Expr {
pub(crate) fn parse(src: &str) -> Result<Self, ParseError> { pub(crate) fn parse(src: &str) -> Result<Self, ParseError> {