[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
}

View file

@ -138,7 +138,6 @@ pub enum TreeKind {
BinaryExpression,
IfStatement,
Identifier,
PrintStatement,
}
pub struct Tree<'a> {
@ -556,32 +555,10 @@ fn statement(p: &mut CParser) {
// require a semicolon at the end if it's all by itself.
TokenKind::If => statement_if(p),
TokenKind::Print => statement_print(p),
_ => statement_expression(p),
}
}
fn statement_print(p: &mut CParser) {
assert!(p.at(TokenKind::Print));
let m = p.start();
p.expect(
TokenKind::Print,
"expect 'print' to start a print statement",
);
p.expect(TokenKind::LeftParen, "expect '(' to start a print");
if !p.at(TokenKind::RightParen) {
expression(p);
}
p.expect(TokenKind::RightParen, "expect ')' after a print statement");
if !p.at(TokenKind::RightBrace) {
p.expect(TokenKind::Semicolon, "expect ';' to end a print statement");
}
p.end(m, TreeKind::PrintStatement);
}
fn statement_if(p: &mut CParser) {
assert!(p.at(TokenKind::If));
let m = p.start();

View file

@ -49,7 +49,6 @@ pub enum TokenKind {
Import,
Let,
Or,
Print,
Return,
Select,
This,
@ -304,11 +303,6 @@ impl<'a> Tokens<'a> {
return TokenKind::Or;
}
}
'p' => {
if ident == "print" {
return TokenKind::Print;
}
}
'r' => {
if ident == "return" {
return TokenKind::Return;
@ -575,18 +569,17 @@ mod tests {
test_tokens!(
more_keywords,
"fun if import let print return select this true while truewhile",
"fun if import let return select this true while truewhile",
(0, Fun, "fun"),
(4, If, "if"),
(7, Import, "import"),
(14, Let, "let"),
(18, Print, "print"),
(24, Return, "return"),
(31, Select, "select"),
(38, This, "this"),
(43, True, "true"),
(48, While, "while"),
(54, Identifier, "truewhile")
(18, Return, "return"),
(25, Select, "select"),
(32, This, "this"),
(37, True, "true"),
(42, While, "while"),
(48, Identifier, "truewhile")
);
test_tokens!(