use anyhow::{bail, Result}; use crate::compiler; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Instruction { Nop, Debug, Quit, Push(i32), Drop, Depth, Pick, Dup, Swap, Over, Rot, Nip, I, J, Tuck, Fetch, FetchPrint, Store, PlusStore, MinusStore, Cells, Allot, Dot, Emit, Space, Spaces, Cr, StringPrint(usize), StringReference(usize), Count, Not, And, Nand, Or, Nor, Xor, Xnor, Lsh, Rsh, Compare, Eq, Neq, Lt, Leq, Gt, Geq, Min, Max, Boolean, Invert, Random, Plus, OnePlus, TwoPlus, Minus, OneMinus, TwoMinus, Times, Divide, Mod, AsmQuote(String), Multiple { instruction: Box, count: usize, }, Call(String), Condition(usize), } impl compiler::Compilable for Instruction { fn compile(&self, data: &compiler::Data) -> Result { match self { Instruction::Nop => Ok(vec![hence::parser::ast::Node::Call { name: "nop".to_string(), arg: None, }]), Instruction::Debug => Ok(vec![hence::parser::ast::Node::Call { name: "dbg".to_string(), arg: None, }]), Instruction::Quit => Ok(vec![hence::parser::ast::Node::MacroCall { name: "std_stop".to_string(), args: vec![], }]), Instruction::Push(x) => Ok(vec![hence::parser::ast::Node::Call { name: "push".to_string(), arg: Some(hence::arg::Arg::Number(*x as u16)), }]), Instruction::Drop => Ok(vec![hence::parser::ast::Node::Call { name: "pop".to_string(), arg: None, }]), Instruction::Depth => Ok(vec![ hence::parser::ast::Node::Call { name: "tsr".to_string(), arg: Some(hence::arg::Arg::Variable("CORE_REG_SP".to_string())), }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Pick => Ok(vec![ hence::parser::ast::Node::Call { name: "tsr".to_string(), arg: Some(hence::arg::Arg::Variable("CORE_REG_SP".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_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::MacroCall { name: "std_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_B".to_string()), hence::arg::Arg::BinaryExpression { left: Box::new(hence::arg::Arg::Variable( "CORE_MEM_PRG_END".to_string(), )), right: Box::new(hence::arg::Arg::Number(2)), op: hence::arg::BinaryExpressionOperator::Sub, }, ], }, 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: "get".to_string(), arg: None, }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Dup => Ok(vec![ hence::parser::ast::Node::Call { name: "tss".to_string(), arg: None, }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Swap => 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, }, ]), Instruction::Over => 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::Call { name: "tss".to_string(), arg: None, }, 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, }, ]), 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![ hence::parser::ast::Node::MacroCall { name: "std_get".to_string(), args: vec![hence::arg::Arg::Variable("MEM_LOOP_I".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::J => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "std_get".to_string(), args: vec![hence::arg::Arg::Variable("MEM_LOOP_J".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), 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(), args: vec![], }, hence::parser::ast::Node::Call { name: "get".to_string(), arg: None, }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), 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![ 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(), 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_set".to_string(), args: vec![hence::arg::Arg::Variable("CORE_MEM_OUT".to_string())], }, ]), Instruction::Emit => 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_set".to_string(), args: vec![hence::arg::Arg::Variable("CORE_MEM_CHR".to_string())], }, ]), 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(' '), ], }, 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 { 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::StringPrint(x) => { let loop_label = format!("loop_strings_{}", x); let data_label = format!("data_strings_{}", x); let data_end_label = format!("data_strings_end_{}", x); Ok(vec![ hence::parser::ast::Node::MacroCall { name: "std_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_B".to_string()), hence::arg::Arg::Variable(data_label), ], }, hence::parser::ast::Node::Label(loop_label.clone()), 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: "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_CHR".to_string())], }, hence::parser::ast::Node::MacroCall { name: "std_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_A".to_string()), hence::arg::Arg::Number(1), ], }, 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_B".to_string())), }, hence::parser::ast::Node::MacroCall { name: "std_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_A".to_string()), hence::arg::Arg::Variable(data_end_label), ], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_GT".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_cond_jump".to_string(), args: vec![hence::arg::Arg::Variable(loop_label)], }, ]) } Instruction::StringReference(x) => Ok(vec![ hence::parser::ast::Node::Call { name: "push".to_string(), arg: Some(hence::arg::Arg::Variable(format!("data_strings_end_{}", x))), }, hence::parser::ast::Node::Call { name: "push".to_string(), arg: Some(hence::arg::Arg::Variable(format!("data_strings_{}", x))), }, ]), Instruction::Count => Ok(vec![]), Instruction::Not => 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_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_NOT".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::And => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_AND".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Nand => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_AND".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_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_NOT".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Or => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_OR".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Nor => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_OR".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_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_NOT".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Xor => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_XOR".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Xnor => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_XOR".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_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_NOT".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Lsh => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_LSH".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Rsh => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_RSH".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Compare => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_CMP".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Eq => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_EQ".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Neq => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_EQ".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_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_INV".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Lt => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_LT".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Leq => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_LEQ".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Gt => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_GT".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Geq => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_GEQ".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Min => 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: "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_GT".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_B".to_string())), }, hence::parser::ast::Node::Call { name: "tlrc".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_C".to_string())), }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Max => 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: "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_LT".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_B".to_string())), }, hence::parser::ast::Node::Call { name: "tlrc".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_C".to_string())), }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Boolean => 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_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_BOL".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Invert => 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_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_INV".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Random => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_RND".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Plus => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, 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: "tls".to_string(), arg: None, }, ]), Instruction::OnePlus => 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_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_B".to_string()), hence::arg::Arg::Number(1), ], }, 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: "tls".to_string(), arg: None, }, ]), Instruction::TwoPlus => 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_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_B".to_string()), hence::arg::Arg::Number(2), ], }, 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: "tls".to_string(), arg: None, }, ]), Instruction::Minus => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, 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: "tls".to_string(), arg: None, }, ]), Instruction::OneMinus => 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_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_B".to_string()), hence::arg::Arg::Number(1), ], }, 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: "tls".to_string(), arg: None, }, ]), Instruction::TwoMinus => 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_rset".to_string(), args: vec![ hence::arg::Arg::Variable("CORE_REG_B".to_string()), hence::arg::Arg::Number(2), ], }, 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: "tls".to_string(), arg: None, }, ]), Instruction::Times => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_MUL".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Divide => Ok(vec![ hence::parser::ast::Node::MacroCall { name: "stack_transfer_alu".to_string(), args: vec![], }, hence::parser::ast::Node::MacroCall { name: "std_alu".to_string(), args: vec![hence::arg::Arg::Variable("CORE_ALU_DIV".to_string())], }, hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }, ]), Instruction::Mod => Ok(vec![]), // Instruction::Call(x) => match data.words.get(x) { // Some(w) => { // if w.times_used > 1 { // Ok(vec![hence::parser::ast::Node::MacroCall { // name: "call_stack_jump".to_string(), // args: vec![hence::arg::Arg::Variable(format!("words_{}", w.id)), hence::arg::Arg::Variable("OFFSET".to_string())], // }]) // } else { // Ok(w.instructions // .iter() // .map(|ins| ins.compile(data)) // .collect::>>()? // .into_iter() // .flatten() // .collect()) // } // } // None => bail!("Unknown word: {}", x), // }, Instruction::Call(x) => bail!("Unknown word: {}", x), Instruction::AsmQuote(x) => Ok(hence::parser::parse(hence::lexer::lex(x)?)?.body), // Instruction::Condition(x) => Ok(vec![]), Instruction::Condition(x) => { dbg!(x); Ok(vec![]) } 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::Push(x) => Ok([ Instruction::Push(x).compile(data)?, [hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }] .into_iter() .cycle() .take(count - 1) .collect(), ] .concat()), 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, }, ]), x => bail!("Remainder of count % 3 cannot be higher than 3: {}", x), }, 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()), Instruction::I | Instruction::J => Ok([ instruction.compile(data)?, [hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }] .into_iter() .cycle() .take(count - 1) .collect(), ] .concat()), Instruction::Fetch => 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, }] .into_iter() .cycle() .take(*count) .collect(), vec![hence::parser::ast::Node::Call { name: "tls".to_string(), arg: None, }], ] .concat()), Instruction::Space | Instruction::Cr => Ok([ instruction.compile(data)?, [hence::parser::ast::Node::Call { name: "set".to_string(), arg: None, }] .into_iter() .cycle() .take(count - 1) .collect(), ] .concat()), _ => { let compiled = instruction.compile(data)?; let len = compiled.len() * count; Ok(compiled.into_iter().cycle().take(len).collect()) } } } } } } } impl Instruction { pub fn from_word(word: &str) -> Option { match word.to_lowercase().as_str() { "nop" => Some(Instruction::Nop), "debug" => Some(Instruction::Debug), "quit" => Some(Instruction::Quit), "drop" => Some(Instruction::Drop), "depth" => Some(Instruction::Depth), "pick" => Some(Instruction::Pick), "dup" => Some(Instruction::Dup), "swap" => Some(Instruction::Swap), "over" => Some(Instruction::Over), "rot" => Some(Instruction::Rot), "nip" => Some(Instruction::Nip), "i" => Some(Instruction::I), "j" => Some(Instruction::J), "tuck" => Some(Instruction::Tuck), "@" => Some(Instruction::Fetch), "?" => Some(Instruction::FetchPrint), "!" => Some(Instruction::Store), "+!" => Some(Instruction::PlusStore), "-!" => Some(Instruction::MinusStore), "cells" => Some(Instruction::Cells), "allot" => Some(Instruction::Allot), "." => Some(Instruction::Dot), "emit" => Some(Instruction::Emit), "space" => Some(Instruction::Space), "spaces" => Some(Instruction::Spaces), "cr" => Some(Instruction::Cr), "count" => Some(Instruction::Count), "not" => Some(Instruction::Not), "and" => Some(Instruction::And), "nand" => Some(Instruction::Nand), "or" => Some(Instruction::Or), "nor" => Some(Instruction::Nor), "xor" => Some(Instruction::Xor), "xnor" => Some(Instruction::Xnor), "lshift" => Some(Instruction::Lsh), "rshift" => Some(Instruction::Rsh), "compare" => Some(Instruction::Compare), "=" => Some(Instruction::Eq), "!=" => Some(Instruction::Neq), "<" => Some(Instruction::Lt), "<=" => Some(Instruction::Leq), ">" => Some(Instruction::Gt), ">=" => Some(Instruction::Geq), "min" => Some(Instruction::Min), "max" => Some(Instruction::Max), "boolean" => Some(Instruction::Boolean), "invert" => Some(Instruction::Invert), "random" => Some(Instruction::Random), "+" => Some(Instruction::Plus), "1+" => Some(Instruction::OnePlus), "2+" => Some(Instruction::TwoPlus), "-" => Some(Instruction::Minus), "1-" => Some(Instruction::OneMinus), "2-" => Some(Instruction::TwoMinus), "*" => Some(Instruction::Times), "/" => Some(Instruction::Divide), "mod" => Some(Instruction::Mod), _ => None, } } }