diff --git a/fine/build.rs b/fine/build.rs index 97a76612..2491adf6 100644 --- a/fine/build.rs +++ b/fine/build.rs @@ -10,7 +10,6 @@ fn generate_test_for_file(path: PathBuf) -> String { let display_path = path.display().to_string(); // Start iterating over lines and processing directives.... - let mut disabled = quote! {}; let mut assertions = Vec::new(); let mut lines = contents.lines(); while let Some(line) = lines.next() { @@ -20,9 +19,7 @@ fn generate_test_for_file(path: PathBuf) -> String { }; let line = line.trim(); - if line == "@disabled" { - disabled = quote! { #[ignore] }; - } else if line == "@concrete:" { + if line == "@concrete:" { let mut concrete = String::new(); while let Some(line) = lines.next() { let line = match line.strip_prefix("// | ") { @@ -68,7 +65,6 @@ fn generate_test_for_file(path: PathBuf) -> String { let name = format_ident!("{}", path.file_stem().unwrap().to_string_lossy()); let test_method = quote! { - #disabled fn #name() { let (_tree, _lines) = fine::parser::parse(#contents); #(#assertions)* diff --git a/fine/src/compiler.rs b/fine/src/compiler.rs index 59c19d4a..cd6806a0 100644 --- a/fine/src/compiler.rs +++ b/fine/src/compiler.rs @@ -1,6 +1,6 @@ use crate::{ parser::{Tree, TreeKind, TreeRef}, - semantics::{Location, Semantics, Type}, + semantics::{Semantics, Type}, tokens::TokenKind, }; @@ -8,25 +8,10 @@ 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, - StoreLocal(usize), + PushFalse, } pub struct Function { @@ -34,32 +19,29 @@ 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]; - let cr = match tree.kind { - TreeKind::Error => None, + 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 => 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::UnaryExpression => todo!(), + TreeKind::ConditionalExpression => todo!(), + TreeKind::BinaryExpression => todo!(), + TreeKind::Identifier => todo!(), TreeKind::CallExpression => todo!(), - TreeKind::Block => compile_block_expression(code, semantics, tree), + TreeKind::Block => todo!(), _ => { 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) -> CR { - let tok = tr.nth_token(0)?; +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 @@ -97,226 +79,15 @@ 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) -> 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); +fn compile_grouping(code: &mut Function, semantics: &Semantics, t: &Tree) { + if let Some(t) = t.nth_tree(1) { + compile_expression(code, semantics, t) } 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); } } -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!() -} +pub fn compile_statement(code: &mut Function, semantics: &Semantics, t: TreeRef) {} diff --git a/fine/src/semantics.rs b/fine/src/semantics.rs index 9ff7bda1..b4465a4d 100644 --- a/fine/src/semantics.rs +++ b/fine/src/semantics.rs @@ -121,48 +121,23 @@ 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, location: Location, base_index: usize) -> Self { + pub fn new(parent: Option) -> 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); @@ -285,7 +260,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, Location::Module, 0)), + empty_environment: EnvironmentRef::new(Environment::new(None)), }; // NOTE: We ensure all the known errors are reported before we move @@ -422,13 +397,10 @@ impl<'a> Semantics<'a> { None => Type::Error, }; - 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); + let mut environment = Environment::new(Some(parent)); + environment + .declarations + .insert(name.as_str().into(), Declaration { declaration_type }); EnvironmentRef::new(environment) } @@ -442,7 +414,7 @@ impl<'a> Semantics<'a> { return parent; // SE } - let mut environment = Environment::new(Some(parent), Location::Argument, 0); + let mut environment = Environment::new(Some(parent)); for child in param_list.children.iter() { let Child::Tree(ct) = child else { continue; @@ -462,7 +434,9 @@ impl<'a> Semantics<'a> { Type::Error }; - environment.insert(param_name, declaration_type); + environment + .declarations + .insert(param_name.as_str().into(), Declaration { declaration_type }); } EnvironmentRef::new(environment) diff --git a/fine/tests/README.md b/fine/tests/README.md index e228e6cb..62bedeec 100644 --- a/fine/tests/README.md +++ b/fine/tests/README.md @@ -37,8 +37,6 @@ e.g., a test might look like this: The various assertions are as follows: -- The `// @disabled` directive marks the test as ignored. - - The `// @concrete:` assertion says that the following lines (prefixed with `// | `, as above) describe the concrete syntax tree of the file after parsing. diff --git a/fine/tests/example_tests.rs b/fine/tests/example_tests.rs index f25af7ed..21aa523d 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); + let actual = format!("{}", tree_type.unwrap_or(Type::Error)); 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, Type::Error), + matches!(tree_type, Some(Type::Error)), "The type of the {:?} tree at position {pos} was '{tree_type:?}', not an error", tree[tree_ref].kind ); diff --git a/fine/tests/expression/empty_statement.fine b/fine/tests/expression/empty_statement.fine deleted file mode 100644 index 710bef3d..00000000 --- a/fine/tests/expression/empty_statement.fine +++ /dev/null @@ -1,5 +0,0 @@ -// @disabled -// @concrete: -// | - -;