Update henceforth
This commit is contained in:
parent
d6f7a51e11
commit
cdd5b8855a
14 changed files with 683 additions and 314 deletions
|
@ -6,20 +6,21 @@ use std::collections::HashMap;
|
|||
|
||||
use crate::parser;
|
||||
|
||||
mod instruction;
|
||||
pub mod instruction;
|
||||
pub mod templates;
|
||||
|
||||
pub use instruction::Instruction;
|
||||
|
||||
pub const TEMPLATE_ASM: &str = include_str!("compiler/templates/default.asm");
|
||||
// pub const TEMPLATE_ASM: &str = include_str!("compiler/templates/default.asm");
|
||||
|
||||
lazy_static! {
|
||||
#[derive(Debug)]
|
||||
pub static ref TEMPLATE: hence::parser::ast::Body = hence::parser::parse(
|
||||
hence::lexer::lex(TEMPLATE_ASM).unwrap()
|
||||
)
|
||||
.unwrap()
|
||||
.body;
|
||||
}
|
||||
// lazy_static! {
|
||||
// #[derive(Debug)]
|
||||
// pub static ref TEMPLATE: hence::parser::ast::Body = hence::parser::parse(
|
||||
// hence::lexer::lex(TEMPLATE_ASM).unwrap()
|
||||
// )
|
||||
// .unwrap()
|
||||
// .body;
|
||||
// }
|
||||
|
||||
pub trait Compilable<T, U> {
|
||||
fn compile(&self, data: &T) -> Result<U>;
|
||||
|
@ -54,8 +55,6 @@ pub struct Compiler {
|
|||
impl Compiler {
|
||||
pub fn default() -> Self {
|
||||
Self {
|
||||
// words: HashMap::new(),
|
||||
// conditions: IndexSet::new(),
|
||||
strings: IndexSet::new(),
|
||||
words: HashMap::new(),
|
||||
conditions: vec![],
|
||||
|
@ -123,22 +122,16 @@ impl Compiler {
|
|||
);
|
||||
}
|
||||
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.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);
|
||||
let if_instructions = self.generate_instructions(if_body, optimize)?;
|
||||
let else_instructions = self.generate_instructions(else_body, optimize)?;
|
||||
let id = self.conditions.len();
|
||||
self.conditions.push(Condition {
|
||||
if_instructions: if_instructions.clone(),
|
||||
else_instructions: else_instructions.clone(),
|
||||
});
|
||||
instructions.push(Instruction::Condition(id));
|
||||
}
|
||||
parser::ast::Node::Word(x) => {
|
||||
dbg!(&self.words, &x);
|
||||
if let Some(ins) = Instruction::from_word(&x) {
|
||||
instructions.push(ins);
|
||||
} else if let Some(w) = self.words.get_mut(&x) {
|
||||
|
@ -154,106 +147,162 @@ impl Compiler {
|
|||
Ok(instructions)
|
||||
}
|
||||
|
||||
pub fn embed(&self, body: hence::parser::ast::Body) -> Result<hence::parser::ast::Body> {
|
||||
let mut x = TEMPLATE.to_vec();
|
||||
pub fn embed(&self, body: hence::parser::ast::Body) -> Result<String> {
|
||||
let strings = self
|
||||
.strings
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(id, s)| templates::IdLike {
|
||||
id,
|
||||
data: s.to_owned(),
|
||||
})
|
||||
.collect();
|
||||
dbg!(&self.strings);
|
||||
// for (id, s) in self.strings.iter().enumerate() {
|
||||
// x.extend([
|
||||
// hence::parser::ast::Node::Label(format!("data_strings_{}", id)),
|
||||
// hence::parser::ast::Node::MacroCall {
|
||||
// name: "bytes".to_string(),
|
||||
// args: vec![hence::arg::Arg::String(s.to_string())],
|
||||
// },
|
||||
// hence::parser::ast::Node::Label(format!("data_strings_end_{}", id)),
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// strings
|
||||
for (id, s) in self.strings.iter().enumerate() {
|
||||
x.extend([
|
||||
hence::parser::ast::Node::Label(format!("data_strings_{}", id)),
|
||||
hence::parser::ast::Node::MacroCall {
|
||||
name: "bytes".to_string(),
|
||||
args: vec![hence::arg::Arg::String(s.to_string())],
|
||||
},
|
||||
hence::parser::ast::Node::Label(format!("data_strings_end_{}", id)),
|
||||
]);
|
||||
}
|
||||
// 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(),
|
||||
// );
|
||||
// }
|
||||
let conditions = self
|
||||
.conditions
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(id, c)| {
|
||||
Ok(templates::IdLike {
|
||||
id,
|
||||
data: (
|
||||
c.if_instructions
|
||||
.iter()
|
||||
.map(|ins| ins.compile(self))
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
c.else_instructions
|
||||
.iter()
|
||||
.map(|ins| ins.compile(self))
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
),
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
// 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(),
|
||||
);
|
||||
}
|
||||
|
||||
// words
|
||||
for (name, word) in &self
|
||||
// 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![],
|
||||
// });
|
||||
// }
|
||||
let words = 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![],
|
||||
});
|
||||
.map(|(name, w)| {
|
||||
Ok(templates::IdLike {
|
||||
id: w.id,
|
||||
data: (
|
||||
name.to_owned(),
|
||||
w.instructions
|
||||
.iter()
|
||||
.map(|ins| ins.compile(self))
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
),
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
// x.extend([
|
||||
// hence::parser::ast::Node::Label("main".to_string()),
|
||||
// hence::parser::ast::Node::MacroCall {
|
||||
// name: "main".to_string(),
|
||||
// args: vec![hence::arg::Arg::Variable("main".to_string())],
|
||||
// },
|
||||
// ]);
|
||||
// x.extend(body);
|
||||
// x.push(hence::parser::ast::Node::MacroCall {
|
||||
// name: "std_stop".to_string(),
|
||||
// args: vec![],
|
||||
// });
|
||||
|
||||
Ok(templates::DefaultTemplate {
|
||||
strings,
|
||||
conditions,
|
||||
words,
|
||||
main: body,
|
||||
}
|
||||
|
||||
x.extend([
|
||||
hence::parser::ast::Node::Label("main".to_string()),
|
||||
hence::parser::ast::Node::MacroCall {
|
||||
name: "main".to_string(),
|
||||
args: vec![hence::arg::Arg::Variable("main".to_string())],
|
||||
},
|
||||
]);
|
||||
x.extend(body);
|
||||
x.push(hence::parser::ast::Node::MacroCall {
|
||||
name: "std_stop".to_string(),
|
||||
args: vec![],
|
||||
});
|
||||
|
||||
Ok(x)
|
||||
.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(ast: parser::ast::AST, optimize: bool) -> Result<hence::parser::ast::AST> {
|
||||
pub fn compile(ast: parser::ast::AST, optimize: bool) -> Result<String> {
|
||||
let mut data = Compiler::default();
|
||||
let instructions = data.generate_instructions(ast.body, optimize)?;
|
||||
|
||||
Ok(hence::parser::ast::AST {
|
||||
body: data.embed(
|
||||
instructions
|
||||
.iter()
|
||||
.map(|ins| ins.compile(&data))
|
||||
.collect::<Result<Vec<hence::parser::ast::Body>>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
)?,
|
||||
})
|
||||
Ok(data.embed(
|
||||
instructions
|
||||
.iter()
|
||||
.map(|ins| ins.compile(&data))
|
||||
.collect::<Result<Vec<hence::parser::ast::Body>>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
)?)
|
||||
}
|
||||
|
|
|
@ -1249,7 +1249,7 @@ impl compiler::Compilable<compiler::Compiler, hence::parser::ast::Body> for Inst
|
|||
Instruction::AsmQuote(x) => Ok(hence::parser::parse(hence::lexer::lex(x)?)?.body),
|
||||
// Instruction::Condition(x) => Ok(vec![]),
|
||||
Instruction::Condition(x) => {
|
||||
dbg!(x);
|
||||
// dbg!(x);
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
|
|
16
henceforth/src/compiler/templates.rs
Normal file
16
henceforth/src/compiler/templates.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
use askama::Template;
|
||||
use hence::assembler::ToCode;
|
||||
|
||||
pub struct IdLike<T, U> {
|
||||
pub id: T,
|
||||
pub data: U,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "default.asm", escape = "none")]
|
||||
pub struct DefaultTemplate {
|
||||
pub strings: Vec<IdLike<usize, String>>,
|
||||
pub conditions: Vec<IdLike<usize, (hence::parser::ast::Body, hence::parser::ast::Body)>>,
|
||||
pub words: Vec<IdLike<usize, (String, hence::parser::ast::Body)>>,
|
||||
pub main: hence::parser::ast::Body,
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
.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_LEN, 16
|
||||
.define MEM_CALL_STACK_PTR, (MEM_LOOP_J + 1)
|
||||
.define MEM_CALL_STACK_END, (MEM_CALL_STACK_PTR + MEM_CALL_STACK_LEN)
|
||||
|
||||
.define MEM_ALLOC_PTR, MEM_CALL_STACK_END
|
||||
|
||||
.macro stack_transfer_alu
|
||||
.std_ld
|
||||
tlr CORE_REG_B
|
||||
.std_ld
|
||||
tlr CORE_REG_A
|
||||
.endmacro
|
||||
|
||||
.macro call_stack_jump, call_stack_jump_arg_0_label, call_stack_jump_arg_1_offset
|
||||
.std_rset CORE_REG_C, call_stack_jump_arg_0_label
|
||||
.std_rset CORE_REG_D, (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
|
|
@ -1,6 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use hence::assembler::ToCode;
|
||||
use std::fs;
|
||||
|
||||
use henceforth::*;
|
||||
|
@ -64,8 +63,7 @@ fn main() -> Result<()> {
|
|||
let source = fs::read_to_string(&src)?;
|
||||
let tokens = lexer::lex(&source)?;
|
||||
let ast = parser::parse(tokens)?;
|
||||
let ast = compiler::compile(ast, optimize.unwrap_or(true))?;
|
||||
let assembly = format!("{}\n", ast.to_code());
|
||||
let assembly = format!("{}\n", compiler::compile(ast, optimize.unwrap_or(true))?);
|
||||
|
||||
if dump {
|
||||
print!("{}", assembly);
|
||||
|
|
|
@ -36,7 +36,10 @@ pub fn parse(tokens: Vec<lexer::Token>) -> Result<ast::AST> {
|
|||
body.push(ast::Node::Comment(x.trim().to_string()));
|
||||
}
|
||||
lexer::Token::StringLiteral { mode, string } => {
|
||||
body.push(ast::Node::String { mode, string });
|
||||
body.push(ast::Node::String {
|
||||
mode,
|
||||
string: snailquote::unescape(&format!("\"{}\"", string))?,
|
||||
});
|
||||
}
|
||||
lexer::Token::Number(x) => body.push(ast::Node::Number(parse_int::parse(&x)?)),
|
||||
lexer::Token::Word(x) => match x.as_str() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue