function declarations
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(())
|
||||||
|
|||||||
@@ -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")?;
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user