diff options
| author | Cody <cody@codyq.dev> | 2023-06-19 03:38:41 -0500 |
|---|---|---|
| committer | Cody <cody@codyq.dev> | 2023-06-19 03:38:41 -0500 |
| commit | c22410c6f334497a404f0b708ae94be527a8f0ee (patch) | |
| tree | 0ce2ead405e647d6636873d3a7f43fc9ca915da1 | |
| parent | 8182f182e69bcde7376661757b5cf7f905f3433b (diff) | |
| download | sloth-c22410c6f334497a404f0b708ae94be527a8f0ee.tar.gz | |
Parser works with function calls
| -rw-r--r-- | examples/hello.sloth | 3 | ||||
| -rw-r--r-- | sloth/src/codegen.rs | 87 | ||||
| -rw-r--r-- | sloth/src/compiler.rs | 57 | ||||
| -rw-r--r-- | sloth/src/main.rs | 9 | ||||
| -rw-r--r-- | sloth/src/parser/ast.rs | 42 | ||||
| -rw-r--r-- | sloth/src/parser/expr.rs | 29 | ||||
| -rw-r--r-- | sloth/src/parser/graph.rs | 41 | ||||
| -rw-r--r-- | sloth/src/parser/stmt.rs | 313 |
8 files changed, 277 insertions, 304 deletions
diff --git a/examples/hello.sloth b/examples/hello.sloth index 0da2fd0..fea5304 100644 --- a/examples/hello.sloth +++ b/examples/hello.sloth @@ -1,6 +1,7 @@ fn main() { var i: Int = 10; - while i > 0 { + var j: Int = int(1.0) - 1; + while i > j { i = i - 1; } } diff --git a/sloth/src/codegen.rs b/sloth/src/codegen.rs deleted file mode 100644 index 8dec27e..0000000 --- a/sloth/src/codegen.rs +++ /dev/null @@ -1,87 +0,0 @@ -use inkwell::builder::Builder; -use inkwell::context::Context; -use inkwell::module::Module; -use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType}; -use inkwell::values::FunctionValue; -use itertools::Itertools; - -use crate::parser::ast::{FunctionInput, StmtKind}; -use crate::symbol::SymbolTableStack; - -/// A module codegen is a struct designated to compiling a single module -pub struct ModuleCodegen<'ctx, 'a> { - context: &'ctx Context, - builder: Builder<'ctx>, - module: Module<'ctx>, - - symbol_table: &'a mut SymbolTableStack, -} - -impl<'ctx, 'a> ModuleCodegen<'ctx, 'a> { - pub fn new( - module: &str, - context: &'ctx Context, - symbol_table: &'a mut SymbolTableStack, - ) -> Self { - let builder = context.create_builder(); - let module = context.create_module(module); - - Self { - context, - builder, - module, - - symbol_table, - } - } - - pub fn compile_function( - &mut self, - ident: String, - args: Vec<FunctionInput>, - return_type: Option<String>, - body: &[StmtKind], - ) { - let llvm_function_type = self.compile_function_type(&args, return_type.as_deref()); - let llvm_function = self.module.add_function(&ident, llvm_function_type, None); - - let entry_block = self.context.append_basic_block(llvm_function, "entry"); - - self.block(body); - } - - fn compile_function_type( - &self, - args: &[FunctionInput], - return_type: Option<&str>, - ) -> FunctionType<'ctx> { - let args = args - .iter() - .map(|it| self.compile_basic_metadata_type(&it.typ).unwrap()) - .collect_vec(); - - match return_type { - None => self.context.void_type().fn_type(&args, false), - Some("int") => self.context.i64_type().fn_type(&args, false), - Some("float") => self.context.f64_type().fn_type(&args, false), - _ => panic!(), - } - } - - fn compile_basic_metadata_type(&self, typ: &str) -> Option<BasicMetadataTypeEnum<'ctx>> { - match typ { - "int" => Some(self.context.i64_type().into()), - "float" => Some(self.context.f64_type().into()), - _ => None, - } - } - - fn block(&mut self, body: &[StmtKind]) { - self.symbol_table.push(); - self.symbol_table.pop(); - } - - // fn compile(symbol_table: &'a mut SymbolTableStack, code: Vec<Stmt>) { - // // - // } -} diff --git a/sloth/src/compiler.rs b/sloth/src/compiler.rs deleted file mode 100644 index 3dedb49..0000000 --- a/sloth/src/compiler.rs +++ /dev/null @@ -1,57 +0,0 @@ -use inkwell::context::Context; -use thiserror::Error; - -use crate::codegen::{self, ModuleCodegen}; -use crate::parser::ast::StmtKind; -use crate::symbol::{Symbol, SymbolTable, SymbolTableStack, SymbolType}; - -#[derive(Debug, Error)] -pub enum CompilerError { - #[error("Unknown compiler error")] - Unknown, -} - -pub struct Compiler { - symbol_table: SymbolTableStack, -} - -impl Compiler { - /// Take in a AST in the form of a vector of statements and compile the - /// program. - pub fn compile(code: Vec<StmtKind>) -> Result<(), CompilerError> { - let mut compiler = Self { - symbol_table: SymbolTableStack::new(), - }; - - // Resolve names - compiler.resolve_globals(&code); - - // Compile each function - let context = Context::create(); - let codegen = ModuleCodegen::new("root", &context, &mut compiler.symbol_table); - - for stmt in code.iter() { - if let StmtKind::DefineFunction { body, .. } = stmt { - // compiler.compile_function(body); - } - } - - Ok(()) - } - - fn resolve_globals(&mut self, code: &[StmtKind]) { - for stmt in code.iter() { - // if let Stmt::DefineFunction { ident, .. } = stmt { - // let symbol = Symbol { - // typ: Some(SymbolType::Function), - // }; - // - // self.symbol_table.insert(ident, symbol); - // } - } - } -} - -// Step 1: Name resolution -// Step 2: Type checking -// Step 3: Code generation diff --git a/sloth/src/main.rs b/sloth/src/main.rs index 0cfeb09..6ae01ec 100644 --- a/sloth/src/main.rs +++ b/sloth/src/main.rs @@ -6,8 +6,6 @@ unused_lifetimes )] -pub mod codegen; -pub mod compiler; pub mod lexer; pub mod parser; pub mod sloth_std; @@ -40,11 +38,4 @@ fn main() { let graph = GraphBuilder::generate(&ast).unwrap(); println!("{graph}"); - - // Compiler::compile(ast).unwrap(); - - // let context = Context::create(); - // let compiler = Compiler::new(&context); - // - // compiler.compile(ast); } diff --git a/sloth/src/parser/ast.rs b/sloth/src/parser/ast.rs index 749271c..1a994df 100644 --- a/sloth/src/parser/ast.rs +++ b/sloth/src/parser/ast.rs @@ -1,4 +1,4 @@ -use std::fmt::{format, Display}; +use std::fmt::Display; use crate::lexer::{self, TokenType}; use crate::parser::ParsingError; @@ -127,7 +127,7 @@ impl Display for Literal { Literal::Boolean(b) => format!("{b}"), Literal::Character(c) => format!("'{c}'"), Literal::String(s) => format!("\"{s}\""), - Literal::Array(a) => format!("<Array>"), + Literal::Array(..) => "<Array>".to_string(), }; write!(f, "{value}") @@ -187,6 +187,33 @@ impl TryFrom<TokenType> for BinaryOp { } } +impl Display for BinaryOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let value = match self { + BinaryOp::Add => "+", + BinaryOp::Con => "++", + BinaryOp::Sub => "-", + BinaryOp::Mul => "*", + BinaryOp::Div => "/", + BinaryOp::Mod => "%", + + BinaryOp::Lt => "<", + BinaryOp::Gt => ">", + BinaryOp::LtEq => "<=", + BinaryOp::GtEq => ">=", + BinaryOp::EqEq => "==", + BinaryOp::NotEq => "!=", + + BinaryOp::LogicalAnd => "&&", + BinaryOp::LogicalOr => "||", + + BinaryOp::Range => "..", + }; + + write!(f, "{value}") + } +} + #[derive(Debug, Clone, Copy, PartialEq)] pub enum UnaryOp { Not, @@ -207,3 +234,14 @@ impl TryFrom<TokenType> for UnaryOp { Ok(operation) } } + +impl Display for UnaryOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let value = match self { + UnaryOp::Not => "!", + UnaryOp::Neg => "-", + }; + + write!(f, "{value}") + } +} diff --git a/sloth/src/parser/expr.rs b/sloth/src/parser/expr.rs index ff662cc..48ee038 100644 --- a/sloth/src/parser/expr.rs +++ b/sloth/src/parser/expr.rs @@ -10,7 +10,7 @@ impl<'a> AstParser<'a> { } fn unary(&mut self) -> Result<Expr, ParsingError> { - if matches!(self.peek().tt, TokenType::Bang | TokenType::Minus) { + if !self.eof() && matches!(self.peek().tt, TokenType::Bang | TokenType::Minus) { let oeprator_tt = self.advance().unwrap().tt.clone(); let operator = UnaryOp::try_from(oeprator_tt)?; @@ -24,7 +24,32 @@ impl<'a> AstParser<'a> { return Ok(Expr::new(self.reserve_id(), kind)); } - self.primary() + self.call() + } + + fn call(&mut self) -> Result<Expr, ParsingError> { + let mut expr = self.primary()?; + + if !self.eof() && self.peek().tt == TokenType::OpeningParen { + self.consume(TokenType::OpeningParen, "Expected '('")?; + + let mut arguments = Vec::new(); + while !self.eof() && self.peek().tt != TokenType::ClosingParen { + arguments.push(self.expression()?); + if !self.advance_if_eq(&TokenType::Comma) { + break; + } + } + + self.consume(TokenType::ClosingParen, "Expected ')'")?; + + expr = Expr::new(self.reserve_id(), ExprKind::Call { + callee: Box::new(expr), + args: arguments, + }); + } + + Ok(expr) } fn primary(&mut self) -> Result<Expr, ParsingError> { diff --git a/sloth/src/parser/graph.rs b/sloth/src/parser/graph.rs index e8236be..da4bd71 100644 --- a/sloth/src/parser/graph.rs +++ b/sloth/src/parser/graph.rs @@ -120,7 +120,7 @@ impl GraphBuilder { ExprKind::Grouping(child) => { writeln!( &mut self.graph, - "N{} [shape=diamond label=\"Grouping\"];", + "N{} [shape=circle label=\"Grouping\"];", expr.id )?; self.traverse_expr0(child)?; @@ -140,13 +140,33 @@ impl GraphBuilder { )?; } ExprKind::BinaryOp { op, lhs, rhs } => { + writeln!( + &mut self.graph, + "N{} [shape=circle label=\"{}\"];", + expr.id, op + )?; self.traverse_expr0(lhs)?; self.traverse_expr0(rhs)?; } ExprKind::UnaryOp { op, value } => { + writeln!( + &mut self.graph, + "N{} [shape=circle label=\"Unary {}\"];", + expr.id, op + )?; self.traverse_expr0(value)?; } - ExprKind::Call { callee, args } => (), + ExprKind::Call { callee, args } => { + writeln!( + &mut self.graph, + "N{} [shape=circle label=\"Function Call\"];", + expr.id + )?; + self.traverse_expr0(callee)?; + for arg in args { + self.traverse_expr0(arg)?; + } + } } Ok(()) @@ -222,15 +242,26 @@ impl GraphBuilder { match &expr.kind { ExprKind::Grouping(children) => { writeln!(&mut self.graph, "N{} -> N{};", expr.id, children.id)?; + self.traverse_expr(children)?; } ExprKind::BinaryOp { lhs, rhs, .. } => { - writeln!(&mut self.graph, "N{} -> N{};", expr.id, lhs.id)?; - writeln!(&mut self.graph, "N{} -> N{};", expr.id, rhs.id)?; + writeln!(&mut self.graph, "N{} -> N{} [label=lhs];", expr.id, lhs.id)?; + writeln!(&mut self.graph, "N{} -> N{} [label=rhs];", expr.id, rhs.id)?; + self.traverse_expr(lhs)?; + self.traverse_expr(rhs)?; } ExprKind::UnaryOp { value, .. } => { writeln!(&mut self.graph, "N{} -> N{};", expr.id, value.id)?; + self.traverse_expr(value)?; + } + ExprKind::Call { callee, args } => { + writeln!(&mut self.graph, "N{} -> N{};", expr.id, callee.id)?; + self.traverse_expr(callee)?; + for arg in args { + writeln!(&mut self.graph, "N{} -> N{};", expr.id, arg.id)?; + self.traverse_expr(arg)?; + } } - ExprKind::Call { callee, args } => (), _ => (), } diff --git a/sloth/src/parser/stmt.rs b/sloth/src/parser/stmt.rs index c8913b4..2370311 100644 --- a/sloth/src/parser/stmt.rs +++ b/sloth/src/parser/stmt.rs @@ -178,145 +178,176 @@ mod tests { use super::{AstParser, StmtKind}; use crate::lexer::Lexer; - use crate::parser::ast::{BinaryOp, ExprKind, FunctionInput, Literal}; - - // #[test] - // fn standalone_blocks() { - // let tokens = Lexer::new("{{{ 0; }}}").collect_vec(); - // - // let expected_ast = - // Ok(Stmt::Block(vec![Stmt::Block(vec![Stmt::Block(vec![ - // Stmt::ExprStmt(Literal::Integer(0).into()), - // ])])])); - // - // let mut parser = AstParser::new(tokens); - // let generated_ast = parser.statement(); - // - // println!("Expected AST:\n{expected_ast:#?}\n\n"); - // println!("Generated AST:\n{generated_ast:#?}\n\n"); - // - // assert_eq!(expected_ast, generated_ast); - // } - // - // #[test] - // fn basic_variable_definition() { - // let tokens = Lexer::new("var foo: Int = 5 + 3;").collect_vec(); - // - // let expected_ast = Ok(Stmt::DefineVariable { - // identifier: "foo".to_string(), - // value: ExprKind::BinaryOp { - // op: BinaryOp::Add, - // lhs: Box::new(ExprKind::Literal(Literal::Integer(5))), - // rhs: Box::new(ExprKind::Literal(Literal::Integer(3))), - // }, - // typ: "Int".to_string(), - // }); - // - // let mut parser = AstParser::new(tokens); - // let generated_ast = parser.statement(); - // - // println!("Expected AST:\n{expected_ast:#?}\n\n"); - // println!("Generated AST:\n{generated_ast:#?}\n\n"); - // - // assert_eq!(expected_ast, generated_ast); - // } - // - // #[test] - // fn basic_function() { - // let tokens = Lexer::new( - // r#" - // fn foo(bar: Int) Int { - // var baz: Int = bar + 1; - // baz = baz + 1; - // return baz; - // } - // "#, - // ) - // .collect_vec(); - // - // let expected_ast = Ok(Stmt::DefineFunction { - // identifier: "foo".to_owned(), - // inputs: vec![FunctionInput { - // identifier: "bar".to_owned(), - // typ: "Int".to_owned(), - // }], - // output: Some("Int".to_owned()), - // body: Box::new(Stmt::Block(vec![ - // Stmt::DefineVariable { - // identifier: "baz".to_owned(), - // value: ExprKind::BinaryOp { - // op: BinaryOp::Add, - // lhs: - // Box::new(ExprKind::Identifier("bar".to_owned())), - // rhs: Box::new(Literal::Integer(1).into()), }, - // typ: "Int".to_owned(), - // }, - // Stmt::AssignVariable { - // identifier: "baz".to_owned(), - // value: ExprKind::BinaryOp { - // op: BinaryOp::Add, - // lhs: - // Box::new(ExprKind::Identifier("baz".to_owned())), - // rhs: Box::new(Literal::Integer(1).into()), }, - // }, - // Stmt::Return(ExprKind::Identifier("baz".to_owned())), - // ])), - // }); - // - // let mut parser = AstParser::new(tokens); - // let generated_ast = parser.statement(); - // - // println!("Expected AST:\n{expected_ast:#?}\n\n"); - // println!("Generated AST:\n{generated_ast:#?}\n\n"); - // - // assert_eq!(expected_ast, generated_ast); - // } - // - // #[test] - // fn basic_conditional() { - // let tokens = Lexer::new( - // r#" - // if foo { - // 0; - // } else if bar { - // 1; - // } else if baz { - // 2; - // } else { - // 3; - // } - // "#, - // ) - // .collect_vec(); - // - // let expected_ast = Ok(Stmt::IfStmt { - // condition: ExprKind::Identifier("foo".to_owned()), - // if_then: Box::new(Stmt::Block(vec![Stmt::ExprStmt( - // Literal::Integer(0).into(), - // )])), - // else_then: Some(Box::new(Stmt::IfStmt { - // condition: ExprKind::Identifier("bar".to_owned()), - // if_then: Box::new(Stmt::Block(vec![Stmt::ExprStmt( - // Literal::Integer(1).into(), - // )])), - // else_then: Some(Box::new(Stmt::IfStmt { - // condition: ExprKind::Identifier("baz".to_owned()), - // if_then: Box::new(Stmt::Block(vec![Stmt::ExprStmt( - // Literal::Integer(2).into(), - // )])), - // else_then: Some(Box::new(Stmt::Block(vec![Stmt::ExprStmt( - // Literal::Integer(3).into(), - // )]))), - // })), - // })), - // }); - // - // let mut parser = AstParser::new(tokens); - // let generated_ast = parser.statement(); - // - // println!("Expected AST:\n{expected_ast:#?}\n\n"); - // println!("Generated AST:\n{generated_ast:#?}\n\n"); - // - // assert_eq!(expected_ast, generated_ast); - // } + use crate::parser::ast::{BinaryOp, Expr, ExprKind, FunctionInput, Literal, Stmt}; + + #[test] + fn standalone_blocks() { + let tokens = Lexer::new("{{{ 0; }}}").collect_vec(); + + let expected_ast = Ok(Stmt::new( + 4, + StmtKind::Block(vec![Stmt::new( + 3, + StmtKind::Block(vec![Stmt::new( + 2, + StmtKind::Block(vec![Stmt::new( + 1, + StmtKind::ExprStmt(Expr::new(0, Literal::Integer(0).into())), + )]), + )]), + )]), + )); + + let mut parser = AstParser::new(tokens); + let generated_ast = parser.statement(); + + println!("Expected AST:\n{expected_ast:#?}\n\n"); + println!("Generated AST:\n{generated_ast:#?}\n\n"); + + assert_eq!(expected_ast, generated_ast); + } + + #[test] + fn basic_variable_definition() { + let tokens = Lexer::new("var foo: Int = 5 + 3;").collect_vec(); + + let expected_ast = Ok(Stmt::new(3, StmtKind::DefineVariable { + identifier: "foo".to_string(), + value: Expr::new(2, ExprKind::BinaryOp { + op: BinaryOp::Add, + lhs: Box::new(Expr::new(0, ExprKind::Literal(Literal::Integer(5)))), + rhs: Box::new(Expr::new(1, ExprKind::Literal(Literal::Integer(3)))), + }), + typ: "Int".to_string(), + })); + + let mut parser = AstParser::new(tokens); + let generated_ast = parser.statement(); + + println!("Expected AST:\n{expected_ast:#?}\n\n"); + println!("Generated AST:\n{generated_ast:#?}\n\n"); + + assert_eq!(expected_ast, generated_ast); + } + + #[test] + fn basic_function() { + let tokens = Lexer::new( + r#" + fn foo(bar: Int) Int { + var baz: Int = bar + 1; + baz = baz + 1; + return baz; + } + "#, + ) + .collect_vec(); + + let expected_ast = Ok(Stmt::new(11, StmtKind::DefineFunction { + identifier: "foo".to_owned(), + inputs: vec![FunctionInput { + identifier: "bar".to_owned(), + typ: "Int".to_owned(), + }], + output: Some("Int".to_owned()), + body: Box::new(Stmt::new( + 10, + StmtKind::Block(vec![ + Stmt::new(3, StmtKind::DefineVariable { + identifier: "baz".to_owned(), + value: Expr::new(2, ExprKind::BinaryOp { + op: BinaryOp::Add, + lhs: Box::new(Expr::new(0, ExprKind::Identifier("bar".to_owned()))), + rhs: Box::new(Expr::new(1, Literal::Integer(1).into())), + }), + typ: "Int".to_owned(), + }), + Stmt::new(7, StmtKind::AssignVariable { + identifier: "baz".to_owned(), + value: Expr::new(6, ExprKind::BinaryOp { + op: BinaryOp::Add, + lhs: Box::new(Expr::new(4, ExprKind::Identifier("baz".to_owned()))), + rhs: Box::new(Expr::new(5, Literal::Integer(1).into())), + }), + }), + Stmt::new( + 9, + StmtKind::Return(Expr::new(8, ExprKind::Identifier("baz".to_owned()))), + ), + ]), + )), + })); + + let mut parser = AstParser::new(tokens); + let generated_ast = parser.statement(); + + println!("Expected AST:\n{expected_ast:#?}\n\n"); + println!("Generated AST:\n{generated_ast:#?}\n\n"); + + assert_eq!(expected_ast, generated_ast); + } + + #[test] + fn basic_conditional() { + let tokens = Lexer::new( + r#" + if foo { + 0; + } else if bar { + 1; + } else if baz { + 2; + } else { + 3; + } + "#, + ) + .collect_vec(); + + let expected_ast = Ok(Stmt::new(17, StmtKind::IfStmt { + condition: Expr::new(0, ExprKind::Identifier("foo".to_owned())), + if_then: Box::new(Stmt::new( + 3, + StmtKind::Block(vec![Stmt::new( + 2, + StmtKind::ExprStmt(Expr::new(1, Literal::Integer(0).into())), + )]), + )), + else_then: Some(Box::new(Stmt::new(16, StmtKind::IfStmt { + condition: Expr::new(4, ExprKind::Identifier("bar".to_owned())), + if_then: Box::new(Stmt::new( + 7, + StmtKind::Block(vec![Stmt::new( + 6, + StmtKind::ExprStmt(Expr::new(5, Literal::Integer(1).into())), + )]), + )), + else_then: Some(Box::new(Stmt::new(15, StmtKind::IfStmt { + condition: Expr::new(8, ExprKind::Identifier("baz".to_owned())), + if_then: Box::new(Stmt::new( + 11, + StmtKind::Block(vec![Stmt::new( + 10, + StmtKind::ExprStmt(Expr::new(9, Literal::Integer(2).into())), + )]), + )), + else_then: Some(Box::new(Stmt::new( + 14, + StmtKind::Block(vec![Stmt::new( + 13, + StmtKind::ExprStmt(Expr::new(12, Literal::Integer(3).into())), + )]), + ))), + }))), + }))), + })); + + let mut parser = AstParser::new(tokens); + let generated_ast = parser.statement(); + + println!("Expected AST:\n{expected_ast:#?}\n\n"); + println!("Generated AST:\n{generated_ast:#?}\n\n"); + + assert_eq!(expected_ast, generated_ast); + } } |
