[WIP] Add conditions

This commit is contained in:
Dominic Grimm 2022-09-11 18:02:56 +02:00
parent 7943b1607b
commit 0530522847
No known key found for this signature in database
GPG key ID: A6C051C716D2CE65
8 changed files with 338 additions and 180 deletions

33
Cargo.lock generated
View file

@ -147,6 +147,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "dependency-graph"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5143247629540606d0888beae9ca0e0b9a81a32151bfecd0b2be4a961155c24d"
dependencies = [
"petgraph",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.9.0" version = "0.9.0"
@ -168,6 +177,12 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.6" version = "0.14.6"
@ -229,9 +244,11 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"dependency-graph",
"hence", "hence",
"indexmap", "indexmap",
"itertools", "itertools",
"lazy_static",
"parse_int", "parse_int",
] ]
@ -263,6 +280,12 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.132" version = "0.2.132"
@ -329,6 +352,16 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "petgraph"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.16" version = "0.2.16"

View file

@ -22,3 +22,6 @@ anyhow = { version = "1.0.62", features = ["backtrace"] }
itertools = "0.10.2" itertools = "0.10.2"
parse_int = "0.6.0" parse_int = "0.6.0"
indexmap = "1.9.1" indexmap = "1.9.1"
lazy_static = "1.4.0"
dependency-graph = "0.1.5"

View file

@ -1,2 +1,7 @@
0 @ @ debug \ 1 1 = debug
\ if 69 else 42 then debug
: test 42 ;
test debug drop
test test debug

View file

