diff --git a/Cargo.lock b/Cargo.lock index 19467d1..7c7db20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "anyhow" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26fa4d7e3f2eebadf743988fc8aec9fa9a9e82611acafd77c1462ed6262440a" +checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" dependencies = [ "backtrace", ] @@ -66,9 +66,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array", ] @@ -87,9 +87,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.20" +version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ "atty", "bitflags", @@ -126,13 +126,13 @@ dependencies = [ [[package]] name = "console" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89eab4d20ce20cea182308bca13088fecea9c05f6776cf287205d41a0ed3c847" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" dependencies = [ "encode_unicode", + "lazy_static", "libc", - "once_cell", "terminal_size", "unicode-width", "winapi", @@ -140,13 +140,23 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "dependency-graph" version = "0.1.5" @@ -158,11 +168,12 @@ dependencies = [ [[package]] name = "digest" -version = "0.9.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "generic-array", + "block-buffer", + "crypto-common", ] [[package]] @@ -250,6 +261,7 @@ dependencies = [ "itertools", "lazy_static", "parse_int", + "petgraph", ] [[package]] @@ -273,9 +285,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -288,9 +300,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.132" +version = "0.2.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" [[package]] name = "memchr" @@ -300,9 +312,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] @@ -327,15 +339,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "os_str_bytes" @@ -394,18 +400,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f53dc8cf16a769a6f677e09e7ff2cd4be1ea0f48754aac39520536962011de0d" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -439,9 +445,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] @@ -454,9 +460,9 @@ checksum = "c5e9af64574935e39f24d1c0313a997c8b880ca0e087c888bc6af8af31579847" [[package]] name = "rust-embed" -version = "6.4.0" +version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a17e5ac65b318f397182ae94e532da0ba56b88dd1200b774715d36c4943b1c3" +checksum = "e26934cd67a1da1165efe61cba4047cc1b4a526019da609fcce13a1000afb5fa" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -465,9 +471,9 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "6.2.0" +version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" +checksum = "e35d7b402e273544cc08e0824aa3404333fab8a90ac43589d3d5b72f4b346e12" dependencies = [ "proc-macro2", "quote", @@ -478,9 +484,9 @@ dependencies = [ [[package]] name = "rust-embed-utils" -version = "7.2.0" +version = "7.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029" +checksum = "c1669d81dfabd1b5f8e2856b8bbe146c6192b0ba22162edc738ac0a5de18f054" dependencies = [ "sha2", "walkdir", @@ -503,15 +509,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.9" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "block-buffer", "cfg-if", "cpufeatures", "digest", - "opaque-debug", ] [[package]] @@ -522,13 +526,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.94" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" +checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -552,9 +556,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "typenum" @@ -569,16 +573,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e" [[package]] -name = "unicode-width" -version = "0.1.9" +name = "unicode-ident" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] -name = "unicode-xid" -version = "0.2.3" +name = "unicode-width" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "version_check" diff --git a/hence/src/lib/arg.rs b/hence/src/lib/arg.rs index 8e9a70b..36dc012 100644 --- a/hence/src/lib/arg.rs +++ b/hence/src/lib/arg.rs @@ -264,8 +264,8 @@ pub fn parse_binary_expression_arg(tokens: &mut Vec<&lexer::Token>) -> Result = tokens.drain(..3).collect(); let mut bin_expr = Arg::BinaryExpression { - left: Box::new((&parse_args(vec![args[0]])?[0]).clone()), - right: Box::new((&parse_args(vec![args[2]])?[0]).clone()), + left: Box::new(parse_args(vec![args[0]])?[0].clone()), + right: Box::new(parse_args(vec![args[2]])?[0].clone()), op: parse_binary_operation(args[1])?, }; @@ -273,7 +273,7 @@ pub fn parse_binary_expression_arg(tokens: &mut Vec<&lexer::Token>) -> Result 0x06, "tlrc" => 0x07, "tls" => 0x08, - // "ld" => 0x09, "dbg" => 0x09, "alu" => 0x0a, "get" => 0x0b, @@ -104,7 +103,6 @@ impl Data { Some(x) => x.resolve_number(self)?, None => 0, }; - if a == 0 { Ok(Some(vec![opcode | 0b10000000])) } else { @@ -158,7 +156,7 @@ impl Data { bail!("First argument of define macro needs to be a variable") } }; - self.constants.insert(name.clone(), (&args[1]).clone()); + self.constants.insert(name.clone(), args[1].clone()); Ok(None) } @@ -181,7 +179,7 @@ impl Data { bail!("First argument of define macro needs to be a literal-like value") } }; - let args = (&args[1..]) + let args = args[1..] .iter() .map(|a| match a { arg::Arg::Variable(x) => Ok(x.clone()), @@ -380,20 +378,17 @@ impl Data { while !self.body_stack.is_empty() { self.constants .insert(offset_name.clone(), arg::Arg::Number(self.offset)); - match self.resolve_node()? { - Some(x) => { - if self.offset + (x.len() as u16) > 32 * 1024 { - bail!( - "Offset out of bounds: 0x{} > 0x8000", - radix(self.offset, 16) - ); - } - for byte in x { - self.program[self.offset as usize] = byte; - self.offset += 1; - } + if let Some(x) = self.resolve_node()? { + if self.offset + (x.len() as u16) > 32 * 1024 { + bail!( + "Offset out of bounds: 0x{} > 0x8000", + radix(self.offset, 16) + ); + } + for byte in x { + self.program[self.offset as usize] = byte; + self.offset += 1; } - None => {} } } diff --git a/hence/src/lib/emulator.rs b/hence/src/lib/emulator.rs index 7877a56..7a69a5d 100644 --- a/hence/src/lib/emulator.rs +++ b/hence/src/lib/emulator.rs @@ -235,6 +235,7 @@ pub fn emulate(data: &mut Data) -> Result<()> { match data.reg_opc { 0x00 => {} 0x01 => { + data.tmp = data.reg_arg; data.memory[data.reg_sp as usize] = data.reg_arg; data.reg_sp = data.reg_sp.wrapping_add(1); } @@ -263,11 +264,6 @@ pub fn emulate(data: &mut Data) -> Result<()> { data.memory[data.reg_sp as usize] = data.tmp; data.reg_sp = data.reg_sp.wrapping_add(1); } - // 0x09 => { - // data.reg_sp = data.reg_sp.wrapping_sub(1); - // data.set_register(data.reg_arg as u8, data.stack[data.reg_sp as usize]); - // data.stack[data.reg_sp as usize] = 0; - // } 0x09 => { println!( "[DEBUG]: [{}]", diff --git a/hence/src/lib/lexer.rs b/hence/src/lib/lexer.rs index b15a625..1260dbe 100644 --- a/hence/src/lib/lexer.rs +++ b/hence/src/lib/lexer.rs @@ -279,68 +279,3 @@ pub fn lex(source: &str) -> Result> { Ok(tokens) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::assembler::ToCode; - - #[test] - fn test_token_to_assembly() { - assert_eq!( - Token::Comment(" \"main function\" like definition macro".to_string()).to_code(), - "; \"main function\" like definition macro".to_string() - ); - assert_eq!( - Token::CharLiteral("\\n".to_string()).to_code(), - "'\\n'".to_string() - ); - assert_eq!( - Token::MacroLiteral("xyz".to_string()).to_code(), - "xyz".to_string() - ); - assert_eq!( - Token::Literal("xkcd".to_string()).to_code(), - "xkcd".to_string() - ); - assert_eq!(Token::Newline("\n".to_string()).to_code(), "\n".to_string()); - assert_eq!( - Token::Whitespace(" ".to_string()).to_code(), - " ".to_string() - ); - } - - #[test] - fn test_lex() -> Result<()> { - assert_eq!( - lex(";; test".to_string())?, - vec![Token::Comment(" test".to_string())] - ); - assert_eq!( - lex("@ test".to_string())?, - vec![Token::Comment(" test".to_string())] - ); - assert_eq!( - lex("# test".to_string())?, - vec![Token::Comment(" test".to_string())] - ); - assert_eq!( - lex("'\\n'".to_string())?, - vec![Token::CharLiteral("\\n".to_string())] - ); - assert_eq!( - lex("\"test\"".to_string())?, - vec![Token::StringLiteral("test".to_string())] - ); - assert_eq!( - lex(".debug CORE_REG_PC".to_string())?, - vec![ - Token::MacroLiteral(".debug".to_string()), - Token::Whitespace(" ".to_string()), - Token::Literal("CORE_REG_PC".to_string()) - ] - ); - - Ok(()) - } -} diff --git a/hence/src/lib/parser.rs b/hence/src/lib/parser.rs index ba9fead..e21abc1 100644 --- a/hence/src/lib/parser.rs +++ b/hence/src/lib/parser.rs @@ -20,7 +20,7 @@ pub fn parse(tokens: Vec) -> Result { iter.next(); body.push(ast::Node::MacroCall { - name: (&x[1..]).to_string(), + name: x[1..].to_string(), args: arg::parse_args( iter.by_ref() .take_while(|t| !matches!(t, lexer::Token::Newline(_))) diff --git a/henceforth/Cargo.toml b/henceforth/Cargo.toml index 3f63dfc..e4cb700 100644 --- a/henceforth/Cargo.toml +++ b/henceforth/Cargo.toml @@ -24,4 +24,5 @@ parse_int = "0.6.0" indexmap = "1.9.1" lazy_static = "1.4.0" dependency-graph = "0.1.5" +petgraph = "0.6.2" diff --git a/henceforth/examples/test.fth b/henceforth/examples/test.fth index c1e936e..c661066 100644 --- a/henceforth/examples/test.fth +++ b/henceforth/examples/test.fth @@ -1,3 +1,6 @@ +: test1 40 ; +: test2 test1 2 ; + 1 1 = debug if 69 else 42 then debug diff --git a/henceforth/src/lib/compiler.rs b/henceforth/src/lib/compiler.rs index b0d5001..87facdd 100644 --- a/henceforth/src/lib/compiler.rs +++ b/henceforth/src/lib/compiler.rs @@ -1,7 +1,8 @@ -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use indexmap::IndexSet; use itertools::Itertools; use lazy_static::lazy_static; +use petgraph::{graph::NodeIndex, Graph}; use std::collections::HashMap; use crate::parser; @@ -9,32 +10,7 @@ use crate::parser; mod instruction; pub use crate::compiler::instruction::Instruction; -pub trait Compilable { - fn compile(&self, data: &T) -> Result; -} - -#[derive(Debug)] -pub struct Word { - pub id: usize, - pub instructions: Vec, - pub times_used: usize, -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct Condition { - pub if_instructions: Vec, - pub else_instructions: Vec, -} - -#[derive(Debug)] -pub struct Data { - pub words: HashMap, - // pub word_graph: - pub conditions: IndexSet, - pub strings: IndexSet, -} - -pub const TEMPLATE_ASM: &str = include_str!("compiler/template.asm"); +pub const TEMPLATE_ASM: &str = include_str!("compiler/templates/default.asm"); lazy_static! { #[derive(Debug)] @@ -45,15 +21,93 @@ lazy_static! { .body; } +pub trait Compilable { + fn compile(&self, data: &T) -> Result; +} + +#[derive(Debug)] +pub struct Word { + pub id: usize, + pub instructions: Vec, + pub times_used: usize, + pub callable_graph_node: NodeIndex, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct Condition { + pub if_instructions: Vec, + pub else_instructions: Vec, + pub callable_graph_node: NodeIndex, +} + +#[derive(Debug)] +pub enum CallableId { + Word(String), + Condition(usize), +} + +#[derive(Debug)] +pub struct Data { + pub strings: IndexSet, + pub callable_graph: Graph, + pub words: HashMap, + pub conditions: Vec, +} + impl Data { pub fn default() -> Self { Self { - words: HashMap::new(), - conditions: IndexSet::new(), + // words: HashMap::new(), + // conditions: IndexSet::new(), strings: IndexSet::new(), + callable_graph: Graph::new(), + words: HashMap::new(), + conditions: vec![], } } + pub fn add_graph_edge(&mut self, origin: NodeIndex, instruction: Instruction) -> Result<()> { + match instruction { + Instruction::Call(x) => { + self.callable_graph.add_edge( + origin, + self.words + .get(&x) + .context(format!("Could not get already resolved referenced word: {}", x))? + .callable_graph_node, + (), + ); + } + Instruction::Condition(x) => { + self.callable_graph.add_edge( + origin, + self.conditions + .get(x) + .context(format!("Could not get already resolved referenced condition: {}", x))? + .callable_graph_node, + (), + ); + } + Instruction::Multiple { + instruction, + count: _, + } => { + self.add_graph_edge(origin, *instruction)?; + } + _ => {} + } + + Ok(()) + } + + pub fn add_graph_edges(&mut self, origin: NodeIndex, ins: Vec) -> Result<()> { + for instruction in ins { + self.add_graph_edge(origin, instruction)?; + } + + Ok(()) + } + pub fn generate_instructions( &mut self, body: parser::ast::Body, @@ -91,7 +145,7 @@ impl Data { }); } parser::ast::Node::Number(x) => { - instructions.push(instruction::Instruction::Push(x as u16)); + instructions.push(instruction::Instruction::Push(x)); } parser::ast::Node::WordDefinition { name, @@ -104,35 +158,46 @@ impl Data { bail!("Word already exists as user word definition: {}", name); } - let ins = self.generate_instructions(body, optimize)?; - + let origin = self + .callable_graph + .add_node(CallableId::Word(name.to_string())); self.words.insert( - name, + name.to_string(), Word { id: self.words.len(), - instructions: ins, + instructions: vec![], times_used: 0, + callable_graph_node: origin, }, ); + let ins = self.generate_instructions(body, optimize)?; + self.words + .get_mut(&name) + .context(format!("Could not get word: {}", name))? + .instructions = ins.clone(); + self.add_graph_edges(origin, ins)?; } parser::ast::Node::Condition { if_body, else_body } => { let if_instructions = self.generate_instructions(if_body, optimize)?; let else_instructions = self.generate_instructions(else_body, optimize)?; - let id = self - .conditions - .insert_full(Condition { - if_instructions, - else_instructions, - }) - .0; + let id = self.conditions.len(); + let origin = self.callable_graph.add_node(CallableId::Condition(id)); + self.conditions.push(Condition { + if_instructions: if_instructions.clone(), + else_instructions: else_instructions.clone(), + callable_graph_node: origin, + }); instructions.push(Instruction::Condition(id)); + self.add_graph_edges(origin, if_instructions)?; + self.add_graph_edges(origin, else_instructions)?; + dbg!(&self); } parser::ast::Node::Word(x) => { if let Some(ins) = Instruction::from_word(&x) { instructions.push(ins); } else if let Some(w) = self.words.get_mut(&x) { - instructions.push(Instruction::Call(x)); w.times_used += 1; + instructions.push(Instruction::Call(x)); } else { bail!("Word does not exist: {}", x); } @@ -159,42 +224,42 @@ impl Data { } // conditions - for (id, c) in self.conditions.iter().enumerate() { - x.push(hence::parser::ast::Node::Label(format!( - "conditions_if_{}", - id - ))); - x.extend(c.if_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); - x.push(hence::parser::ast::Node::Label(format!("conditions_else_{}", id))); - x.extend(c.else_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); - } + // for (id, c) in self.conditions.iter().enumerate() { + // x.push(hence::parser::ast::Node::Label(format!( + // "conditions_if_{}", + // id + // ))); + // x.extend(c.if_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); + // x.push(hence::parser::ast::Node::Label(format!("conditions_else_{}", id))); + // x.extend(c.else_instructions.iter().map(|ins| ins.compile(self)).collect::>>()?.into_iter().flatten()); + // } // words - for (name, word) in &self - .words - .iter() - .filter(|(_, w)| w.times_used > 1) - .sorted_by(|a, b| Ord::cmp(&a.1.id, &b.1.id)) - .collect::>() - { - x.extend(vec![ - hence::parser::ast::Node::Label(format!("words_{}", word.id)), - hence::parser::ast::Node::Comment(format!("word: \"{}\"", name)), - ]); - x.extend( - word.instructions - .iter() - .map(|ins| ins.compile(self)) - .collect::>>() - .unwrap() - .into_iter() - .flatten(), - ); - x.push(hence::parser::ast::Node::MacroCall { - name: "return_call_stack_jump".to_string(), - args: vec![], - }); - } + // for (name, word) in &self + // .words + // .iter() + // .filter(|(_, w)| w.times_used > 1) + // .sorted_by(|a, b| Ord::cmp(&a.1.id, &b.1.id)) + // .collect::>() + // { + // x.extend(vec![ + // hence::parser::ast::Node::Label(format!("words_{}", word.id)), + // hence::parser::ast::Node::Comment(format!("word: \"{}\"", name)), + // ]); + // x.extend( + // word.instructions + // .iter() + // .map(|ins| ins.compile(self)) + // .collect::>>() + // .unwrap() + // .into_iter() + // .flatten() + // ); + // x.push(hence::parser::ast::Node::MacroCall { + // name: "return_call_stack_jump".to_string(), + // args: vec![], + // }); + // } x.extend([ hence::parser::ast::Node::Label("main".to_string()), diff --git a/henceforth/src/lib/compiler/instruction.rs b/henceforth/src/lib/compiler/instruction.rs index 7f653ab..11f8ef0 100644 --- a/henceforth/src/lib/compiler/instruction.rs +++ b/henceforth/src/lib/compiler/instruction.rs @@ -7,7 +7,7 @@ pub enum Instruction { Nop, Debug, Quit, - Push(u16), + Push(i32), Drop, Depth, Pick, @@ -64,14 +64,15 @@ pub enum Instruction { Times, Divide, Mod, - Call(String), AsmQuote(String), - Condition(usize), Multiple { instruction: Box, count: usize, }, + + Call(String), + Condition(usize), } impl compiler::Compilable for Instruction { @@ -91,7 +92,7 @@ impl compiler::Compilable for Instruct }]), Instruction::Push(x) => Ok(vec![hence::parser::ast::Node::Call { name: "push".to_string(), - arg: Some(hence::arg::Arg::Number(*x)), + arg: Some(hence::arg::Arg::Number(*x as u16)), }]), Instruction::Drop => Ok(vec![hence::parser::ast::Node::Call { name: "pop".to_string(), @@ -1222,27 +1223,33 @@ impl compiler::Compilable for Instruct }, ]), 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) => 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) => Ok(vec![]), + Instruction::Condition(x) => { + dbg!(x); + + Ok(vec![]) + } Instruction::Multiple { instruction, count } => { if *count == 0 { @@ -1253,6 +1260,18 @@ impl compiler::Compilable for Instruct 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 { @@ -1369,7 +1388,7 @@ impl compiler::Compilable for Instruct arg: None, }, ]), - _ => bail!("Remainder of count % 3 cannot be higher than 3"), + x => bail!("Remainder of count % 3 cannot be higher than 3: {}", x), }, Instruction::Nip => Ok([ vec![hence::parser::ast::Node::MacroCall { diff --git a/henceforth/src/lib/compiler/template.asm b/henceforth/src/lib/compiler/templates/default.asm similarity index 99% rename from henceforth/src/lib/compiler/template.asm rename to henceforth/src/lib/compiler/templates/default.asm index 83837f1..b54a29b 100644 --- a/henceforth/src/lib/compiler/template.asm +++ b/henceforth/src/lib/compiler/templates/default.asm @@ -61,4 +61,3 @@ return_call_stack_jump: tsr CORE_REG_C get tlr CORE_REG_PC - diff --git a/henceforth/src/lib/lexer.rs b/henceforth/src/lib/lexer.rs index fff7038..edc3e83 100644 --- a/henceforth/src/lib/lexer.rs +++ b/henceforth/src/lib/lexer.rs @@ -4,8 +4,8 @@ use itertools::Itertools; #[derive(Debug)] pub enum Token { - Newline(String), - Whitespace(String), + Newline(usize), + Whitespace(usize), ParenComment(String), BackslashComment(String), @@ -19,7 +19,8 @@ pub enum Token { impl ToCode for Token { fn to_code(&self) -> String { match self { - Token::Newline(x) | Token::Whitespace(x) => x.clone(), + Token::Newline(x) => ["\n"].into_iter().cycle().take(*x).join(""), + Token::Whitespace(x) => [" "].into_iter().cycle().take(*x).join(""), Token::ParenComment(x) => format!("( {})", x), Token::BackslashComment(x) => format!("\\{}", x), Token::DoubleDashComment(x) => format!("-- {}", x), @@ -37,21 +38,19 @@ pub fn lex(source: &str) -> Result> { let mut chars = source.chars().peekable(); let mut tokens: Vec = vec![]; - while let Some(&c) = chars.peek() { + while let Some(c) = chars.peek() { tokens.push(match c { - '\n' => Token::Newline(chars.peeking_take_while(|&c| c == '\n').collect()), + '\n' => Token::Newline(chars.peeking_take_while(|&c| c == '\n').count()), _ if c.is_whitespace() => { - Token::Whitespace(chars.peeking_take_while(|&c| c.is_whitespace()).collect()) - } - '\\' => { - chars.next(); - Token::BackslashComment(chars.peeking_take_while(|&c| c != '\n').collect()) + Token::Whitespace(chars.peeking_take_while(|&c| c.is_whitespace()).count()) } + '\\' => Token::BackslashComment(chars.peeking_take_while(|&c| c != '\n').collect()), _ if c.is_numeric() => { Token::Number(chars.peeking_take_while(|&c| !is_space(c)).collect()) } _ => { let x: String = chars.peeking_take_while(|&c| !is_space(c)).collect(); + let mut iter = x.chars(); match x.as_str() { "(" => Token::ParenComment( @@ -64,6 +63,17 @@ pub fn lex(source: &str) -> Result> { mode: x.chars().take(x.len() - 1).collect(), string: chars.by_ref().skip(1).take_while(|&c| c != '"').collect(), }, + _ if iter.next() == Some('-') => { + if let Some(c) = iter.next() { + if c.is_numeric() { + Token::Number(x) + } else { + Token::Word(x) + } + } else { + Token::Word(x) + } + } _ => Token::Word(x), } }