[fine] Garbage Compile

This commit is contained in:
John Doty 2024-01-08 18:43:47 -08:00
parent 8d09076586
commit 6d2fd446ee
3 changed files with 113 additions and 38 deletions

93
fine/src/compiler.rs Normal file
View file

@ -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<Instruction>,
strings: Vec<String>,
}
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) {}

View file

@ -1,3 +1,4 @@
pub mod compiler;
pub mod parser; pub mod parser;
pub mod semantics; pub mod semantics;
pub mod tokens; pub mod tokens;

View file

@ -389,9 +389,7 @@ impl<'a> Semantics<'a> {
}; };
let declaration_type = match tree.nth_tree(3) { let declaration_type = match tree.nth_tree(3) {
Some(expr) => self Some(expr) => self.type_of(expr),
.type_of(expr)
.expect("the tree in the expression should yield a type"),
// The syntax error should already have been reported, so we'll // The syntax error should already have been reported, so we'll
// stick with error type here. (But bind the name, because we see // 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) { let declaration_type = if let Some(type_expression) = param.nth_tree(2) {
self.type_of(type_expression) self.type_of(type_expression)
.expect("the type expression should yield *some* type here")
} else { } else {
Type::Error Type::Error
}; };
@ -445,17 +442,17 @@ impl<'a> Semantics<'a> {
EnvironmentRef::new(environment) EnvironmentRef::new(environment)
} }
pub fn type_of(&self, t: TreeRef) -> Option<Type> { pub fn type_of(&self, t: TreeRef) -> Type {
{ {
let state = &mut self.types.borrow_mut()[t.index()]; let state = &mut self.types.borrow_mut()[t.index()];
match state { match state {
Incremental::None => (), Incremental::None => (),
Incremental::Complete(existing) => return Some(existing.clone()), Incremental::Complete(existing) => return existing.clone(),
Incremental::InProgress => { Incremental::InProgress => {
// eprintln!("type_of circular => {t:?}"); // eprintln!("type_of circular => {t:?}");
self.report_error_tree_ref(t, "The type of this expression depends on itself"); self.report_error_tree_ref(t, "The type of this expression depends on itself");
*state = Incremental::Complete(Type::Error); *state = Incremental::Complete(Type::Error);
return Some(Type::Error); return Type::Error;
} }
} }
*state = Incremental::InProgress; *state = Incremental::InProgress;
@ -488,7 +485,7 @@ impl<'a> Semantics<'a> {
let result = result.unwrap_or(Type::Error); let result = result.unwrap_or(Type::Error);
self.types.borrow_mut()[t.index()] = Incremental::Complete(result.clone()); self.types.borrow_mut()[t.index()] = Incremental::Complete(result.clone());
Some(result) result
} }
fn type_of_unary(&self, tree: &Tree) -> Option<Type> { fn type_of_unary(&self, tree: &Tree) -> Option<Type> {
@ -497,10 +494,7 @@ impl<'a> Semantics<'a> {
let op = tree.nth_token(0)?; let op = tree.nth_token(0)?;
let expr = tree.nth_tree(1)?; let expr = tree.nth_tree(1)?;
let argument_type = self let argument_type = self.type_of(expr);
.type_of(expr)
.expect("Our argument should be an expression");
match (op.kind, argument_type) { match (op.kind, argument_type) {
(TokenKind::Plus, Type::F64) => Some(Type::F64), (TokenKind::Plus, Type::F64) => Some(Type::F64),
(TokenKind::Minus, 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<Type> { fn type_of_binary(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::BinaryExpression); assert_eq!(tree.kind, TreeKind::BinaryExpression);
let lhs = self let lhs = self.type_of(tree.nth_tree(0)?);
.type_of(tree.nth_tree(0)?)
.expect("must be an expression");
let op = tree.nth_token(1)?; let op = tree.nth_token(1)?;
let rhs = self let rhs = self.type_of(tree.nth_tree(2)?);
.type_of(tree.nth_tree(2)?)
.expect("must be an expression");
match (op.kind, lhs, rhs) { match (op.kind, lhs, rhs) {
( (
@ -618,22 +608,17 @@ impl<'a> Semantics<'a> {
let mut is_unreachable = false; let mut is_unreachable = false;
for i in 1..last_index { for i in 1..last_index {
// TODO: if `is_unreachable` here then we actually have // TODO: if `is_unreachable` here then we actually have
// unreachable code here! We should warn about it I guess. // unreachable code here! We should warn about it
// I guess.
is_unreachable = self is_unreachable =
.type_of(tree.nth_tree(i)?) matches!(self.type_of(tree.nth_tree(i)?), Type::Unreachable) || is_unreachable;
.map(|t| matches!(t, Type::Unreachable))
.unwrap_or(false)
|| is_unreachable;
} }
// NOTE: If for some reason the last statement is unsuitable for a // NOTE: If for some reason the last statement is unsuitable for a
// type then we consider the type of the block to be Nothing. // type then we consider the type of the block to be Nothing.
// (And explicitly not Error, which is what returning None // (And explicitly not Error, which is what returning None
// would yield.) // would yield.)
let last_type = self let last_type = self.type_of(tree.nth_tree(last_index)?);
.type_of(tree.nth_tree(last_index)?)
.unwrap_or(Type::Nothing);
// If anything in this block generated an "Unreachable" then the // If anything in this block generated an "Unreachable" then the
// whole type of the block is "unreachable" no matter what. // 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<Type> { fn type_of_grouping(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::GroupingExpression); assert_eq!(tree.kind, TreeKind::GroupingExpression);
let expr = tree.nth_tree(1)?; tree.nth_tree(1).map(|t| self.type_of(t))
Some(
self.type_of(expr)
.expect("the thing in the parenthesis must have some type"),
)
} }
fn type_of_conditional(&self, tree: &Tree) -> Option<Type> { fn type_of_conditional(&self, tree: &Tree) -> Option<Type> {
assert_eq!(tree.kind, TreeKind::ConditionalExpression); assert_eq!(tree.kind, TreeKind::ConditionalExpression);
let cond_tree = tree.nth_tree(1)?; let cond_tree = tree.nth_tree(1)?;
let cond_type = self.type_of(cond_tree).expect("must be expression"); let cond_type = self.type_of(cond_tree);
let then_type = self.type_of(tree.nth_tree(2)?).expect("must be expression"); let then_type = self.type_of(tree.nth_tree(2)?);
let has_else = tree let has_else = tree
.nth_token(3) .nth_token(3)
.map(|t| t.kind == TokenKind::Else) .map(|t| t.kind == TokenKind::Else)
.unwrap_or(false); .unwrap_or(false);
let else_type = if has_else { 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 { } else {
None None
}; };
@ -731,7 +712,7 @@ impl<'a> Semantics<'a> {
.map(|t| t.kind == TokenKind::Semicolon) .map(|t| t.kind == TokenKind::Semicolon)
.unwrap_or(false); .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 { Some(match expression_type {
Type::Unreachable => Type::Unreachable, Type::Unreachable => Type::Unreachable,
_ => { _ => {
@ -802,7 +783,7 @@ impl<'a> Semantics<'a> {
} }
} }
fn internal_compiler_error(&self, tr: Option<TreeRef>, message: &str) -> ! { pub fn internal_compiler_error(&self, tr: Option<TreeRef>, message: &str) -> ! {
eprintln!("Internal compiler error: {message}!"); eprintln!("Internal compiler error: {message}!");
self.dump_compiler_state(tr); self.dump_compiler_state(tr);
panic!("INTERNAL COMPILER ERROR: {message}") panic!("INTERNAL COMPILER ERROR: {message}")