[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 semantics;
pub mod tokens;

View file

@ -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<Type> {
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<Type> {
@ -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<Type> {
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<Type> {
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<Type> {
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<TreeRef>, message: &str) -> ! {
pub fn internal_compiler_error(&self, tr: Option<TreeRef>, message: &str) -> ! {
eprintln!("Internal compiler error: {message}!");
self.dump_compiler_state(tr);
panic!("INTERNAL COMPILER ERROR: {message}")