From d14c9a72dfd4d0ede121afe01b6fd1ed6aeefc0d Mon Sep 17 00:00:00 2001 From: John Doty Date: Mon, 8 Jan 2024 22:30:34 -0800 Subject: [PATCH] [fine] Fully untested compiler --- fine/src/compiler.rs | 267 +++++++++++++++++++++++++++++++++--- fine/src/semantics.rs | 46 +++++-- fine/tests/example_tests.rs | 4 +- 3 files changed, 286 insertions(+), 31 deletions(-) diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index cd6806a0..59c19d4a 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -1,6 +1,6 @@ use crate::{ parser::{Tree, TreeKind, TreeRef}, - semantics::{Semantics, Type}, + semantics::{Location, Semantics, Type}, tokens::TokenKind, }; @@ -8,10 +8,25 @@ use crate::{ // But I'm not cool. pub enum Instruction { Panic, + + BoolNot, + Discard, + FloatAdd, + FloatDivide, + FloatMultiply, + FloatSubtract, + Jump(usize), + JumpFalse(usize), + JumpTrue(usize), + LoadArgument(usize), + LoadLocal(usize), + LoadModule(usize), + PushFalse, PushFloat(f64), + PushNothing, PushString(usize), PushTrue, - PushFalse, + StoreLocal(usize), } pub struct Function { @@ -19,29 +34,32 @@ pub struct Function { strings: Vec, } +type CR = Option<()>; +const OK: CR = CR::Some(()); + pub fn compile_expression(code: &mut Function, semantics: &Semantics, t: TreeRef) { let tree = &semantics.tree()[t]; - match tree.kind { - TreeKind::Error => code.instructions.push(Instruction::Panic), + let cr = match tree.kind { + TreeKind::Error => None, TreeKind::LiteralExpression => compile_literal(code, semantics, t, tree), TreeKind::GroupingExpression => compile_grouping(code, semantics, tree), - TreeKind::UnaryExpression => todo!(), - TreeKind::ConditionalExpression => todo!(), - TreeKind::BinaryExpression => todo!(), - TreeKind::Identifier => todo!(), + TreeKind::UnaryExpression => compile_unary_operator(code, semantics, tree), + TreeKind::ConditionalExpression => compile_condition_expression(code, semantics, tree), + TreeKind::BinaryExpression => compile_binary_expression(code, semantics, tree), + TreeKind::Identifier => compile_identifier_expression(code, semantics, t, tree), TreeKind::CallExpression => todo!(), - TreeKind::Block => todo!(), + TreeKind::Block => compile_block_expression(code, semantics, tree), _ => { semantics.internal_compiler_error(Some(t), "tree is not an expression, cannot compile") } + }; + if matches!(cr, None) { + code.instructions.push(Instruction::Panic); } } -fn compile_literal(code: &mut Function, semantics: &Semantics, t: TreeRef, tr: &Tree) { - let Some(tok) = tr.nth_token(0) else { - code.instructions.push(Instruction::Panic); - return; - }; +fn compile_literal(code: &mut Function, semantics: &Semantics, t: TreeRef, tr: &Tree) -> CR { + let tok = tr.nth_token(0)?; match semantics.type_of(t) { Type::F64 => code .instructions @@ -79,15 +97,226 @@ fn compile_literal(code: &mut Function, semantics: &Semantics, t: TreeRef, tr: & } Type::Error => code.instructions.push(Instruction::Panic), _ => panic!("unsupported literal type: {t:?}"), - } + }; + OK } -fn compile_grouping(code: &mut Function, semantics: &Semantics, t: &Tree) { - if let Some(t) = t.nth_tree(1) { - compile_expression(code, semantics, t) +fn compile_grouping(code: &mut Function, semantics: &Semantics, t: &Tree) -> CR { + compile_expression(code, semantics, t.nth_tree(1)?); + OK +} + +fn compile_unary_operator(code: &mut Function, semantics: &Semantics, t: &Tree) -> CR { + compile_expression(code, semantics, t.nth_tree(1)?); + + let tok = t.nth_token(0)?; + match tok.kind { + TokenKind::Minus => { + code.instructions.push(Instruction::PushFloat(-1.0)); + code.instructions.push(Instruction::FloatMultiply); + } + TokenKind::Bang => { + code.instructions.push(Instruction::BoolNot); + } + _ => panic!("unsupported unary operator"), + } + OK +} + +fn compile_condition_expression(code: &mut Function, semantics: &Semantics, t: &Tree) -> CR { + let condition = t.nth_tree(1)?; + compile_expression(code, semantics, condition); + + let jump_else_index = code.instructions.len(); + code.instructions.push(Instruction::JumpFalse(0)); + + let then_branch = t.nth_tree(2)?; + compile_expression(code, semantics, then_branch); + + if let Some(else_branch) = t.nth_tree(4) { + let jump_end_index = code.instructions.len(); + code.instructions.push(Instruction::Jump(0)); + + let else_index = code.instructions.len(); + code.instructions[jump_else_index] = Instruction::JumpFalse(else_index); + + compile_expression(code, semantics, else_branch); + + let end_index = code.instructions.len(); + code.instructions[jump_end_index] = Instruction::Jump(end_index); } else { + let else_index = code.instructions.len(); + code.instructions[jump_else_index] = Instruction::JumpFalse(else_index); + } + OK +} + +fn compile_binary_expression(code: &mut Function, semantics: &Semantics, t: &Tree) -> CR { + compile_expression(code, semantics, t.nth_tree(0)?); + match t.nth_token(1)?.kind { + TokenKind::Plus => { + compile_expression(code, semantics, t.nth_tree(2)?); + code.instructions.push(Instruction::FloatAdd); + } + TokenKind::Minus => { + compile_expression(code, semantics, t.nth_tree(2)?); + code.instructions.push(Instruction::FloatSubtract); + } + TokenKind::Star => { + compile_expression(code, semantics, t.nth_tree(2)?); + code.instructions.push(Instruction::FloatMultiply); + } + TokenKind::Slash => { + compile_expression(code, semantics, t.nth_tree(2)?); + code.instructions.push(Instruction::FloatDivide); + } + TokenKind::And => { + let jump_false_index = code.instructions.len(); + code.instructions.push(Instruction::JumpFalse(0)); + code.instructions.push(Instruction::PushTrue); + + let jump_end_index = code.instructions.len(); + code.instructions.push(Instruction::Jump(0)); + + let false_index = code.instructions.len(); + code.instructions[jump_false_index] = Instruction::JumpFalse(false_index); + + compile_expression(code, semantics, t.nth_tree(2)?); + + let end_index = code.instructions.len(); + code.instructions[jump_end_index] = Instruction::Jump(end_index); + } + TokenKind::Or => { + let jump_true_index = code.instructions.len(); + code.instructions.push(Instruction::JumpTrue(0)); + code.instructions.push(Instruction::PushTrue); + + let jump_end_index = code.instructions.len(); + code.instructions.push(Instruction::Jump(0)); + + let true_index = code.instructions.len(); + code.instructions[jump_true_index] = Instruction::JumpTrue(true_index); + + compile_expression(code, semantics, t.nth_tree(2)?); + + let end_index = code.instructions.len(); + code.instructions[jump_end_index] = Instruction::Jump(end_index); + } + _ => panic!("Unsupported binary expression"), + } + OK +} + +fn compile_identifier_expression( + code: &mut Function, + semantics: &Semantics, + t: TreeRef, + tree: &Tree, +) -> Option<()> { + let ident = tree.nth_token(0)?; + let environment = semantics.environment_of(t); + let declaration = environment.bind(ident)?; + + let instruction = match declaration.location { + Location::Local => Instruction::LoadLocal(declaration.index), + Location::Argument => Instruction::LoadArgument(declaration.index), + Location::Module => Instruction::LoadModule(declaration.index), + }; + code.instructions.push(instruction); + + OK +} + +fn compile_block_expression(code: &mut Function, semantics: &Semantics, tree: &Tree) -> Option<()> { + let last_is_brace = tree.nth_token(tree.children.len() - 1).is_some(); + let last_index = tree.children.len() - if last_is_brace { 2 } else { 1 }; + + for i in 1..last_index { + compile_statement(code, semantics, tree.nth_tree(i)?, false); + } + compile_statement(code, semantics, tree.nth_tree(last_index)?, true); + OK +} + +pub fn compile_statement(code: &mut Function, semantics: &Semantics, t: TreeRef, gen_value: bool) { + let tree = &semantics.tree()[t]; + let cr = match tree.kind { + TreeKind::FunctionDecl => compile_function_declaration(code, semantics, tree, gen_value), + TreeKind::LetStatement => compile_let_statement(code, semantics, t, tree, gen_value), + TreeKind::ExpressionStatement => { + compile_expression_statement(code, semantics, tree, gen_value) + } + TreeKind::IfStatement => compile_if_statement(code, semantics, tree, gen_value), + _ => panic!("unsupported tree kind {:?}", tree.kind), + }; + if matches!(cr, None) { code.instructions.push(Instruction::Panic); } } -pub fn compile_statement(code: &mut Function, semantics: &Semantics, t: TreeRef) {} +fn compile_if_statement( + code: &mut Function, + semantics: &Semantics, + tree: &Tree, + gen_value: bool, +) -> CR { + compile_expression(code, semantics, tree.nth_tree(0)?); + if !gen_value { + code.instructions.push(Instruction::Discard); + } + + OK +} + +fn compile_expression_statement( + code: &mut Function, + semantics: &Semantics, + tree: &Tree, + gen_value: bool, +) -> CR { + compile_expression(code, semantics, tree.nth_tree(0)?); + if tree + .nth_token(1) + .is_some_and(|t| t.kind == TokenKind::Semicolon) + { + code.instructions.push(Instruction::Discard); + if gen_value { + code.instructions.push(Instruction::PushNothing); + } + } else if !gen_value { + code.instructions.push(Instruction::Discard); + } + + OK +} + +fn compile_let_statement( + code: &mut Function, + semantics: &Semantics, + t: TreeRef, + tree: &Tree, + gen_value: bool, +) -> CR { + compile_expression(code, semantics, tree.nth_tree(3)?); + let environment = semantics.environment_of(t); + let declaration = environment.bind(tree.nth_token(1)?)?; + + // NOTE: Because this is a let statement I assume it's local! + assert!(matches!(declaration.location, Location::Local)); + code.instructions + .push(Instruction::StoreLocal(declaration.index)); + if gen_value { + code.instructions.push(Instruction::PushNothing); + } + + OK +} + +fn compile_function_declaration( + _code: &mut Function, + _semantics: &Semantics, + _tree: &Tree, + _gen_value: bool, +) -> CR { + todo!() +} diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index b4465a4d..9ff7bda1 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -121,23 +121,48 @@ impl fmt::Display for Type { } } +#[derive(Clone, Copy)] +pub enum Location { + Argument, + Local, + Module, +} + pub struct Declaration { pub declaration_type: Type, + pub location: Location, + pub index: usize, } pub struct Environment { pub parent: Option, + pub location: Location, + pub base_index: usize, pub declarations: HashMap, Declaration>, } impl Environment { - pub fn new(parent: Option) -> Self { + pub fn new(parent: Option, location: Location, base_index: usize) -> Self { Environment { parent, + location, + base_index, declarations: HashMap::new(), } } + pub fn insert(&mut self, token: &Token, t: Type) { + let index = self.base_index + self.declarations.len(); + self.declarations.insert( + token.as_str().into(), + Declaration { + declaration_type: t, + location: self.location, + index, + }, + ); + } + pub fn bind(&self, token: &Token) -> Option<&Declaration> { if let Some(decl) = self.declarations.get(token.as_str()) { return Some(decl); @@ -260,7 +285,7 @@ impl<'a> Semantics<'a> { errors: RefCell::new(vec![]), types: RefCell::new(vec![Incremental::None; tree.len()]), environments: RefCell::new(vec![Incremental::None; tree.len()]), - empty_environment: EnvironmentRef::new(Environment::new(None)), + empty_environment: EnvironmentRef::new(Environment::new(None, Location::Module, 0)), }; // NOTE: We ensure all the known errors are reported before we move @@ -397,10 +422,13 @@ impl<'a> Semantics<'a> { None => Type::Error, }; - let mut environment = Environment::new(Some(parent)); - environment - .declarations - .insert(name.as_str().into(), Declaration { declaration_type }); + let base_index = match parent.location { + Location::Local => parent.base_index + parent.declarations.len(), + _ => 0, + }; + + let mut environment = Environment::new(Some(parent), Location::Local, base_index); + environment.insert(name, declaration_type); EnvironmentRef::new(environment) } @@ -414,7 +442,7 @@ impl<'a> Semantics<'a> { return parent; // SE } - let mut environment = Environment::new(Some(parent)); + let mut environment = Environment::new(Some(parent), Location::Argument, 0); for child in param_list.children.iter() { let Child::Tree(ct) = child else { continue; @@ -434,9 +462,7 @@ impl<'a> Semantics<'a> { Type::Error }; - environment - .declarations - .insert(param_name.as_str().into(), Declaration { declaration_type }); + environment.insert(param_name, declaration_type); } EnvironmentRef::new(environment) diff --git a/fine/tests/example_tests.rs b/fine/tests/example_tests.rs index 21aa523d..f25af7ed 100644 --- a/fine/tests/example_tests.rs +++ b/fine/tests/example_tests.rs @@ -136,7 +136,7 @@ fn assert_type_at( }; let tree_type = semantics.type_of(tree_ref); - let actual = format!("{}", tree_type.unwrap_or(Type::Error)); + let actual = format!("{}", tree_type); semantic_assert_eq!( &semantics, Some(tree_ref), @@ -167,7 +167,7 @@ fn assert_type_error_at( semantic_assert!( &semantics, Some(tree_ref), - matches!(tree_type, Some(Type::Error)), + matches!(tree_type, Type::Error), "The type of the {:?} tree at position {pos} was '{tree_type:?}', not an error", tree[tree_ref].kind );