diff --git a/lang/src/ast.asm b/lang/src/ast.asm index 8fea220..f8f98e6 100644 --- a/lang/src/ast.asm +++ b/lang/src/ast.asm @@ -12,6 +12,11 @@ section .rdata AST_RETURN_STATEMENT equ 6 AST_VALUE_TO_PLACE equ 7 AST_PLACE_TO_VALUE equ 8 + AST_ASSIGNMENT equ 9 + AST_DEREF equ 10 + AST_ADDRESS_OF equ 11 + AST_VAR_DECL equ 12 + AST_VAR_REF equ 13 TYPE_VOID equ 1 TYPE_BOOL equ 2 @@ -44,6 +49,9 @@ extern expect_token extern unwrap_token extern peek_expect_token +extern tokeniser_get_cursor +extern tokeniser_set_cursor + extern str_to_int global parse_func @@ -342,7 +350,7 @@ parse_binary_expr: mov byte [rsp + 17], sil ; upper_precedence mov byte [rsp + 16], 0 - call parse_primary_expr + call parse_prefix_expr mov [rsp + 8], rax ; left mov [rsp + 19], dl ; left_placeness @@ -404,12 +412,14 @@ parse_binary_expr: mov dl, [rsp + 19] ; left_placeness call ast_place_to_value mov [rsp + 8], rax ; left + mov byte [rsp + 19], 0 ; left_placeness = false mov rdi, [rsp] ; Ast mov rsi, [rsp + 24] ; right mov dl, [rsp + 20] ; right_placeness call ast_place_to_value mov [rsp + 24], rax ; right + mov byte [rsp + 20], 0 ; right_placeness = false mov rdi, 24 mov rsi, 8 @@ -431,10 +441,12 @@ parse_binary_expr: mov rax, [rdi + 8] ; Ast.nodes.len() dec rax mov [rsp + 8], rax ; left + mov byte [rsp + 19], 0 ; left_placeness = false jmp .loop .done: mov rax, [rsp + 8] ; left + movzx rdx, byte [rsp + 19] ; left_placeness add rsp, 64 pop rbp ret @@ -448,7 +460,7 @@ parse_expr: sub rsp, 8 mov [rsp], rdi ; Ast mov sil, 0 - call parse_binary_expr + call parse_assignment_expr add rsp, 8 pop rbp ret @@ -468,8 +480,18 @@ parse_statement: call expect_token test rax, rax jnz .return + mov dil, TOKEN_LET + call expect_token + test rax, rax + jnz .let jmp .panic +.let: + mov rdi, [rsp + 24] ; Ast + call ast_parse_let + mov [rsp], rax ; statement + jmp .semi + .return: mov rdi, [rsp + 24] ; Ast call parse_expr @@ -484,6 +506,7 @@ parse_statement: dec rax mov [rsp], rax +.semi: mov dil, TOKEN_SEMI call unwrap_token mov rax, [rsp] ; expression @@ -583,6 +606,213 @@ parse_type: .panic: call panic +;; rdi: *mut Ast +;; define-fn: fn parse_prefix_expr(ast: *mut Ast) -> (u64, bool) +parse_prefix_expr: + push rbp + mov rbp, rsp + + ; ast [0..8] + sub rsp, 32 + + mov [rsp], rdi ; Ast + + mov dil, TOKEN_STAR + call expect_token + test rax, rax + jnz .dereference + mov dil, TOKEN_AMP + call expect_token + test rax, rax + jnz .address_of + + mov rdi, [rsp] ; Ast + call parse_primary_expr + jmp .done +.dereference: + mov rdi, [rsp] ; Ast + call parse_prefix_expr + + mov qword [rsp + 8], AST_DEREF ; AstNode.kind + mov [rsp + 16], rax ; AstNode.data + mov qword [rsp + 24], 0 ; AstNode.extra + mov rdi, [rsp] ; Ast + lea rsi, [rsp + 8] ; &AstNode + call vec_push + mov rdi, [rsp] ; Ast + mov rax, [rdi + 8] ; Ast.nodes.len() + dec rax + mov rdx, 1 ; placeness = true + jmp .done + +.address_of: + ; address-of must be applied to a place + ; so we convert the inner expression to a place first + mov rdi, [rsp] ; Ast + call parse_prefix_expr + + mov rdi, [rsp] ; Ast + mov rsi, rax ; expr + ; mov rdx, rdx ; placeness + call ast_value_to_place + mov qword [rsp + 8], AST_ADDRESS_OF ; AstNode.kind + mov [rsp + 16], rax ; AstNode.data + mov qword [rsp + 24], 0 ; AstNode.extra + mov rdi, [rsp] ; Ast + lea rsi, [rsp + 8] ; &AstNode + call vec_push + mov rdi, [rsp] ; Ast + mov rax, [rdi + 8] ; Ast.nodes.len() + dec rax + xor rdx, rdx ; placeness = false + jmp .done + +.done: + add rsp, 32 + pop rbp + ret + +;; rdi: *mut Ast +;; define-fn: fn parse_assignment(ast: *mut Ast) -> (u64, bool) +parse_assignment_expr: + push rbp + mov rbp, rsp + + ; source [24..32] + ; dest [16..24] + ; dest_placeness [8..9] + ; ast [0..8] + sub rsp, 32 + mov [rsp], rdi ; Ast + + mov rdi, [rsp] ; Ast + call parse_binary_expr + mov [rsp + 16], rax ; dest + mov [rsp + 8], dl ; placeness + + mov dil, TOKEN_EQUALS + call expect_token + test rax, rax + jnz .assignment + jmp .done + +.assignment: + mov rdi, [rsp] ; Ast + mov rsi, [rsp + 16] ; dest + movzx rdx, byte [rsp + 8] ; placeness + call ast_value_to_place + mov [rsp + 16], rax ; source + + mov rdi, [rsp] ; Ast + call parse_expr + + mov rdi, [rsp] ; Ast + mov rsi, rax ; expr + ; mov rdx, rdx ; placeness + call ast_place_to_value + mov [rsp + 24], rax ; source + + mov qword [rsp + 8], AST_ASSIGNMENT ; AstNode.kind + mov rdi, [rsp] ; Ast + lea rsi, [rsp + 8] ; &AstNode + call vec_push + mov rdi, [rsp] ; Ast + mov rax, [rdi + 8] ; Ast.nodes.len() + dec rax + mov [rsp + 16], rax ; dest + mov byte [rsp + 8], 0 ; placeness = false + +.done: + mov rax, [rsp + 16] ; dest + movzx rdx, byte [rsp + 8] ; placeness + add rsp, 32 + pop rbp + ret + +;; rdi: *mut Ast +;; define-fn: fn ast_parse_let(ast: *mut Ast) -> (u64, bool) +ast_parse_let: + push rbp + mov rbp, rsp + + ; start-structs + ; struct AstVarDecl { + ; name: *const u8, + ; name_len: usize, + ; var_type: Type, + ; } + ; + ; struct AstAssignment { + ; variable: u64, + ; expr: u64, + ; } + ; end-structs + + sub rsp, 64 + mov [rsp], rdi ; Ast + + ; skipped in parse_statement + ; mov dil, TOKEN_LET + ; call unwrap_token + + mov dil, TOKEN_IDENT + call unwrap_token + mov [rsp + 8], rax ; variable name + mov [rsp + 16], rdx ; variable name length + + mov dil, TOKEN_COLON + call unwrap_token + mov rdi, [rsp] ; Ast + call parse_type + mov [rsp + 24], rax ; variable type + + mov rdi, 24 + mov rsi, 8 + call bump_alloc + + mov rdi, rax ; AstVariable ptr + lea rsi, [rsp + 8] ; &AstVariable + mov rdx, 24 + call memcpy + + mov qword [rsp + 32], AST_VAR_DECL ; AstNode.kind + mov [rsp + 40], rdi ; AstNode.data + mov qword [rsp + 48], 0 ; AstNode.extra + + mov rdi, [rsp] ; Ast + lea rsi, [rsp + 32] ; &AstNode + call vec_push + ; variable is already a place + + mov rdi, [rsp] ; Ast + mov rax, [rdi + 8] ; Ast.nodes.len() + dec rax + mov qword [rsp + 32], AST_ASSIGNMENT ; AstNode.kind + mov [rsp + 40], rax ; AstNode.data (variable index) + + mov dil, TOKEN_EQUALS + call unwrap_token + mov rdi, [rsp] ; Ast + call parse_expr + + mov rdi, [rsp] ; Ast + mov rsi, rax ; expr + ; mov rdx, rdx ; is_placeness + call ast_place_to_value + + mov [rsp + 48], rax ; AstNode.extra (expr index) + mov rdi, [rsp] ; Ast + lea rsi, [rsp + 32] ; &AstNode + call vec_push + mov rdi, [rsp] ; Ast + mov rax, [rdi + 8] ; Ast.nodes.len() + dec rax + + add rsp, 64 + xor rdx, rdx ; placeness = false + pop rbp + ret + ;; rdi: *mut Ast ;; rsi: index of node ;; rdx: is_placeness @@ -591,8 +821,8 @@ ast_value_to_place: push rbp mov rbp, rsp - cmp dl, 0 - xor rax, rax + cmp dl, 1 + mov rax, rsi je .done ; create new AST node sub rsp, 32 @@ -618,8 +848,8 @@ ast_place_to_value: push rbp mov rbp, rsp - cmp dl, 1 - xor rax, rax + cmp dl, 0 + mov rax, rsi je .done ; create new AST node sub rsp, 32 diff --git a/lang/src/tokeniser.asm b/lang/src/tokeniser.asm index f37b87c..21afb01 100644 --- a/lang/src/tokeniser.asm +++ b/lang/src/tokeniser.asm @@ -27,6 +27,9 @@ global unwrap_token global peek_expect_token global peek_lexeme +global tokeniser_get_cursor +global tokeniser_set_cursor + ;; ============================= ;; Tokeniser functions ;; ============================= @@ -583,3 +586,11 @@ peek_lexeme: pop rax pop rbp ret + +tokeniser_get_cursor: + mov rax, [rel cursor] + ret + +tokeniser_set_cursor: + mov [rel cursor], rdi + ret diff --git a/lang/tests/ast.rs b/lang/tests/ast.rs index 594b03b..5ae1a38 100644 --- a/lang/tests/ast.rs +++ b/lang/tests/ast.rs @@ -46,17 +46,43 @@ fn main() { print_ast(b"fn main() -> void { return 1 + 2 * 3; }", |ast| unsafe { parse_func(ast); }); + + print_ast(b"fn main() -> void { let x: u32 = 4; }", |ast| unsafe { + parse_func(ast); + }); } impl std::fmt::Display for AstNode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use util::defs::{ - BinaryExpr, AST_BINARY_OP, AST_BLOCK, AST_FUNCTION, AST_NUMBER, AST_RETURN_STATEMENT, + BinaryExpr, AST_ADDRESS_OF, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK, AST_DEREF, + AST_FUNCTION, AST_NUMBER, AST_RETURN_STATEMENT, AST_VAR_DECL, AST_VAR_REF, }; match self.kind as u32 { AST_NUMBER => { write!(f, "Number({})", self.data as usize) } + AST_VAR_DECL => { + let var_decl = unsafe { self.data.cast::().read() }; + write!( + f, + "VarDecl(name: {:?}, var_type: {:?})", + unsafe { + std::str::from_utf8(std::slice::from_raw_parts( + var_decl.name, + var_decl.name_len, + )) + }, + var_decl.var_type, + ) + } + AST_ASSIGNMENT => { + write!( + f, + "Assignment(dest: {}, src: {})", + self.data as usize, self.extra + ) + } AST_BINARY_OP => { let BinaryExpr { left, @@ -90,6 +116,12 @@ impl std::fmt::Display for AstNode { std::slice::from_raw_parts(self.data.cast::(), self.extra as usize) }) } + AST_PLACE_TO_VALUE => { + write!(f, "PlaceToValue(place: {})", self.data as usize) + } + AST_VALUE_TO_PLACE => { + write!(f, "ValueToPlace(value: {})", self.data as usize) + } _ => write!(f, "UnknownNode"), } } diff --git a/lang/tests/shared/defs.rs b/lang/tests/shared/defs.rs index bc5692a..aec2a0d 100644 --- a/lang/tests/shared/defs.rs +++ b/lang/tests/shared/defs.rs @@ -10,6 +10,9 @@ unsafe extern "C" { pub unsafe fn parse_statement(ast: *mut Ast) -> u64; pub unsafe fn parse_block(ast: *mut Ast) -> u64; pub unsafe fn parse_type(ast: *mut Ast) -> Type; + pub unsafe fn parse_prefix_expr(ast: *mut Ast) -> (u64, bool); + pub unsafe fn parse_assignment(ast: *mut Ast) -> (u64, bool); + pub unsafe fn ast_parse_let(ast: *mut Ast) -> (u64, bool); } pub const AST_FUNCTION: u32 = 1; @@ -20,6 +23,11 @@ pub const AST_BINARY_OP: u32 = 5; pub const AST_RETURN_STATEMENT: u32 = 6; pub const AST_VALUE_TO_PLACE: u32 = 7; pub const AST_PLACE_TO_VALUE: u32 = 8; +pub const AST_ASSIGNMENT: u32 = 9; +pub const AST_DEREF: u32 = 10; +pub const AST_ADDRESS_OF: u32 = 11; +pub const AST_VAR_DECL: u32 = 12; +pub const AST_VAR_REF: u32 = 13; pub const TYPE_VOID: u32 = 1; pub const TYPE_BOOL: u32 = 2; pub const TYPE_I32: u32 = 3; @@ -120,4 +128,19 @@ pub struct BinaryExpr { pub right: u64, } +#[repr(C)] +#[derive(Debug)] +pub struct AstVarDecl { + pub name: *const u8, + pub name_len: usize, + pub var_type: Type, +} + +#[repr(C)] +#[derive(Debug)] +pub struct AstAssignment { + pub variable: u64, + pub expr: u64, +} + use super::vec::Vec;