diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs new file mode 100644 index 00000000..cd6806a0 --- /dev/null +++ b/fine/src/compiler.rs @@ -0,0 +1,93 @@ +use crate::{ + parser::{Tree, TreeKind, TreeRef}, + semantics::{Semantics, Type}, + tokens::TokenKind, +}; + +// TODO: If I were cool this would by actual bytecode. +// But I'm not cool. +pub enum Instruction { + Panic, + PushFloat(f64), + PushString(usize), + PushTrue, + PushFalse, +} + +pub struct Function { + instructions: Vec, + strings: Vec, +} + +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), + 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::CallExpression => todo!(), + TreeKind::Block => todo!(), + _ => { + semantics.internal_compiler_error(Some(t), "tree is not an expression, cannot compile") + } + } +} + +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; + }; + match semantics.type_of(t) { + Type::F64 => code + .instructions + .push(Instruction::PushFloat(tok.as_str().parse().unwrap())), + Type::Bool => code.instructions.push(if tok.kind == TokenKind::True { + Instruction::PushTrue + } else { + Instruction::PushFalse + }), + Type::String => { + let index = code.strings.len(); + + // TODO: Interpret string here make good! + let mut result = String::new(); + let mut input = tok.as_str().chars(); + while let Some(ch) = input.next() { + if ch == '\\' { + if let Some(ch) = input.next() { + match ch { + 'n' => result.push('\n'), + 'r' => result.push('\r'), + 't' => result.push('\t'), + _ => result.push(ch), + } + } else { + result.push(ch) + } + } else { + result.push(ch) + } + } + code.strings.push(result); + + code.instructions.push(Instruction::PushString(index)) + } + Type::Error => code.instructions.push(Instruction::Panic), + _ => panic!("unsupported literal type: {t:?}"), + } +} + +fn compile_grouping(code: &mut Function, semantics: &Semantics, t: &Tree) { + if let Some(t) = t.nth_tree(1) { + compile_expression(code, semantics, t) + } else { + code.instructions.push(Instruction::Panic); + } +} + +pub fn compile_statement(code: &mut Function, semantics: &Semantics, t: TreeRef) {} diff --git a/fine/src/lib.rs b/fine/src/lib.rs index d2832c15..d36953aa 100644 --- a/fine/src/lib.rs +++ b/fine/src/lib.rs @@ -1,3 +1,4 @@ +pub mod compiler; pub mod parser; pub mod semantics; pub mod tokens; diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 098f60c6..b4465a4d 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -389,9 +389,7 @@ impl<'a> Semantics<'a> { }; let declaration_type = match tree.nth_tree(3) { - Some(expr) => self - .type_of(expr) - .expect("the tree in the expression should yield a type"), + Some(expr) => self.type_of(expr), // The syntax error should already have been reported, so we'll // stick with error type here. (But bind the name, because we see @@ -432,7 +430,6 @@ impl<'a> Semantics<'a> { let declaration_type = if let Some(type_expression) = param.nth_tree(2) { self.type_of(type_expression) - .expect("the type expression should yield *some* type here") } else { Type::Error }; @@ -445,17 +442,17 @@ impl<'a> Semantics<'a> { EnvironmentRef::new(environment) } - pub fn type_of(&self, t: TreeRef) -> Option { + pub fn type_of(&self, t: TreeRef) -> Type { { let state = &mut self.types.borrow_mut()[t.index()]; match state { Incremental::None => (), - Incremental::Complete(existing) => return Some(existing.clone()), + Incremental::Complete(existing) => return existing.clone(), Incremental::InProgress => { // eprintln!("type_of circular => {t:?}"); self.report_error_tree_ref(t, "The type of this expression depends on itself"); *state = Incremental::Complete(Type::Error); - return Some(Type::Error); + return Type::Error; } } *state = Incremental::InProgress; @@ -488,7 +485,7 @@ impl<'a> Semantics<'a> { let result = result.unwrap_or(Type::Error); self.types.borrow_mut()[t.index()] = Incremental::Complete(result.clone()); - Some(result) + result } fn type_of_unary(&self, tree: &Tree) -> Option { @@ -497,10 +494,7 @@ impl<'a> Semantics<'a> { let op = tree.nth_token(0)?; let expr = tree.nth_tree(1)?; - let argument_type = self - .type_of(expr) - .expect("Our argument should be an expression"); - + let argument_type = self.type_of(expr); match (op.kind, argument_type) { (TokenKind::Plus, Type::F64) => Some(Type::F64), (TokenKind::Minus, Type::F64) => Some(Type::F64), @@ -534,13 +528,9 @@ impl<'a> Semantics<'a> { fn type_of_binary(&self, tree: &Tree) -> Option { assert_eq!(tree.kind, TreeKind::BinaryExpression); - let lhs = self - .type_of(tree.nth_tree(0)?) - .expect("must be an expression"); + let lhs = self.type_of(tree.nth_tree(0)?); let op = tree.nth_token(1)?; - let rhs = self - .type_of(tree.nth_tree(2)?) - .expect("must be an expression"); + let rhs = self.type_of(tree.nth_tree(2)?); match (op.kind, lhs, rhs) { ( @@ -618,22 +608,17 @@ impl<'a> Semantics<'a> { let mut is_unreachable = false; for i in 1..last_index { // TODO: if `is_unreachable` here then we actually have - // unreachable code here! We should warn about it I guess. - - is_unreachable = self - .type_of(tree.nth_tree(i)?) - .map(|t| matches!(t, Type::Unreachable)) - .unwrap_or(false) - || is_unreachable; + // unreachable code here! We should warn about it + // I guess. + is_unreachable = + matches!(self.type_of(tree.nth_tree(i)?), Type::Unreachable) || is_unreachable; } // NOTE: If for some reason the last statement is unsuitable for a // type then we consider the type of the block to be Nothing. // (And explicitly not Error, which is what returning None // would yield.) - let last_type = self - .type_of(tree.nth_tree(last_index)?) - .unwrap_or(Type::Nothing); + let last_type = self.type_of(tree.nth_tree(last_index)?); // If anything in this block generated an "Unreachable" then the // whole type of the block is "unreachable" no matter what. @@ -660,26 +645,22 @@ impl<'a> Semantics<'a> { fn type_of_grouping(&self, tree: &Tree) -> Option { assert_eq!(tree.kind, TreeKind::GroupingExpression); - let expr = tree.nth_tree(1)?; - Some( - self.type_of(expr) - .expect("the thing in the parenthesis must have some type"), - ) + tree.nth_tree(1).map(|t| self.type_of(t)) } fn type_of_conditional(&self, tree: &Tree) -> Option { assert_eq!(tree.kind, TreeKind::ConditionalExpression); let cond_tree = tree.nth_tree(1)?; - let cond_type = self.type_of(cond_tree).expect("must be expression"); - let then_type = self.type_of(tree.nth_tree(2)?).expect("must be expression"); + let cond_type = self.type_of(cond_tree); + let then_type = self.type_of(tree.nth_tree(2)?); let has_else = tree .nth_token(3) .map(|t| t.kind == TokenKind::Else) .unwrap_or(false); let else_type = if has_else { - Some(self.type_of(tree.nth_tree(4)?).expect("must be expression")) + Some(self.type_of(tree.nth_tree(4)?)) } else { None }; @@ -731,7 +712,7 @@ impl<'a> Semantics<'a> { .map(|t| t.kind == TokenKind::Semicolon) .unwrap_or(false); - let expression_type = self.type_of(tree.nth_tree(0)?).expect("must be expression"); + let expression_type = self.type_of(tree.nth_tree(0)?); Some(match expression_type { Type::Unreachable => Type::Unreachable, _ => { @@ -802,7 +783,7 @@ impl<'a> Semantics<'a> { } } - fn internal_compiler_error(&self, tr: Option, message: &str) -> ! { + pub fn internal_compiler_error(&self, tr: Option, message: &str) -> ! { eprintln!("Internal compiler error: {message}!"); self.dump_compiler_state(tr); panic!("INTERNAL COMPILER ERROR: {message}")