Compare commits
5 commits
072653935e
...
0bcf2a1ef5
Author | SHA1 | Date | |
---|---|---|---|
0bcf2a1ef5 | |||
b607b6f8ed | |||
e020b8b78a | |||
2c67dba4d7 | |||
040ab13911 |
12 changed files with 286 additions and 259 deletions
116
Cargo.lock
generated
116
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -264,8 +264,8 @@ pub fn parse_binary_expression_arg(tokens: &mut Vec<&lexer::Token>) -> Result<Ar
|
|||
let mut args: Vec<_> = 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<Ar
|
|||
args = tokens.drain(..2).collect();
|
||||
bin_expr = Arg::BinaryExpression {
|
||||
left: Box::new(bin_expr),
|
||||
right: Box::new((&parse_args(vec![args[1]])?[0]).clone()),
|
||||
right: Box::new(parse_args(vec![args[1]])?[0].clone()),
|
||||
op: parse_binary_operation(args[0])?,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,6 @@ impl Data {
|
|||
"tlr" => 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 => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]: [{}]",
|
||||
|
|
|
@ -279,68 +279,3 @@ pub fn lex(source: &str) -> Result<Vec<Token>> {
|
|||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ pub fn parse(tokens: Vec<lexer::Token>) -> Result<ast::AST> {
|
|||
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(_)))
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
: test1 40 ;
|
||||
: test2 test1 2 ;
|
||||
|
||||
1 1 = debug
|
||||
if 69 else 42 then debug
|
||||
|
||||
|
|
|
@ -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<T, U> {
|
||||
fn compile(&self, data: &T) -> Result<U>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Word {
|
||||
pub id: usize,
|
||||
pub instructions: Vec<Instruction>,
|
||||
pub times_used: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Condition {
|
||||
pub if_instructions: Vec<Instruction>,
|
||||
pub else_instructions: Vec<Instruction>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Data {
|
||||
pub words: HashMap<String, Word>,
|
||||
// pub word_graph:
|
||||
pub conditions: IndexSet<Condition>,
|
||||
pub strings: IndexSet<String>,
|
||||
}
|
||||
|
||||
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<T, U> {
|
||||
fn compile(&self, data: &T) -> Result<U>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Word {
|
||||
pub id: usize,
|
||||
pub instructions: Vec<Instruction>,
|
||||
pub times_used: usize,
|
||||
pub callable_graph_node: NodeIndex,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Condition {
|
||||
pub if_instructions: Vec<Instruction>,
|
||||
pub else_instructions: Vec<Instruction>,
|
||||
pub callable_graph_node: NodeIndex,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CallableId {
|
||||
Word(String),
|
||||
Condition(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Data {
|
||||
pub strings: IndexSet<String>,
|
||||
pub callable_graph: Graph<CallableId, ()>,
|
||||
pub words: HashMap<String, Word>,
|
||||
pub conditions: Vec<Condition>,
|
||||
}
|
||||
|
||||
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<Instruction>) -> 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::<Result<Vec<_>>>()?.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::<Result<Vec<_>>>()?.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::<Result<Vec<_>>>()?.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::<Result<Vec<_>>>()?.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::<Vec<_>>()
|
||||
{
|
||||
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::<Result<Vec<hence::parser::ast::Body>>>()
|
||||
.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::<Vec<_>>()
|
||||
// {
|
||||
// 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::<Result<Vec<hence::parser::ast::Body>>>()
|
||||
// .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()),
|
||||
|
|
|
@ -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<Self>,
|
||||
count: usize,
|
||||
},
|
||||
|
||||
Call(String),
|
||||
Condition(usize),
|
||||
}
|
||||
|
||||
impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruction {
|
||||
|
@ -91,7 +92,7 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> 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<compiler::Data, hence::parser::ast::Body> 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::<Result<Vec<hence::parser::ast::Body>>>()?
|
||||
.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::<Result<Vec<hence::parser::ast::Body>>>()?
|
||||
// .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<compiler::Data, hence::parser::ast::Body> 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<compiler::Data, hence::parser::ast::Body> 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 {
|
||||
|
|
|
@ -61,4 +61,3 @@ return_call_stack_jump:
|
|||
tsr CORE_REG_C
|
||||
get
|
||||
tlr CORE_REG_PC
|
||||
|
|
@ -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<Vec<Token>> {
|
|||
let mut chars = source.chars().peekable();
|
||||
let mut tokens: Vec<Token> = 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<Vec<Token>> {
|
|||
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),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue