[fine] Garbage Compile
This commit is contained in:
parent
8d09076586
commit
6d2fd446ee
3 changed files with 113 additions and 38 deletions
93
fine/src/compiler.rs
Normal file
93
fine/src/compiler.rs
Normal 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) {}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
pub mod compiler;
|
||||
pub mod parser;
|
||||
pub mod semantics;
|
||||
pub mod tokens;
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue