function declarations
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
while a < 100000
|
||||
print(a)
|
||||
let temp: I64 = b
|
||||
b = a + b
|
||||
a = temp
|
||||
@@ -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<dyn Error>> {
|
||||
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(())
|
||||
|
||||
@@ -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<Stmt>,
|
||||
},
|
||||
Function {
|
||||
name: Token,
|
||||
params: Vec<Param>,
|
||||
body: Box<Stmt>,
|
||||
},
|
||||
}
|
||||
|
||||
#[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<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>> {
|
||||
let name = self.consume(TokenType::Identifier, "expected variable name")?;
|
||||
self.consume(TokenType::Colon, "expected ':' after variable name")?;
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user