[fine] test compilation, start removing print
This commit is contained in:
parent
d8db65af55
commit
d8988cb2cf
8 changed files with 239 additions and 81 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue