diff --git a/henceforth/examples/test.fth b/henceforth/examples/test.fth index 9994f74..11d41cb 100644 --- a/henceforth/examples/test.fth +++ b/henceforth/examples/test.fth @@ -1,2 +1,13 @@ -1 2 debug -1 pick debug +asm" +.std_get MEM_ALLOC_PTR +tls +dbg +pop +" +3 cells allot +asm" +.std_get MEM_ALLOC_PTR +tls +dbg +pop +" diff --git a/henceforth/src/lib/compiler.rs b/henceforth/src/lib/compiler.rs index c69d3d3..b2bcc2c 100644 --- a/henceforth/src/lib/compiler.rs +++ b/henceforth/src/lib/compiler.rs @@ -26,7 +26,7 @@ pub struct Data { } impl Data { - pub fn new() -> Self { + pub fn default() -> Self { Self { words: HashMap::new(), strings: IndexSet::new(), @@ -35,13 +35,29 @@ impl Data { pub fn generate_instructions(&mut self, body: parser::ast::Body) -> Result> { let mut instructions: Vec = vec![]; - for node in body { + let mut iter = body.into_iter().peekable(); + while let Some(node) = iter.next() { match node { + _ if iter.next_if_eq(&node).is_some() => { + let count = iter.by_ref().peeking_take_while(|n| *n == node).count() + 2; + instructions.push(Instruction::Multiple { + instruction: Box::new( + self.generate_instructions(vec![node])? + .into_iter() + .next() + .unwrap(), + ), + count, + }); + } parser::ast::Node::Comment(_) => {} parser::ast::Node::String { mode, string } => { - let id = self.strings.insert_full(string).0; instructions.push(match mode.as_str() { - "." => Instruction::DotQuote(id), + "." => { + let id = self.strings.insert_full(string).0; + Instruction::DotQuote(id) + } + "asm" => Instruction::AsmQuote(string), _ => bail!("Unknown string mode: {}", mode), }); } @@ -109,6 +125,17 @@ impl Data { hence::arg::Arg::Variable("CORE_MEM_MEM".to_string()), ], }, + hence::parser::ast::Node::MacroCall { + name: "define".to_string(), + args: vec![ + hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string()), + hence::arg::Arg::BinaryExpression { + left: Box::new(hence::arg::Arg::Variable("CORE_MEM_MEM".to_string())), + right: Box::new(hence::arg::Arg::Number(16)), + op: hence::arg::BinaryExpressionOperator::Add, + }, + ], + }, // macros // stack_transfer_alu hence::parser::ast::Node::MacroCall { @@ -195,6 +222,22 @@ impl Data { name: "endmacro".to_string(), args: vec![], }, + // setup + hence::parser::ast::Node::MacroCall { + name: "std_rset".to_string(), + args: vec![ + hence::arg::Arg::Variable("CORE_REG_A".to_string()), + hence::arg::Arg::BinaryExpression { + left: Box::new(hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string())), + right: Box::new(hence::arg::Arg::Number(1)), + op: hence::arg::BinaryExpressionOperator::Add, + }, + ], + }, + hence::parser::ast::Node::MacroCall { + name: "std_set".to_string(), + args: vec![hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string())], + }, // jump_main hence::parser::ast::Node::MacroCall { name: "jump_main".to_string(), @@ -262,7 +305,7 @@ impl Data { } pub fn compile(ast: parser::ast::AST) -> Result { - let mut data = Data::new(); + let mut data = Data::default(); let instructions = data.generate_instructions(ast.body)?; Ok(hence::parser::ast::AST { diff --git a/henceforth/src/lib/compiler/instruction.rs b/henceforth/src/lib/compiler/instruction.rs index 3ec7704..881a653 100644 --- a/henceforth/src/lib/compiler/instruction.rs +++ b/henceforth/src/lib/compiler/instruction.rs @@ -2,7 +2,7 @@ use anyhow::{bail, Result}; use crate::compiler; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub enum Instruction { Nop, Debug, @@ -63,6 +63,12 @@ pub enum Instruction { Divide, Mod, Call(String), + AsmQuote(String), + + Multiple { + instruction: Box, + count: usize, + }, } impl Instruction { @@ -291,11 +297,114 @@ impl compiler::Compilable for Instruct arg: None, }, ]), - Instruction::Rot => Ok(vec![]), - Instruction::Nip => Ok(vec![]), + Instruction::Rot => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + ]), + Instruction::Nip => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "pop".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + ]), Instruction::I => Ok(vec![]), Instruction::J => Ok(vec![]), - Instruction::Tuck => Ok(vec![]), + Instruction::Tuck => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + ]), Instruction::Fetch => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "std_ld".to_string(), @@ -310,12 +419,165 @@ impl compiler::Compilable for Instruct arg: None, }, ]), - Instruction::FetchPrint => Ok(vec![]), - Instruction::Store => Ok(vec![]), - Instruction::PlusStore => Ok(vec![]), - Instruction::MinusStore => Ok(vec![]), + Instruction::FetchPrint => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "get".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_set".to_string(), + args: vec![hence::arg::Arg::Variable("CORE_MEM_OUT".to_string())], + }, + ]), + Instruction::Store => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::Call { + name: "set".to_string(), + arg: None, + }, + ]), + Instruction::PlusStore => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::Call { + name: "get".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_alu".to_string(), + args: vec![hence::arg::Arg::Variable("CORE_ALU_ADD".to_string())], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::Call { + name: "set".to_string(), + arg: None, + }, + ]), + Instruction::MinusStore => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::Call { + name: "get".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_alu".to_string(), + args: vec![hence::arg::Arg::Variable("CORE_ALU_SUB".to_string())], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::Call { + name: "set".to_string(), + arg: None, + }, + ]), Instruction::Cells => Ok(vec![]), - Instruction::Allot => Ok(vec![]), + Instruction::Allot => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_get".to_string(), + args: vec![hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string())], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_alu".to_string(), + args: vec![hence::arg::Arg::Variable("CORE_ALU_ADD".to_string())], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_set".to_string(), + args: vec![hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string())], + }, + ]), Instruction::Dot => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "std_ld".to_string(), @@ -344,7 +606,19 @@ impl compiler::Compilable for Instruct args: vec![hence::arg::Arg::Variable("CORE_MEM_CHR".to_string())], }, ]), - Instruction::Space => Ok(vec![]), + Instruction::Space => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_rset".to_string(), + args: vec![ + hence::arg::Arg::Variable("CORE_REG_A".to_string()), + hence::arg::Arg::Char('\n'), + ], + }, + hence::parser::ast::Node::MacroCall { + name: "std_set".to_string(), + args: vec![hence::arg::Arg::Variable("CORE_MEM_CHR".to_string())], + }, + ]), Instruction::Spaces => Ok(vec![]), Instruction::Cr => Ok(vec![ hence::parser::ast::Node::MacroCall { @@ -622,6 +896,163 @@ impl compiler::Compilable for Instruct } None => bail!("Unknown word: {}", x), }, + Instruction::AsmQuote(x) => { + Ok(hence::parser::parse(hence::lexer::lex(x.to_string())?)?.body) + } + Instruction::Multiple { instruction, count } => { + if *count == 0 { + Ok(vec![]) + } else if *count == 1 { + Ok(instruction.compile(data)?) + } else { + match **instruction { + Instruction::Nop => Ok(Instruction::Nop.compile(data)?), + Instruction::Quit => Ok(Instruction::Quit.compile(data)?), + Instruction::Depth => Ok([ + Instruction::Depth.compile(data)?, + Instruction::Multiple { + instruction: Box::new(Instruction::Dup), + count: count - 1, + } + .compile(data)?, + ] + .concat()), + Instruction::Dup => Ok([ + Instruction::Dup.compile(data)?, + [hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }] + .into_iter() + .cycle() + .take(count - 1) + .collect(), + ] + .concat()), + Instruction::Swap => { + if count % 2 == 0 { + Ok(vec![]) + } else { + Ok(Instruction::Swap.compile(data)?) + } + } + Instruction::Over => Ok([ + Instruction::Over.compile(data)?, + (0..count - 1) + .flat_map(|n| { + if n % 2 == 0 { + vec![ + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable( + "CORE_REG_A".to_string(), + )), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + ] + } else { + vec![ + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable( + "CORE_REG_B".to_string(), + )), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + ] + } + }) + .collect(), + ] + .concat()), + Instruction::Rot => match count % 3 { + 0 => Ok(vec![]), + 1 => Ok(Instruction::Rot.compile(data)?), + 2 => Ok(vec![ + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }, + hence::parser::ast::Node::Call { + name: "tlr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_A".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_B".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + hence::parser::ast::Node::Call { + name: "tsr".to_string(), + arg: Some(hence::arg::Arg::Variable("CORE_REG_C".to_string())), + }, + hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }, + ]), + _ => bail!("Remainder of count % 3 cannot be higher than 3"), + }, + Instruction::Nip => Ok([ + vec![hence::parser::ast::Node::MacroCall { + name: "std_ld".to_string(), + args: vec![], + }], + [hence::parser::ast::Node::Call { + name: "pop".to_string(), + arg: None, + }] + .into_iter() + .cycle() + .take(*count) + .collect(), + vec![hence::parser::ast::Node::Call { + name: "tls".to_string(), + arg: None, + }], + ] + .concat()), + _ => { + let compiled = instruction.compile(data)?; + let len = compiled.len() * count; + Ok(compiled.into_iter().cycle().take(len).collect()) + } + } + } + } } } } diff --git a/henceforth/src/lib/parser/ast.rs b/henceforth/src/lib/parser/ast.rs index cd82756..0bec15b 100644 --- a/henceforth/src/lib/parser/ast.rs +++ b/henceforth/src/lib/parser/ast.rs @@ -1,7 +1,7 @@ use hence::assembler::ToCode; use itertools::Itertools; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct StackResult { pub before: Vec, pub after: Vec, @@ -25,7 +25,7 @@ impl ToCode for StackResult { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub enum Node { Comment(String), String {