@ -1,6 +1,7 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indexmap::IndexSet; use indexmap::IndexSet;
use itertools::Itertools; use itertools::Itertools;
use lazy_static::lazy_static;
use std::collections::HashMap; use std::collections::HashMap;
use crate::parser; use crate::parser;
@ -19,21 +20,45 @@ pub struct Word {
pub times_used: usize, pub times_used: usize,
} }
#[derive(Debug)]
pub struct Condition {
pub if_instructions: Vec<Instruction>,
pub else_instructions: Vec<Instruction>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct Data { pub struct Data {
pub words: HashMap<String, Word>, pub words: HashMap<String, Word>,
// pub word_graph:
pub conditions: IndexSet<Instruction>,
pub strings: IndexSet<String>, pub strings: IndexSet<String>,
} }
pub const TEMPLATE_ASM: &str = include_str!("compiler/template.asm");
lazy_static! {
#[derive(Debug)]
pub static ref TEMPLATE: hence::parser::ast::Body = hence::parser::parse(
hence::lexer::lex(TEMPLATE_ASM.to_string()).unwrap()
)
.unwrap()
.body;
}
impl Data { impl Data {
pub fn default() -> Self { pub fn default() -> Self {
Self { Self {
words: HashMap::new(), words: HashMap::new(),
conditions: IndexSet::new(),
strings: IndexSet::new(), strings: IndexSet::new(),
} }
} }
pub fn generate_instructions(&mut self, body: parser::ast::Body, optimize: bool) -> Result<Vec<Instruction>> { pub fn generate_instructions(
&mut self,
body: parser::ast::Body,
optimize: bool,
) -> Result<Vec<Instruction>> {
let mut instructions: Vec<Instruction> = vec![]; let mut instructions: Vec<Instruction> = vec![];
let mut iter = body.into_iter().peekable(); let mut iter = body.into_iter().peekable();
while let Some(node) = iter.next() { while let Some(node) = iter.next() {
@ -90,6 +115,12 @@ impl Data {
}, },
); );
} }
parser::ast::Node::Condition { if_body, else_body } => {
instructions.push(Instruction::Condition {
if_instructions: self.generate_instructions(if_body, optimize)?,
else_instructions: self.generate_instructions(else_body, optimize)?,
});
}
parser::ast::Node::Word(x) => { parser::ast::Node::Word(x) => {
if let Some(ins) = Instruction::from_word(&x) { if let Some(ins) = Instruction::from_word(&x) {
instructions.push(ins); instructions.push(ins);
@ -106,174 +137,10 @@ impl Data {
Ok(instructions) Ok(instructions)
} }
pub fn embed(&self, body: hence::parser::ast::Body) -> hence::parser::ast::Body { pub fn embed(&self, body: hence::parser::ast::Body) -> Result<hence::parser::ast::Body> {
let mut x = vec![ let mut x = TEMPLATE.to_vec();
// includes
hence::parser::ast::Node::MacroCall {
name: "include".to_string(),
args: vec![hence::arg::Arg::String("$lib/core.asm".to_string())],
},
hence::parser::ast::Node::MacroCall {
name: "include".to_string(),
args: vec![hence::arg::Arg::String("$lib/std.asm".to_string())],
},
hence::parser::ast::Node::MacroCall {
name: "include".to_string(),
args: vec![hence::arg::Arg::String("$lib/main.asm".to_string())],
},
// constants
hence::parser::ast::Node::MacroCall {
name: "define".to_string(),
args: vec![
hence::arg::Arg::Variable("MEM_CALL_STACK".to_string()),
hence::arg::Arg::Variable("CORE_MEM_MEM".to_string()),
],
},
hence::parser::ast::Node::MacroCall {
name: "define".to_string(),
args: vec![
hence::arg::Arg::Variable("MEM_LOOP_I".to_string()),
hence::arg::Arg::BinaryExpression {
left: Box::new(hence::arg::Arg::Variable("CORE_MEM_MEM".to_string())),
right: Box::new(hence::arg::Arg::Number(16)),
op: hence::arg::BinaryExpressionOperator::Add,
},
],
},
hence::parser::ast::Node::MacroCall {
name: "define".to_string(),
args: vec![
hence::arg::Arg::Variable("MEM_LOOP_J".to_string()),
hence::arg::Arg::BinaryExpression {
left: Box::new(hence::arg::Arg::Variable("MEM_LOOP_I".to_string())),
right: Box::new(hence::arg::Arg::Number(1)),
op: hence::arg::BinaryExpressionOperator::Add,
},
],
},
hence::parser::ast::Node::MacroCall {
name: "define".to_string(),
args: vec![
hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string()),
hence::arg::Arg::BinaryExpression {
left: Box::new(hence::arg::Arg::Variable("MEM_LOOP_J".to_string())),
right: Box::new(hence::arg::Arg::Number(1)),
op: hence::arg::BinaryExpressionOperator::Add,
},
],
},
// macros
// stack_transfer_alu
hence::parser::ast::Node::MacroCall {
name: "macro".to_string(),
args: vec![hence::arg::Arg::Variable("stack_transfer_alu".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_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: "endmacro".to_string(),
args: vec![],
},
// call_word
hence::parser::ast::Node::MacroCall {
name: "macro".to_string(),
args: vec![
hence::arg::Arg::Variable("call_word".to_string()),
hence::arg::Arg::Variable("call_word_arg_0_label".to_string()),
],
},
hence::parser::ast::Node::Call {
name: "ts".to_string(),
arg: Some(hence::arg::Arg::BinaryExpression {
left: Box::new(hence::arg::Arg::Variable("OFFSET".to_string())),
right: Box::new(hence::arg::Arg::Number(3 + 3 + 3 + 1 + 3 + 1)),
op: hence::arg::BinaryExpressionOperator::Add,
}),
},
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: "ts".to_string(),
arg: Some(hence::arg::Arg::Variable("MEM_CALL_STACK".to_string())),
},
hence::parser::ast::Node::Call {
name: "set".to_string(),
arg: None,
},
hence::parser::ast::Node::Call {
name: "ts".to_string(),
arg: Some(hence::arg::Arg::Variable(
"call_word_arg_0_label".to_string(),
)),
},
hence::parser::ast::Node::Call {
// tlr CORE_REG_PC -> tlr 0 -> tlr
name: "tlr".to_string(),
arg: Some(hence::arg::Arg::Variable("CORE_REG_PC".to_string())),
},
hence::parser::ast::Node::MacroCall {
name: "endmacro".to_string(),
args: vec![],
},
// return_word
hence::parser::ast::Node::MacroCall {
name: "macro".to_string(),
args: vec![hence::arg::Arg::Variable("return_word".to_string())],
},
hence::parser::ast::Node::MacroCall {
name: "std_get".to_string(),
args: vec![hence::arg::Arg::Variable("MEM_CALL_STACK".to_string())],
},
hence::parser::ast::Node::Call {
name: "tlr".to_string(),
arg: Some(hence::arg::Arg::Variable("CORE_REG_PC".to_string())),
},
hence::parser::ast::Node::MacroCall {
name: "endmacro".to_string(),
args: vec![],
},
// setup
hence::parser::ast::Node::MacroCall {
name: "std_rset".to_string(),
args: vec![
hence::arg::Arg::Variable("CORE_REG_A".to_string()),
hence::arg::Arg::BinaryExpression {
left: Box::new(hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string())),
right: Box::new(hence::arg::Arg::Number(1)),
op: hence::arg::BinaryExpressionOperator::Add,
},
],
},
hence::parser::ast::Node::MacroCall {
name: "std_set".to_string(),
args: vec![hence::arg::Arg::Variable("MEM_ALLOC_PTR".to_string())],
},
// jump_main
hence::parser::ast::Node::MacroCall {
name: "jump_main".to_string(),
args: vec![],
},
// data
hence::parser::ast::Node::Label("data".to_string()),
hence::parser::ast::Node::Label("data_strings".to_string()),
];
// strings
for (id, s) in self.strings.iter().enumerate() { for (id, s) in self.strings.iter().enumerate() {
x.extend([ x.extend([
hence::parser::ast::Node::Label(format!("data_strings_{}", id)), hence::parser::ast::Node::Label(format!("data_strings_{}", id)),
@ -286,7 +153,6 @@ impl Data {
} }
// words // words
x.push(hence::parser::ast::Node::Label("words".to_string()));
for (name, word) in &self for (name, word) in &self
.words .words
.iter() .iter()
@ -308,7 +174,7 @@ impl Data {
.flatten(), .flatten(),
); );
x.push(hence::parser::ast::Node::MacroCall { x.push(hence::parser::ast::Node::MacroCall {
name: "return_word".to_string(), name: "return_call_stack_jump".to_string(),
args: vec![], args: vec![],
}); });
} }
@ -326,7 +192,7 @@ impl Data {
args: vec![], args: vec![],
}); });
x Ok(x)
} }
} }
@ -344,6 +210,6 @@ pub fn compile(ast: parser::ast::AST, optimize: bool) -> Result<hence::parser::a
.into_iter() .into_iter()
.flatten() .flatten()
.collect(), .collect(),
), )?,
}) })
} }

