[fine] test compilation, start removing print

This commit is contained in:
John Doty 2024-01-11 06:33:08 -08:00
parent d8db65af55
commit d8988cb2cf
8 changed files with 239 additions and 81 deletions

View file

@ -6,8 +6,34 @@ use crate::{
tokens::TokenKind,
};
macro_rules! compiler_assert_eq {
($compiler:expr, $tr:expr, $ll:expr, $rr:expr, $($t:tt)*) => {{
let left = &$ll;
let right = &$rr;
if left != right {
let semantics = $compiler.semantics;
semantics.dump_compiler_state(Some($tr));
let message = format!($($t)*);
assert_eq!(left, right, "{}", message);
}
}};
}
macro_rules! compiler_assert {
($compiler:expr, $tr:expr, $($t:tt)*) => {{
if !($($t)*) {
let semantics = $compiler.semantics;
semantics.dump_compiler_state(Some($tr));
assert!($($t)*);
}
}};
}
// TODO: If I were cool this would by actual bytecode.
// But I'm not cool.
#[derive(Debug)]
pub enum Instruction {
Panic,
@ -53,8 +79,13 @@ impl Module {
init: 0,
}
}
pub fn functions(&self) -> &[Function] {
&self.functions
}
}
// TODO: Debug information.
pub struct Function {
name: String,
instructions: Vec<Instruction>,
@ -64,12 +95,12 @@ pub struct Function {
}
impl Function {
pub fn new(name: &str) -> Self {
pub fn new(name: &str, args: usize) -> Self {
Function {
name: name.to_string(),
instructions: Vec::new(),
strings: Vec::new(),
args: 0,
args,
locals: 0,
}
}
@ -77,12 +108,29 @@ impl Function {
pub fn name(&self) -> &str {
&self.name
}
pub fn args(&self) -> usize {
self.args
}
pub fn locals(&self) -> usize {
self.locals
}
pub fn strings(&self) -> &[String] {
&self.strings
}
pub fn instructions(&self) -> &[Instruction] {
&self.instructions
}
}
struct Compiler<'a> {
semantics: &'a Semantics<'a>,
syntax: &'a SyntaxTree<'a>,
function_bindings: HashMap<String, usize>,
module: Module,
function: Function,
}
@ -114,8 +162,9 @@ pub fn compile(semantics: &Semantics) -> Module {
let mut compiler = Compiler {
semantics,
syntax: semantics.tree(),
function_bindings: HashMap::new(),
module: Module::new(),
function: Function::new("<< module >>"),
function: Function::new("<< module >>", 0),
};
if let Some(t) = semantics.tree().root() {
@ -132,7 +181,7 @@ pub fn compile(semantics: &Semantics) -> Module {
fn file(c: &mut Compiler, t: TreeRef) {
let tree = &c.syntax[t];
assert_eq!(tree.kind, TreeKind::File);
compiler_assert_eq!(c, t, tree.kind, TreeKind::File, "must be compiling a file");
for i in 0..tree.children.len() {
if let Some(t) = tree.nth_tree(i) {
compile_statement(c, t, false);
@ -306,11 +355,11 @@ fn compile_identifier_expression(c: &mut Compiler, t: TreeRef, tree: &Tree) -> O
Instruction::LoadLocal(declaration.index)
}
Location::Argument => {
assert!(declaration.index < c.function.args);
compiler_assert!(c, t, declaration.index < c.function.args);
Instruction::LoadArgument(declaration.index)
}
Location::Module => {
assert!(declaration.index < c.module.globals);
compiler_assert!(c, t, declaration.index < c.module.globals);
Instruction::LoadModule(declaration.index)
}
};
@ -398,6 +447,34 @@ fn compile_let_statement(c: &mut Compiler, t: TreeRef, tree: &Tree, gen_value: b
OK
}
fn compile_function_declaration(_c: &mut Compiler, _tree: &Tree, _gen_value: bool) -> CR {
todo!()
fn compile_function_declaration(c: &mut Compiler, tree: &Tree, gen_value: bool) -> CR {
let name = tree.nth_token(1)?;
let block = if tree
.nth_token(3)
.is_some_and(|t| t.kind == TokenKind::Arrow)
{
tree.nth_tree(4)?
} else {
tree.nth_tree(3)?
};
let arg_list = tree.nth_tree(2)?;
let arg_count = c.syntax[arg_list].children.len() - 2;
let mut prev = Function::new(name.as_str(), arg_count);
std::mem::swap(&mut c.function, &mut prev);
c.function_bindings
.insert(c.function.name.clone(), c.module.functions.len());
compile_expression(c, block);
std::mem::swap(&mut c.function, &mut prev);
c.module.functions.push(prev);
if gen_value {
c.push(Instruction::PushNothing);
}
OK
}