diff --git a/README.md b/README.md index 2235f4a..c559a55 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A very cool language ## Syntax ```go -func fib[U32 n] : U32 +func fib[n: U32] : U32 if n <= 1 return n return fib(n-2) + fib(n-1) diff --git a/examples/fib.mot b/examples/fib.mot index a4b0591..37344da 100644 --- a/examples/fib.mot +++ b/examples/fib.mot @@ -1,8 +1,9 @@ -let a: I64 = 0 -let b: I64 = 1 +func main[] + let a: I64 = 0 + let b: I64 = 1 -while a < 100000 - print(a) - let temp: I64 = b - b = a + b - a = temp \ No newline at end of file + while a < 100000 + print(a) + let temp: I64 = b + b = a + b + a = temp \ No newline at end of file diff --git a/src/codegen.rs b/src/codegen.rs index 05683fc..f7140ea 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -67,32 +67,28 @@ impl Codegen { writeln!( &mut self.output, "section .data -format db \"%d\", 10, 0 +format db \"%ld\", 10, 0 section .text extern printf -global main -main: +print: push rbp mov rbp, rsp - sub rsp, 256" // TODO + mov rdi, format + mov rsi, rax + xor rax, rax + call printf + pop rbp + ret +" )?; Ok(()) } pub fn emit_epilogue(&mut self) -> Result<(), Box> { - write!( - &mut self.output, - " mov rsp, rbp - pop rbp - mov rax, 0 - ret - -section .note.GNU-stack - db 0 -" - )?; + writeln!(&mut self.output, "section .note.GNU-stack")?; + writeln!(&mut self.output, " db 0")?; Ok(()) } @@ -156,6 +152,22 @@ section .note.GNU-stack writeln!(&mut self.output, " jmp {}", begin_label)?; writeln!(&mut self.output, "{}:", end_label)?; } + Stmt::Function { name, params, body } => { + assert!(params.is_empty()); // TODO + + writeln!(&mut self.output, "global {}", name.lexeme)?; + writeln!(&mut self.output, "{}:", name.lexeme)?; + writeln!(&mut self.output, " push rbp")?; + writeln!(&mut self.output, " mov rbp, rsp")?; + writeln!(&mut self.output, " sub rsp, 256")?; // TODO + + self.compile_stmt(env, *body)?; + + writeln!(&mut self.output, " mov rsp, rbp")?; + writeln!(&mut self.output, " pop rbp")?; + writeln!(&mut self.output, " mov rax, 0")?; + writeln!(&mut self.output, " ret")?; + } } Ok(()) } @@ -275,18 +287,11 @@ section .note.GNU-stack }; // TODO - assert!(callee == "print"); assert!(args.len() == 1); self.compile_expr(env, args.first().unwrap().clone())?; - - writeln!( - &mut self.output, - " mov rdi, format - mov rsi, rax - xor rax, rax - call printf" - )?; + writeln!(&mut self.output, " mov rdi, rax")?; + writeln!(&mut self.output, " call {}", callee)?; } } Ok(()) diff --git a/src/parser.rs b/src/parser.rs index b630dcb..e61251d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,6 +2,12 @@ use std::error::Error; use crate::tokenizer::{MotError, Token, TokenType, error}; +#[derive(Debug, Clone)] +pub struct Param { + var_type: Token, + var_name: Token, +} + #[derive(Debug, Clone)] pub enum Stmt { Expression(Expr), @@ -20,6 +26,11 @@ pub enum Stmt { condition: Expr, body: Box, }, + Function { + name: Token, + params: Vec, + body: Box, + }, } #[derive(Debug, Clone)] @@ -69,11 +80,36 @@ impl Parser { // TODO: synchronization after parse error if self.match_token(&[TokenType::KeywordLet]) { self.let_declaration() + } else if self.match_token(&[TokenType::KeywordFunc]) { + self.func_declaration() } else { self.statement() } } + // TOOD: parse return type + fn func_declaration(&mut self) -> Result> { + let name = self.consume(TokenType::Identifier, "expected function name")?; + self.consume(TokenType::LeftBracket, "expected '[' after function name")?; + + let mut params = vec![]; + if !self.check(&TokenType::RightBracket) { + loop { + let var_name = self.consume(TokenType::Identifier, "expected parameter name")?; + self.consume(TokenType::Colon, "expected ':' after parameter name")?; + let var_type = self.consume(TokenType::Identifier, "expected parameter type")?; + params.push(Param { var_type, var_name }); + if !self.match_token(&[TokenType::Comma]) { + break; + } + } + } + + self.consume(TokenType::RightBracket, "expected ']' after arguments")?; + let body = Box::new(self.block()?); + Ok(Stmt::Function { name, params, body }) + } + fn let_declaration(&mut self) -> Result> { let name = self.consume(TokenType::Identifier, "expected variable name")?; self.consume(TokenType::Colon, "expected ':' after variable name")?; diff --git a/src/tokenizer.rs b/src/tokenizer.rs index ad5e713..a7158e7 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -34,6 +34,7 @@ pub enum TokenType { KeywordIf, KeywordElse, KeywordWhile, + KeywordFunc, Indent, Dedent, @@ -298,6 +299,7 @@ impl Tokenizer { "if" => TokenType::KeywordIf, "else" => TokenType::KeywordElse, "while" => TokenType::KeywordWhile, + "func" => TokenType::KeywordFunc, _ => TokenType::Identifier, }) }