View file

@ -66,6 +66,10 @@ pub enum Instruction {
Mod, Mod,
Call(String), Call(String),
AsmQuote(String), AsmQuote(String),
Condition {
if_instructions: Vec<Self>,
else_instructions: Vec<Self>,
},
Multiple { Multiple {
instruction: Box<Self>, instruction: Box<Self>,
@ -926,8 +930,98 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruct
arg: None, arg: None,
}, },
]), ]),
Instruction::Min => Ok(vec![]), Instruction::Min => Ok(vec![
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_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![ Instruction::Boolean => Ok(vec![
hence::parser::ast::Node::MacroCall { hence::parser::ast::Node::MacroCall {
name: "std_ld".to_string(), name: "std_ld".to_string(),
@ -1134,10 +1228,15 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruct
Instruction::Call(x) => match data.words.get(x) { Instruction::Call(x) => match data.words.get(x) {
Some(w) => { Some(w) => {
if w.times_used > 1 { if w.times_used > 1 {
Ok(vec![hence::parser::ast::Node::MacroCall { Ok(vec![
name: "call_word".to_string(), hence::parser::ast::Node::MacroCall {
args: vec![hence::arg::Arg::Variable(format!("words_{}", w.id))], name: "call_stack_jump".to_string(),
}]) args: vec![
hence::arg::Arg::Variable(format!("words_{}", w.id)),
hence::arg::Arg::Variable("OFFSET".to_string())
],
}
])
} else { } else {
Ok(w.instructions Ok(w.instructions
.iter() .iter()
@ -1153,6 +1252,23 @@ impl compiler::Compilable<compiler::Data, hence::parser::ast::Body> for Instruct
Instruction::AsmQuote(x) => { Instruction::AsmQuote(x) => {
Ok(hence::parser::parse(hence::lexer::lex(x.to_string())?)?.body) Ok(hence::parser::parse(hence::lexer::lex(x.to_string())?)?.body)
} }
Instruction::Condition {
if_instructions,
else_instructions,
} => {
let if_compiled = if_instructions
.iter()
.map(|ins| ins.compile(data))
.collect::<Result<Vec<_>>>()?;
let else_compiled = else_instructions
.iter()
.map(|ins| ins.compile(data))
.collect::<Result<Vec<_>>>()?;
dbg!(if_compiled, else_compiled);
Ok(vec![])
}
Instruction::Multiple { instruction, count } => { Instruction::Multiple { instruction, count } => {
if *count == 0 { if *count == 0 {
Ok(vec![]) Ok(vec![])
@ -1418,4 +1534,3 @@ impl Instruction {
} }
} }
} }

View file

@ -0,0 +1,64 @@
.include "$lib/core.asm"
.include "$lib/std.asm"
.include "$lib/main.asm"
.define MEM_LOOP_I, CORE_MEM_MEM
.define MEM_LOOP_J, (MEM_LOOP_I + 1)
.define MEM_CALL_STACK_PTR, (MEM_LOOP_J + 1)
.define MEM_ALLOC_PTR, (MEM_CALL_STACK_PTR + 16)
.macro stack_transfer_alu
.std_ld
tlr CORE_REG_B
.std_ld
tlr CORE_REG_A
.endmacro
.macro call_stack_jump, prep_call_stack_jump_arg_0_label, prep_call_stack_jump_arg_1_offset
.std_rset CORE_REG_C, prep_call_stack_jump_arg_0_label
.std_rset CORE_REG_D, (prep_call_stack_jump_arg_1_offset + 7)
ts call_stack_jump
tlr CORE_REG_PC
.endmacro
.macro return_call_stack_jump
.std_jump return_call_stack_jump
.endmacro
.std_rset CORE_REG_A, MEM_CALL_STACK_PTR
.std_set MEM_CALL_STACK_PTR
.std_rset CORE_REG_A, (MEM_ALLOC_PTR + 1)
.std_set MEM_ALLOC_PTR
.jump_main
call_stack_jump:
.std_get MEM_CALL_STACK_PTR
tlr CORE_REG_A
.std_rset CORE_REG_B, 1
.std_alu CORE_ALU_ADD
tlr CORE_REG_A
tlr CORE_REG_B
.std_set MEM_CALL_STACK_PTR
tsr CORE_REG_D
tlr CORE_REG_A
tsr CORE_REG_B
set
tsr CORE_REG_C
tlr CORE_REG_PC
return_call_stack_jump:
.std_get MEM_CALL_STACK_PTR
tlr CORE_REG_A
tlr CORE_REG_C
.std_rset CORE_REG_B, 1
.std_alu CORE_ALU_SUB
tlr CORE_REG_A
.std_set MEM_CALL_STACK_PTR
tsr CORE_REG_C
get
tlr CORE_REG_PC

View file

@ -100,6 +100,63 @@ pub fn parse(tokens: Vec<lexer::Token>) -> Result<ast::AST> {
body: parse(content.collect())?.body, body: parse(content.collect())?.body,
}); });
} }
"if" => {
let mut depth: usize = 1;
let mut else_used = false;
let if_toks: Vec<_> = iter
.by_ref()
.take_while(|t| match t {
lexer::Token::Word(x) => match x.as_str() {
"if" => {
depth += 1;
true
}
"else" => {
if depth == 1 {
else_used = true;
false
} else {
true
}
}
"then" => {
depth -= 1;
depth != 0
}
_ => true,
},
_ => true,
})
.collect();
let else_toks: Vec<_> = if else_used {
iter.by_ref()
.take_while(|t| match t {
lexer::Token::Word(x) => match x.as_str() {
"if" => {
depth += 1;
true
}
"then" => {
depth -= 1;
depth != 0
}
_ => true,
},
_ => true,
})
.collect()
} else {
vec![]
};
if depth != 0 {
bail!("Unbalanced conditions");
}
body.push(ast::Node::Condition {
if_body: parse(if_toks)?.body,
else_body: parse(else_toks)?.body,
});
}
_ => { _ => {
body.push(ast::Node::Word(x)); body.push(ast::Node::Word(x));
} }

View file

@ -38,6 +38,10 @@ pub enum Node {
stack: Option<StackResult>, stack: Option<StackResult>,
body: Body, body: Body,
}, },
Condition {
if_body: Body,
else_body: Body,
},
Word(String), Word(String),
} }
@ -56,6 +60,17 @@ impl ToCode for Node {
}, },
body.iter().map(|x| x.to_code()).join(" ") body.iter().map(|x| x.to_code()).join(" ")
), ),
Node::Condition { if_body, else_body } => {
if else_body.is_empty() {
format!("if {} then", if_body.iter().map(|x| x.to_code()).join(" "))
} else {
format!(
"if {} else {} then",
if_body.iter().map(|x| x.to_code()).join(" "),
else_body.iter().map(|x| x.to_code()).join(" ")
)
}
}
Node::Word(x) => x.clone(), Node::Word(x) => x.clone(),
} }
} }