From 0e25f627a8d1bee09058b7c260b2d064e7b36fa1 Mon Sep 17 00:00:00 2001 From: janis Date: Mon, 3 Nov 2025 20:07:51 +0100 Subject: [PATCH] can codegen if/else --- lang/src/ast.asm | 161 ++++++++++++++++- lang/src/ast.inc | 6 +- lang/src/codegen.asm | 314 ++++++++++++++++++++++++++++++++- lang/src/tokeniser.inc | 40 ++++- lang/tests/ast.rs | 102 ++++++----- lang/tests/codegen.rs | 17 +- lang/tests/shared/ast_debug.rs | 15 +- lang/tests/shared/defs.rs | 43 ++++- 8 files changed, 628 insertions(+), 70 deletions(-) diff --git a/lang/src/ast.asm b/lang/src/ast.asm index 30db7ed..040d8e5 100644 --- a/lang/src/ast.asm +++ b/lang/src/ast.asm @@ -4,11 +4,16 @@ default rel %include "src/ast.inc" section .rdata + PRECEDENCE_PIPE2 dw 10 + PRECEDENCE_AMP2 dw 20 + PRECEDENCE_PIPE dw 30 + PRECEDENCE_CARET dw 40 + PRECEDENCE_AMP dw 50 + PRECEDENCE_EQ dw 60 + PRECEDENCE_CMP dw 70 + PRECEDENCE_SHIFT dw 80 PRECEDENCE_ADD dw 90 - PRECEDENCE_SUB dw 90 PRECEDENCE_MUL dw 100 - PRECEDENCE_DIV dw 100 - PRECEDENCE_REM dw 100 section .text extern vec_init_with @@ -42,6 +47,7 @@ global parse_args global parse_expr global parse_binary_expr global parse_primary_expr +global parse_if_expr global parse_statement global parse_block global ast_build_symtable @@ -446,11 +452,15 @@ parse_binary_expr: cmp al, TOKEN_PLUS cmove bx, word [rel PRECEDENCE_ADD] cmp al, TOKEN_MINUS - cmove bx, word [rel PRECEDENCE_SUB] + cmove bx, word [rel PRECEDENCE_ADD] cmp al, TOKEN_STAR cmove bx, word [rel PRECEDENCE_MUL] cmp al, TOKEN_SLASH - cmove bx, word [rel PRECEDENCE_DIV] + cmove bx, word [rel PRECEDENCE_MUL] + cmp al, TOKEN_EQEQ + cmove bx, word [rel PRECEDENCE_EQ] + cmp al, TOKEN_BANGEQ + cmove bx, word [rel PRECEDENCE_EQ] cmp bx, -1 je .done mov byte [rsp + 18], bl @@ -557,10 +567,20 @@ parse_statement: call peek_expect_token ; parse_block expects lbrace to still be there test rax, rax jnz .block + mov dil, TOKEN_IF + call peek_expect_token + test rax, rax + jnz .if_expr mov rdi, [rsp] ; Ast call parse_expr jmp .epilogue +.if_expr: + mov rdi, [rsp] ; Ast + call ast_parse_if_expr + ; If expressions don't require a trailing semicolon + jmp .epilogue + .block: mov rdi, [rsp] ; Ast call parse_block @@ -576,6 +596,12 @@ parse_statement: .return: mov rdi, [rsp] ; Ast call parse_expr + ; return expression requires a value + + mov rdi, [rsp] ; Ast + mov rsi, rax ; expr + call ast_place_to_value + mov byte [rsp + 8], AST_RETURN_STATEMENT ; AstNode.kind mov [rsp + 16], rax ; AstNode.data mov qword [rsp + 24], 0 ; AstNode.extra @@ -859,6 +885,116 @@ parse_assignment_expr: pop rbp ret +;; rdi: *mut Ast +;; define-fn: fn ast_parse_switch_expr(ast: *mut Ast) -> (u64, bool) +ast_parse_switch_expr: + push rbp + mov rbp, rsp + + ; start-structs + ; struct AstSwitch { + ; expr: u64, + ; cases: *const u64, + ; cases_len: usize, + ; } + ; + ; struct AstSwitchCase { + ; pattern: u64, + ; expr: u64, + ; } + ; end-structs + + pop rbp + ret + +;; rdi: *mut Ast +;; define-fn: fn ast_parse_if_expr(ast: *mut Ast) -> (u64, bool) +ast_parse_if_expr: + push rbp + mov rbp, rsp + + ; start-structs + ; struct AstIfExpr { + ; condition: u64, + ; then: u64, + ; else_: u64, + ; } + ; end-structs + + ; ast [0..8] + sub rsp, 40 + mov [rsp], rdi ; Ast + + call tokeniser_get_cursor + mov [rsp + 32], rax ; span + + mov dil, TOKEN_IF + call unwrap_token + + mov dil, TOKEN_LPARENS + call unwrap_token + + mov rdi, [rsp] ; Ast + call parse_expr + mov [rsp + 8], rax ; condition + + mov dil, TOKEN_RPARENS + call unwrap_token + + mov rdi, [rsp] ; Ast + call parse_block + mov [rsp + 16], rax ; then + + mov dil, TOKEN_ELSE + call expect_token + test rax, rax + jz .no_else + + mov dil, TOKEN_IF + call peek_expect_token + test rax, rax + jnz .else_if + + mov rdi, [rsp] ; Ast + call parse_block + mov [rsp + 24], rax ; else + jmp .after_else + +.else_if: + mov rdi, [rsp] ; Ast + call ast_parse_if_expr + mov [rsp + 24], rax ; else + jmp .after_else + +.no_else: + mov qword [rsp + 24], -1 ; else = None + +.after_else: + mov rdi, 24 ; size_of:: + mov rsi, 8 ; align_of:: + call bump_alloc + + mov rdi, rax ; AstIfExpr ptr + lea rsi, [rsp + 8] ; &AstIfExpr + mov rdx, 24 ; size_of:: + call memcpy + + mov qword [rsp + 8], AST_IF ; AstNode.kind + mov [rsp + 16], rdi ; 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 + + add rsp, 40 + pop rbp + ret + ;; rdi: *mut Ast ;; define-fn: fn ast_parse_let(ast: *mut Ast) -> (u64, bool) ast_parse_let: @@ -1441,6 +1577,8 @@ ast_walk_for_each: je .address_of cmp bl, AST_RETURN_STATEMENT je .return_statement + cmp bl, AST_IF + je .if_expr jmp .check_scope .func: @@ -1496,6 +1634,19 @@ ast_walk_for_each: push rdx ; push left index jmp .check_scope +.if_expr: + mov rbx, [rax + 8] ; AstNode.data + mov rdx, [rbx + 16] ; else index + cmp rdx, -1 + je .no_else + push rdx ; push else index +.no_else: + mov rdx, [rbx + 8] ; then index + push rdx ; push then index + mov rdx, [rbx + 0] ; condition index + push rdx ; push condition index + jmp .check_scope + .assignment: mov rbx, [rax + 8] ; AstNode.data = dest mov rdx, [rax + 16] ; AstNode.extra = source diff --git a/lang/src/ast.inc b/lang/src/ast.inc index 9966a0d..fe8cfda 100644 --- a/lang/src/ast.inc +++ b/lang/src/ast.inc @@ -14,6 +14,10 @@ section .rdata AST_VAR_DECL equ 12 ; :u8 AST_VAR_REF equ 13 ; :u8 AST_ARG equ 14 ; :u8 + AST_SWITCH equ 15 ; :u8 + AST_IF equ 16 ; :u8 + AST_ELSE equ 17 ; :u8 + AST_CALL equ 18 ; :u8 TYPE_VOID equ 1 ; :u8 TYPE_BOOL equ 2 ; :u8 @@ -21,4 +25,4 @@ section .rdata TYPE_U32 equ 4 ; :u8 TYPE_STR equ 5 ; :u8 TYPE_POINTER equ 6 ; :u8 -;; end-consts \ No newline at end of file +;; end-consts diff --git a/lang/src/codegen.asm b/lang/src/codegen.asm index 239d991..fc55532 100644 --- a/lang/src/codegen.asm +++ b/lang/src/codegen.asm @@ -1020,8 +1020,210 @@ codegen_expr: je .deref cmp bl, AST_ADDRESS_OF je .address_of + cmp bl, AST_IF + je .if_expr jmp .panic +.if_expr: + mov rbx, [rax + 8] ; AstNode.data = *AstIfExpr + mov [rsp + 16], rax ; scratch = AstNode + + mov rdx, [rbx] ; AstIfExpr.cond + mov rdi, [rsp] ; ctx + mov rsi, [rsp + 8] ; &function_ctx + call codegen_expr + mov [rsp + 24], rax ; cond operand + mov [rsp + 32], rdx + + ; cmp cond, 0 + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rsp + 24] ; left = cond + lea rdx, [rel OPERAND_ZERO] ; right = 0 + mov rcx, 'cmp ' + call codegen_binary_op_unchecked + + ; free cond + mov rdi, [rsp + 8] ; &function_ctx + lea rsi, [rsp + 24] ; cond operand + call codegen_free_operand + + ; je .branch_{else_} + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rel JE_B] + mov rdx, JE_B_len + call vec_extend + + mov rdi, [rbx + 16] ; AstIfExpr.else + lea rsi, [rsp + 24] ; scratch + mov rdx, 30 + mov rcx, 16 + call int_to_str2 + mov byte [rax + rdx], 10 + inc rdx + + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + mov rsi, rax + call vec_extend + + ; codegen then branch + mov rdx, [rbx + 8] ; AstIfExpr.then + mov rdi, [rsp] ; ctx + mov rsi, [rsp + 8] ; &function_ctx + call codegen_expr + mov [rsp + 24], rax ; then + mov [rsp + 32], rdx + + cmp rax, 0 + je .if_skip_phi + ; mov rax, then + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rel OPERAND_RAX] + lea rdx, [rsp + 24] ; src + call codegen_move_dst_src + + ; free then + mov rdi, [rsp + 8] ; &function_ctx + lea rsi, [rsp + 24] ; then operand + call codegen_free_operand + +.if_skip_phi: + ; jmp .branch_{if} + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rel JMP_PHI] + mov rdx, JMP_PHI_len + call vec_extend + + mov rdi, [rbx + 0] ; AstIfExpr.cond + lea rsi, [rsp + 24] ; scratch + mov rdx, 30 + mov rcx, 16 + call int_to_str2 + mov byte [rax + rdx], 10 + inc rdx + + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + mov rsi, rax + call vec_extend + + ; .branch_{else_}: + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rel JE_B] + add rsi, 3 + mov rdx, 2 + call vec_extend + + mov rdi, [rbx + 16] ; AstIfExpr.else + lea rsi, [rsp + 24] ; scratch + mov rdx, 30 + mov rcx, 16 + call int_to_str2 + mov byte [rax + rdx], ':' + inc rdx + mov byte [rax + rdx], 10 + inc rdx + + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + mov rsi, rax + call vec_extend + + ; codegen else branch + mov rdx, [rbx + 16] ; AstIfExpr.else + mov rdi, [rsp] ; ctx + mov rsi, [rsp + 8] ; &function_ctx + call codegen_expr + mov [rsp + 24], rax ; else + mov [rsp + 32], rdx + + cmp rax, 0 + je .if_skip_phi2 + ; mov rax, else + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rel OPERAND_RAX] + lea rdx, [rsp + 24] ; src + call codegen_move_dst_src + + ; free else + mov rdi, [rsp + 8] ; &function_ctx + lea rsi, [rsp + 24] ; else operand + call codegen_free_operand + +.if_skip_phi2: + ; .branch_{if} + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rel JMP_PHI] + add rsi, 4 + mov rdx, 4 + call vec_extend + + mov rdi, [rbx + 0] ; AstIfExpr.cond + lea rsi, [rsp + 32] ; scratch + mov rdx, 30 + mov rcx, 16 + call int_to_str2 + mov byte [rax + rdx], ':' + inc rdx + mov byte [rax + rdx], 10 + inc rdx + + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + mov rsi, rax + call vec_extend + + mov rax, qword [rsp + 24] + cmp rax, 0 + je .if_no_value + + ; dst = allocate_value + mov rdi, [rsp + 8] ; &function_ctx + mov rsi, 8 ; width + call codegen_allocate_value + mov [rsp + 40], rax + mov [rsp + 48], rdx + + cmp byte [rsp + 24], OPERAND_LAST_VALUE + ja .if_phi_place + + ; preserve width of then/else value + mov ax, word [rsp + 24 + 2] ; Operand.width + mov word [rsp + 40 + 2], ax + jmp .if_value + +.if_phi_place: + ; turn dst into it's place equivalent + cmp byte [rsp + 40], OPERAND_REGISTER + cmove ax, word [rel OPERAND_REGISTER_PLACE] + cmp byte [rsp + 40], OPERAND_RBP_VALUE + cmove ax, word [rel OPERAND_RBP_PLACE] + mov byte [rsp + 40], al + +.if_value: + ; mov dst, rax + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rsp + 40] ; dst + lea rdx, [rel OPERAND_RAX] ; rax (phi) + call codegen_move_dst_src + + mov rax, [rsp + 40] + mov rdx, [rsp + 48] + jmp .done + +.if_no_value: + xor rax, rax + xor rdx, rdx + jmp .done + .block: mov rbx, [rax + 8] ; AstNode.data mov r15, [rax + 16] ; AstNode.extra @@ -1154,6 +1356,10 @@ codegen_expr: cmove rbx, [rel SUB_] cmp rbx, -1 jne .gen_op + cmp al, TOKEN_EQEQ + je .binop_cmp + cmp al, TOKEN_BANGEQ + je .binop_cmp cmp al, TOKEN_STAR cmove rbx, [rel MUL_] cmp al, TOKEN_SLASH @@ -1161,7 +1367,73 @@ codegen_expr: cmp al, TOKEN_PERCENT cmove rbx, [rel DIV_] cmp rbx, -1 - je .panic ; unknown operator + jne .mul_div + jmp .panic ; unknown operator + +.binop_cmp: + mov bl, al ; operator + mov rdi, [rsp + 8] ; &function_ctx + mov rsi, [rsp] ; ctx + lea rsi, [rsi + 8] ; &ctx.text + lea rdx, [rsp + 32] ; left operand + lea rcx, [rsp + 48] ; right operand + mov r8, 'cmp ' + mov r9, 1 + call codegen_binary_op_rm64_rm64 + mov [rsp + 32], rax + mov [rsp + 40], rdx + + ; free operand + mov rdi, [rsp + 8] ; &function_ctx + lea rsi, [rsp + 32] ; left operand + call codegen_free_operand + + ; dst = allocate_value(1) + mov rdi, [rsp + 8] ; &function_ctx + mov rsi, 1 ; width + call codegen_allocate_value + mov [rsp + 32], rax + mov [rsp + 40], rdx + + xor rax, rax + cmp bl, TOKEN_EQEQ + cmove rax, [rel SETE_] + cmp bl, TOKEN_BANGEQ + cmove rax, [rel SETNE_] + cmp bl, TOKEN_LEQ + cmove rax, [rel SETBE_] + cmp bl, TOKEN_LT + cmove rax, [rel SETB_] + cmp bl, TOKEN_GEQ + cmove rax, [rel SETAE_] + cmp bl, TOKEN_GT + cmove rax, [rel SETA_] + cmp rax, 0 + je .panic ; unknown cmp operator + mov [rsp + 48], rax + + ; "{rax} dst\n" + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rsp + 48] ; op + mov rdx, 6 + call vec_extend + + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + lea rsi, [rsp + 32] ; dst + call codegen_write_operand + + mov rdi, [rsp] ; ctx + lea rdi, [rdi + 8] ; &ctx.text + mov byte [rsp + 48], 10 ; newline + lea rsi, [rsp + 48] + call vec_push + + mov rax, [rsp + 32] + mov rdx, [rsp + 40] + jmp .done + .mul_div: ; mul/div need to clobber rax:rdx @@ -1316,6 +1588,7 @@ codegen_expr: lea rdx, [rsp + 32] ; left operand lea rcx, [rsp + 48] ; right operand mov r8, rbx ; operation + mov r9, 0 call codegen_binary_op_rm64_rm64 jmp .done @@ -1612,6 +1885,8 @@ section .rdata OPERAND_RBP_V dq 0x0008_0002, 0 align 8 OPERAND_RBP_P dq 0x0008_0009, 0 + align 8 + OPERAND_ZERO dq 0x0001_000b, 0 section .text @@ -1836,19 +2111,23 @@ codegen_write_width: ;; rdx: lhs: *Operand ;; rcx: rhs: *Operand ;; r8: op: [u8; 8] +;; r9: discard_result ;; Generates: {op} {lhs}, {rhs} for a binary operation that has the encodings rN, rmN and rmN, rN +;; define-fn: fn codegen_binary_op_rm64_rm64(function_ctx: *mut FunctionCtx, text: *mut BlobVec, lhs: *const Operand, rhs: *const Operand, op: [u8; 8], discard_result: bool) -> *const Operand codegen_binary_op_rm64_rm64: push rbp mov rbp, rsp push rbx - ; dst [32..48] - sub rsp, 56 + ; discard_result [56..57] + ; dst [40..56] + sub rsp, 64 mov [rsp], rdi ; *function_ctx mov [rsp + 8], rsi ; *text mov [rsp + 16], rdx ; lhs mov [rsp + 24], rcx ; rhs mov [rsp + 32], r8 ; op + mov byte [rsp + 48], r9b ; discard_result ; match (lhs.kind, rhs.kind) { cmp byte [rdx + 0], OPERAND_REGISTER @@ -1961,6 +2240,15 @@ codegen_binary_op_rm64_rm64: mov rsi, [rsp + 16] ; lhs call codegen_free_operand + cmp byte [rsp + 56], 0 + je .rax_rhs_done + ; mov rhs, rax + mov rdi, [rsp + 8] ; *text + mov rsi, [rsp + 24] ; rhs + lea rdx, [rel OPERAND_RAX] + call codegen_move_dst_src + +.rax_rhs_done: ; ret rhs mov rbx, [rsp + 24] ; rhs mov rax, [rbx] @@ -2007,13 +2295,13 @@ codegen_binary_op_rm64_rm64: call codegen_free_operand ; ret dst - mov rax, [rsp + 32] ; dst - mov rdx, [rsp + 40] + mov rax, [rsp + 40] ; dst + mov rdx, [rsp + 48] ; } .epilogue: - add rsp, 56 + add rsp, 64 pop rbx pop rbp ret @@ -2243,4 +2531,18 @@ section .rdata SUB_ dq "sub " MUL_ dq "mul " DIV_ dq "div " + SETE_ dq "sete " + SETNE_ dq "setne " + SETA_ dq "seta " + SETAE_ dq "setae " + SETB_ dq "setb " + SETBE_ dq "setbe " + SETL_ dq "setl " + SETLE_ dq "setle " + SETG_ dq "setg " + SETGE_ dq "setge " + JE_B dq "je .B" + JE_B_len equ $ - JE_B + JMP_PHI dq "jmp .PHI" + JMP_PHI_len equ $ - JMP_PHI diff --git a/lang/src/tokeniser.inc b/lang/src/tokeniser.inc index 1a95a12..6105b78 100644 --- a/lang/src/tokeniser.inc +++ b/lang/src/tokeniser.inc @@ -62,6 +62,11 @@ LEXEMES: dq LEX_DOT2 dq LEX_DOT dq LEX_BACKTICK + dq LEX_SWITCH + dq LEX_AS + dq LEX_MATCH + dq LEX_WHILE + dq LEX_FOR align 8 TOKENS: @@ -126,6 +131,11 @@ TOKENS: db TOKEN_DOT2 ;; 53 db TOKEN_DOT ;; 52 db TOKEN_BACKTICK ;; 55 + db TOKEN_SWITCH + db TOKEN_AS + db TOKEN_MATCH + db TOKEN_WHILE + db TOKEN_FOR align 8 LEXEME_LENS: @@ -190,9 +200,14 @@ LEXEME_LENS: dq LEX_DOT2_len dq LEX_DOT_len dq LEX_BACKTICK_len + dq LEX_SWITCH_len + dq LEX_AS_len + dq LEX_MATCH_len + dq LEX_WHILE_len + dq LEX_FOR_len align 8 -NUM_LEXEMES: dq 61 +NUM_LEXEMES: dq 66 LEX_NOT_A_LEXEME db "", 0 LEX_LET db "let" @@ -315,6 +330,16 @@ NUM_LEXEMES: dq 61 LEX_DOT_len equ $ - LEX_DOT LEX_BACKTICK db "`" LEX_BACKTICK_len equ $ - LEX_BACKTICK + LEX_SWITCH db "switch" + LEX_SWITCH_len equ $ - LEX_SWITCH + LEX_AS db "as" + LEX_AS_len equ $ - LEX_AS + LEX_MATCH db "match" + LEX_MATCH_len equ $ - LEX_MATCH + LEX_WHILE db "while" + LEX_WHILE_len equ $ - LEX_WHILE + LEX_FOR db "for" + LEX_FOR_len equ $ - LEX_FOR LEX_IDENT db "" LEX_IDENT_len equ $ - LEX_IDENT LEX_NUMBER db "" @@ -386,8 +411,13 @@ NUM_LEXEMES: dq 61 TOKEN_DOT2 equ 58 ; :u8 TOKEN_DOT equ 59 ; :u8 TOKEN_BACKTICK equ 60 ; :u8 - TOKEN_IDENT equ 61 ; :u8 - TOKEN_NUMBER equ 62 ; :u8 - TOKEN_STRING equ 63 ; :u8 - TOKEN_COMMENT equ 64 ; :u8 + TOKEN_SWITCH equ 61 ; :u8 + TOKEN_AS equ 62 ; :u8 + TOKEN_MATCH equ 63 ; :u8 + TOKEN_WHILE equ 64 ; :u8 + TOKEN_FOR equ 65 ; :u8 + TOKEN_IDENT equ 66 ; :u8 + TOKEN_NUMBER equ 67 ; :u8 + TOKEN_STRING equ 68 ; :u8 + TOKEN_COMMENT equ 69 ; :u8 ;; end-consts diff --git a/lang/tests/ast.rs b/lang/tests/ast.rs index 1eabcfa..31705a4 100644 --- a/lang/tests/ast.rs +++ b/lang/tests/ast.rs @@ -12,7 +12,7 @@ unsafe extern "C" { unsafe fn tokeniser_init_buf(bytes: *const u8, len: usize) -> (); } -use util::defs::{parse_func, Ast}; +use util::defs::{parse_expr, parse_func, Ast}; fn main() { unsafe { @@ -58,57 +58,67 @@ fn main() { }; } - // print_ast( - // b"fn main() -> void { return 1 * 2 + 3 * 4; }", - // |ast| unsafe { parse_func(ast) }, - // ); + print_ast( + b"fn main() -> void { return 1 * 2 + 3 * 4; }", + |ast| unsafe { parse_func(ast) }, + ); - // print_ast(b"3 + 4", |ast| unsafe { parse_expr(ast) }); - // print_ast(b"fn main() -> void { return 1 + 2; }", |ast| unsafe { - // parse_func(ast) - // }); - // print_ast( - // b"fn main() -> void { ;;;return (1 + (2)); }", - // |ast| unsafe { parse_func(ast) }, - // ); - // print_ast( - // b"fn main() -> void { return (1 + (2 * 3)) / 4; }", - // |ast| unsafe { parse_func(ast) }, - // ); - // print_ast(b"fn main() -> void { return 1 + 2 * 3; }", |ast| unsafe { - // parse_func(ast) - // }); + print_ast(b"3 + 4", |ast| unsafe { parse_expr(ast) }); + print_ast(b"fn main() -> void { return 1 + 2; }", |ast| unsafe { + parse_func(ast) + }); + print_ast( + b"fn main() -> void { ;;;return (1 + (2)); }", + |ast| unsafe { parse_func(ast) }, + ); + print_ast( + b"fn main() -> void { return (1 + (2 * 3)) / 4; }", + |ast| unsafe { parse_func(ast) }, + ); + 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) - // }); - // print_ast( - // b"fn main(a: u32) -> void { let x: u32 = a + 4; }", - // |ast| unsafe { parse_func(ast) }, - // ); - // print_ast( - // b"fn main(a: u32) -> void { - // let y: u32 = a + 4; - // let y: *u32 = &y; - // return *y; - // }", - // |ast| unsafe { parse_func(ast) }, - // ); - // print_ast( - // b"fn main(a: u32) -> void { - // let y: u32 = a + 4; - // { - // let y: u32 = 10; - // } - // let y: *u32 = &y; - // return *y; - // }", - // |ast| unsafe { parse_func(ast) }, - // ); + print_ast(b"fn main() -> void { let x: u32 = 4; }", |ast| unsafe { + parse_func(ast) + }); + print_ast( + b"fn main(a: u32) -> void { let x: u32 = a + 4; }", + |ast| unsafe { parse_func(ast) }, + ); + print_ast( + b"fn main(a: u32) -> void { + let y: u32 = a + 4; + let y: *u32 = &y; + return *y; + }", + |ast| unsafe { parse_func(ast) }, + ); + print_ast( + b"fn main(a: u32) -> void { + let y: u32 = a + 4; + { + let y: u32 = 10; + } + let y: *u32 = &y; + return *y; + }", + |ast| unsafe { parse_func(ast) }, + ); print_ast( b"fn main(a: *u32, b: u32) -> void { *a = b; a = &b; +}", + |ast| unsafe { parse_func(ast) }, + ); + print_ast( + b"fn main(a: u32) -> void { + if (a == 0) { + return 1; + } else { + return 0; + } }", |ast| unsafe { parse_func(ast) }, ); diff --git a/lang/tests/codegen.rs b/lang/tests/codegen.rs index fdd1af7..54b52a2 100644 --- a/lang/tests/codegen.rs +++ b/lang/tests/codegen.rs @@ -91,10 +91,23 @@ fn main() { }; } +// print_ast( +// b"fn main(a: u32) -> void { +// let b: *u32 = &a; +// return 5 + *b; +// }", +// |ast| unsafe { parse_func(ast) }, +// ); + print_ast( b"fn main(a: u32) -> void { -let b: *u32 = &a; - return 5 + *b; +let x: u32 = 10; +if (a == 42) { +x = 7; +} else { +x = 8; +} +return x; }", |ast| unsafe { parse_func(ast) }, ); diff --git a/lang/tests/shared/ast_debug.rs b/lang/tests/shared/ast_debug.rs index 700a6a0..6486af3 100644 --- a/lang/tests/shared/ast_debug.rs +++ b/lang/tests/shared/ast_debug.rs @@ -4,7 +4,7 @@ impl core::fmt::Display for util::defs::AstNode { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { use util::defs::{ BinaryExpr, AST_ADDRESS_OF, AST_ARG, AST_ASSIGNMENT, AST_BINARY_OP, AST_BLOCK, - AST_DEREF, AST_FUNCTION, AST_NUMBER, AST_PLACE_TO_VALUE, AST_RETURN_STATEMENT, + AST_DEREF, AST_FUNCTION, AST_IF, AST_NUMBER, AST_PLACE_TO_VALUE, AST_RETURN_STATEMENT, AST_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF, }; match self.kind { @@ -98,6 +98,19 @@ impl core::fmt::Display for util::defs::AstNode { std::slice::from_raw_parts(self.data.cast::(), self.extra as usize) }) } + AST_IF => { + let if_node = unsafe { self.data.cast::().read() }; + write!( + f, + "If(cond: {}, then_branch: {}, else_branch: {:?})", + if_node.condition, + if_node.then, + match if_node.else_ { + u64::MAX => None, + v => Some(v), + } + ) + } AST_PLACE_TO_VALUE => { write!(f, "PlaceToValue(place: {})", self.data as usize) } diff --git a/lang/tests/shared/defs.rs b/lang/tests/shared/defs.rs index 682da45..d31e46f 100644 --- a/lang/tests/shared/defs.rs +++ b/lang/tests/shared/defs.rs @@ -12,6 +12,8 @@ unsafe extern "C" { 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_switch_expr(ast: *mut Ast) -> (u64, bool); + pub unsafe fn ast_parse_if_expr(ast: *mut Ast) -> (u64, bool); pub unsafe fn ast_parse_let(ast: *mut Ast) -> (u64, bool); pub unsafe fn symkey_cmp(a: *const SymKey, b: *const SymKey) -> i32; pub unsafe fn ast_build_symtable(ast: *mut Ast, root_index: u64, symtable: *mut core::mem::MaybeUninit); @@ -27,6 +29,7 @@ unsafe extern "C" { pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> (); pub unsafe fn codegen_push_pop_used_registers(text: *mut Vec, function_ctx: &FunctionCtx, pop: bool) -> u8; pub unsafe fn codegen_expr(ctx: *const CodegenCtx, function_ctx: &FunctionCtx, expr_idx: u64) -> (u64, bool); + pub unsafe fn codegen_binary_op_rm64_rm64(function_ctx: *mut FunctionCtx, text: *mut BlobVec, lhs: *const Operand, rhs: *const Operand, op: [u8; 8], discard_result: bool) -> *const Operand; pub unsafe fn vec_insert_many(vec: *mut BlobVec, index: usize, data: *const u8, count: usize); pub unsafe fn vec_extend(vec: *mut BlobVec, elements: *const u8, count: usize) -> (); } @@ -52,6 +55,10 @@ pub const AST_ADDRESS_OF: u8 = 11; pub const AST_VAR_DECL: u8 = 12; pub const AST_VAR_REF: u8 = 13; pub const AST_ARG: u8 = 14; +pub const AST_SWITCH: u8 = 15; +pub const AST_IF: u8 = 16; +pub const AST_ELSE: u8 = 17; +pub const AST_CALL: u8 = 18; pub const TYPE_VOID: u8 = 1; pub const TYPE_BOOL: u8 = 2; pub const TYPE_I32: u8 = 3; @@ -132,10 +139,15 @@ pub const TOKEN_DOT3: u8 = 57; pub const TOKEN_DOT2: u8 = 58; pub const TOKEN_DOT: u8 = 59; pub const TOKEN_BACKTICK: u8 = 60; -pub const TOKEN_IDENT: u8 = 61; -pub const TOKEN_NUMBER: u8 = 62; -pub const TOKEN_STRING: u8 = 63; -pub const TOKEN_COMMENT: u8 = 64; +pub const TOKEN_SWITCH: u8 = 61; +pub const TOKEN_AS: u8 = 62; +pub const TOKEN_MATCH: u8 = 63; +pub const TOKEN_WHILE: u8 = 64; +pub const TOKEN_FOR: u8 = 65; +pub const TOKEN_IDENT: u8 = 66; +pub const TOKEN_NUMBER: u8 = 67; +pub const TOKEN_STRING: u8 = 68; +pub const TOKEN_COMMENT: u8 = 69; #[repr(C)] #[derive(Debug)] @@ -194,6 +206,29 @@ pub struct BinaryExpr { pub right: u64, } +#[repr(C)] +#[derive(Debug)] +pub struct AstSwitch { + pub expr: u64, + pub cases: *const u64, + pub cases_len: usize, +} + +#[repr(C)] +#[derive(Debug)] +pub struct AstSwitchCase { + pub pattern: u64, + pub expr: u64, +} + +#[repr(C)] +#[derive(Debug)] +pub struct AstIfExpr { + pub condition: u64, + pub then: u64, + pub else_: u64, +} + #[repr(C)] #[derive(Debug)] pub struct AstVarDecl {