function declarations

This commit is contained in:
2025-05-30 18:33:52 +02:00
parent 2bc24c394d
commit b3475651eb
5 changed files with 76 additions and 32 deletions

View File

@@ -4,7 +4,7 @@ A very cool language
## Syntax ## Syntax
```go ```go
func fib[U32 n] : U32 func fib[n: U32] : U32
if n <= 1 if n <= 1
return n return n
return fib(n-2) + fib(n-1) return fib(n-2) + fib(n-1)

View File

@@ -1,7 +1,8 @@
let a: I64 = 0 func main[]
let b: I64 = 1 let a: I64 = 0
let b: I64 = 1
while a < 100000 while a < 100000
print(a) print(a)
let temp: I64 = b let temp: I64 = b
b = a + b b = a + b

View File

@@ -67,32 +67,28 @@ impl Codegen {
writeln!( writeln!(
&mut self.output, &mut self.output,
"section .data "section .data
format db \"%d\", 10, 0 format db \"%ld\", 10, 0
section .text section .text
extern printf extern printf
global main print:
main:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
sub rsp, 256" // TODO mov rdi, format
mov rsi, rax
xor rax, rax
call printf
pop rbp
ret
"
)?; )?;
Ok(()) Ok(())
} }
pub fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>> { pub fn emit_epilogue(&mut self) -> Result<(), Box<dyn Error>> {
write!( writeln!(&mut self.output, "section .note.GNU-stack")?;
&mut self.output, writeln!(&mut self.output, " db 0")?;
" mov rsp, rbp
pop rbp
mov rax, 0
ret
section .note.GNU-stack
db 0
"
)?;
Ok(()) Ok(())
} }
@@ -156,6 +152,22 @@ section .note.GNU-stack
writeln!(&mut self.output, " jmp {}", begin_label)?; writeln!(&mut self.output, " jmp {}", begin_label)?;
writeln!(&mut self.output, "{}:", end_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(()) Ok(())
} }
@@ -275,18 +287,11 @@ section .note.GNU-stack
}; };
// TODO // TODO
assert!(callee == "print");
assert!(args.len() == 1); assert!(args.len() == 1);
self.compile_expr(env, args.first().unwrap().clone())?; self.compile_expr(env, args.first().unwrap().clone())?;
writeln!(&mut self.output, " mov rdi, rax")?;
writeln!( writeln!(&mut self.output, " call {}", callee)?;
&mut self.output,
" mov rdi, format
mov rsi, rax
xor rax, rax
call printf"
)?;
} }
} }
Ok(()) Ok(())

View File

@@ -2,6 +2,12 @@ use std::error::Error;
use crate::tokenizer::{MotError, Token, TokenType, error}; use crate::tokenizer::{MotError, Token, TokenType, error};
#[derive(Debug, Clone)]
pub struct Param {
var_type: Token,
var_name: Token,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Stmt { pub enum Stmt {
Expression(Expr), Expression(Expr),
@@ -20,6 +26,11 @@ pub enum Stmt {
condition: Expr, condition: Expr,
body: Box<Stmt>, body: Box<Stmt>,
}, },
Function {
name: Token,
params: Vec<Param>,
body: Box<Stmt>,
},
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -69,11 +80,36 @@ impl Parser {
// TODO: synchronization after parse error // TODO: synchronization after parse error
if self.match_token(&[TokenType::KeywordLet]) { if self.match_token(&[TokenType::KeywordLet]) {
self.let_declaration() self.let_declaration()
} else if self.match_token(&[TokenType::KeywordFunc]) {
self.func_declaration()
} else { } else {
self.statement() self.statement()
} }
} }
// TOOD: parse return type
fn func_declaration(&mut self) -> Result<Stmt, Box<dyn Error>> {
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<Stmt, Box<dyn Error>> { fn let_declaration(&mut self) -> Result<Stmt, Box<dyn Error>> {
let name = self.consume(TokenType::Identifier, "expected variable name")?; let name = self.consume(TokenType::Identifier, "expected variable name")?;
self.consume(TokenType::Colon, "expected ':' after variable name")?; self.consume(TokenType::Colon, "expected ':' after variable name")?;

View File

@@ -34,6 +34,7 @@ pub enum TokenType {
KeywordIf, KeywordIf,
KeywordElse, KeywordElse,
KeywordWhile, KeywordWhile,
KeywordFunc,
Indent, Indent,
Dedent, Dedent,
@@ -298,6 +299,7 @@ impl Tokenizer {
"if" => TokenType::KeywordIf, "if" => TokenType::KeywordIf,
"else" => TokenType::KeywordElse, "else" => TokenType::KeywordElse,
"while" => TokenType::KeywordWhile, "while" => TokenType::KeywordWhile,
"func" => TokenType::KeywordFunc,
_ => TokenType::Identifier, _ => TokenType::Identifier,
}) })
} }