A big refactor, step 3.1
This commit is contained in:
@@ -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")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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> {
|
||||||
|
|||||||
Reference in New Issue
Block a user