Compare commits
14 commits
e79af01925
...
da2a298baf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da2a298baf | ||
|
|
d793a3251f | ||
|
|
e3e0d6843f | ||
|
|
d5de30d9e7 | ||
|
|
6bdd2ef18a | ||
|
|
c7f026a678 | ||
|
|
9b4d42ba3a | ||
|
|
555f79f00e | ||
|
|
d754f8c4b9 | ||
|
|
402d295fff | ||
|
|
94d5d9e15b | ||
|
|
c52b7ab8de | ||
|
|
6041ec5102 | ||
|
|
1201a6c45a |
|
|
@ -31,7 +31,7 @@
|
||||||
just-formatter
|
just-formatter
|
||||||
just-lsp
|
just-lsp
|
||||||
gdb
|
gdb
|
||||||
gdbgui
|
rr
|
||||||
nasm
|
nasm
|
||||||
nasmfmt
|
nasmfmt
|
||||||
git
|
git
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Makefile: Compile and link main.asm using nasm and mold, intermediate files in target/
|
# Makefile: Compile and link main.asm using nasm and mold, intermediate files in target/
|
||||||
|
|
||||||
TARGET_DIR := target
|
TARGET_DIR := target
|
||||||
SRC := src/lib.asm src/int_to_str.asm src/vec.asm src/tokeniser.asm src/file.asm src/alloc.asm src/ast.asm
|
SRC := src/lib.asm src/int_to_str.asm src/vec.asm src/tokeniser.asm src/file.asm src/alloc.asm src/ast.asm src/codegen.asm
|
||||||
OBJ := $(patsubst src/%.asm,$(TARGET_DIR)/%.o,$(SRC))
|
OBJ := $(patsubst src/%.asm,$(TARGET_DIR)/%.o,$(SRC))
|
||||||
|
|
||||||
BIN_SRC := src/main.asm src/panic.asm
|
BIN_SRC := src/main.asm src/panic.asm
|
||||||
|
|
|
||||||
157
lang/src/ast.asm
157
lang/src/ast.asm
|
|
@ -1,32 +1,9 @@
|
||||||
default rel
|
default rel
|
||||||
|
|
||||||
%include "src/tokeniser.inc"
|
%include "src/tokeniser.inc"
|
||||||
|
%include "src/ast.inc"
|
||||||
|
|
||||||
section .rdata
|
section .rdata
|
||||||
;; start-consts
|
|
||||||
AST_FUNCTION equ 1 ; :u8
|
|
||||||
AST_BLOCK equ 2 ; :u8
|
|
||||||
AST_VARIABLE equ 3 ; :u8
|
|
||||||
AST_NUMBER equ 4 ; :u8
|
|
||||||
AST_BINARY_OP equ 5 ; :u8
|
|
||||||
AST_RETURN_STATEMENT equ 6 ; :u8
|
|
||||||
AST_VALUE_TO_PLACE equ 7 ; :u8
|
|
||||||
AST_PLACE_TO_VALUE equ 8 ; :u8
|
|
||||||
AST_ASSIGNMENT equ 9 ; :u8
|
|
||||||
AST_DEREF equ 10 ; :u8
|
|
||||||
AST_ADDRESS_OF equ 11 ; :u8
|
|
||||||
AST_VAR_DECL equ 12 ; :u8
|
|
||||||
AST_VAR_REF equ 13 ; :u8
|
|
||||||
AST_ARG equ 14 ; :u8
|
|
||||||
|
|
||||||
TYPE_VOID equ 1 ; :u8
|
|
||||||
TYPE_BOOL equ 2 ; :u8
|
|
||||||
TYPE_I32 equ 3 ; :u8
|
|
||||||
TYPE_U32 equ 4 ; :u8
|
|
||||||
TYPE_STR equ 5 ; :u8
|
|
||||||
TYPE_POINTER equ 6 ; :u8
|
|
||||||
;; end-consts
|
|
||||||
|
|
||||||
PRECEDENCE_ADD equ 90
|
PRECEDENCE_ADD equ 90
|
||||||
PRECEDENCE_SUB equ 90
|
PRECEDENCE_SUB equ 90
|
||||||
PRECEDENCE_MUL equ 100
|
PRECEDENCE_MUL equ 100
|
||||||
|
|
@ -591,8 +568,17 @@ parse_statement:
|
||||||
call expect_token
|
call expect_token
|
||||||
test rax, rax
|
test rax, rax
|
||||||
jnz .let
|
jnz .let
|
||||||
|
mov dil, TOKEN_LBRACE
|
||||||
|
call peek_expect_token ; parse_block expects lbrace to still be there
|
||||||
|
jnz .block
|
||||||
jmp .panic
|
jmp .panic
|
||||||
|
|
||||||
|
.block:
|
||||||
|
mov rdi, [rsp] ; Ast
|
||||||
|
call parse_block
|
||||||
|
; Blocks don't require a trailing semicolon
|
||||||
|
jmp .epilogue
|
||||||
|
|
||||||
.let:
|
.let:
|
||||||
mov rdi, [rsp] ; Ast
|
mov rdi, [rsp] ; Ast
|
||||||
call ast_parse_let
|
call ast_parse_let
|
||||||
|
|
@ -617,6 +603,7 @@ parse_statement:
|
||||||
mov dil, TOKEN_SEMI
|
mov dil, TOKEN_SEMI
|
||||||
call unwrap_token
|
call unwrap_token
|
||||||
mov rax, [rsp] ; expression
|
mov rax, [rsp] ; expression
|
||||||
|
.epilogue:
|
||||||
add rsp, 40
|
add rsp, 40
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
@ -652,12 +639,19 @@ parse_block:
|
||||||
mov rdx, 0 ; drop = None
|
mov rdx, 0 ; drop = None
|
||||||
mov rcx, 64 ; capacity
|
mov rcx, 64 ; capacity
|
||||||
call vec_init_with
|
call vec_init_with
|
||||||
|
nop
|
||||||
.loop:
|
.loop:
|
||||||
mov dil, TOKEN_RBRACE
|
mov dil, TOKEN_RBRACE
|
||||||
call peek_expect_token
|
call peek_expect_token
|
||||||
test rax, rax
|
test rax, rax
|
||||||
jnz .done
|
jnz .done
|
||||||
|
|
||||||
|
; skip semicolons
|
||||||
|
mov dil, TOKEN_SEMI
|
||||||
|
call expect_token
|
||||||
|
test rax, rax
|
||||||
|
jnz .loop
|
||||||
|
|
||||||
mov rdi, [rsp + 56] ; Ast
|
mov rdi, [rsp + 56] ; Ast
|
||||||
call parse_statement
|
call parse_statement
|
||||||
lea rdi, [rsp + 8] ; vec
|
lea rdi, [rsp + 8] ; vec
|
||||||
|
|
@ -666,6 +660,10 @@ parse_block:
|
||||||
call vec_push
|
call vec_push
|
||||||
jmp .loop
|
jmp .loop
|
||||||
.done:
|
.done:
|
||||||
|
; eat the closing brace
|
||||||
|
mov dil, TOKEN_RBRACE
|
||||||
|
call unwrap_token
|
||||||
|
|
||||||
mov rdi, [rsp + 56] ; Ast
|
mov rdi, [rsp + 56] ; Ast
|
||||||
mov qword [rsp], AST_BLOCK ; AstNode.kind
|
mov qword [rsp], AST_BLOCK ; AstNode.kind
|
||||||
mov rsi, [rsp + 64] ; span
|
mov rsi, [rsp + 64] ; span
|
||||||
|
|
@ -1154,6 +1152,11 @@ ast_build_symtable:
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
section .rdata
|
||||||
|
ANONYMOUS_SCOPE_NAME db "<anonymous>"
|
||||||
|
ANONYMOUS_SCOPE_NAME_LEN equ $ - ANONYMOUS_SCOPE_NAME
|
||||||
|
section .text
|
||||||
|
|
||||||
;; symtable is a sorted vec pretending to be a b-tree:
|
;; symtable is a sorted vec pretending to be a b-tree:
|
||||||
;; entries are sorted by a key in order to get the following ordering:
|
;; entries are sorted by a key in order to get the following ordering:
|
||||||
;; scope (index0) -> (ident0)
|
;; scope (index0) -> (ident0)
|
||||||
|
|
@ -1242,8 +1245,29 @@ ast_build_symtable_for_each:
|
||||||
je .var_decl
|
je .var_decl
|
||||||
cmp bl, AST_ARG
|
cmp bl, AST_ARG
|
||||||
je .arg
|
je .arg
|
||||||
|
cmp bl, AST_BLOCK
|
||||||
|
je .block
|
||||||
jmp .done
|
jmp .done
|
||||||
|
.block:
|
||||||
|
; insert scope entry
|
||||||
|
|
||||||
|
lea rdx, [rel ANONYMOUS_SCOPE_NAME]
|
||||||
|
mov rcx, ANONYMOUS_SCOPE_NAME_LEN
|
||||||
|
mov [rsp + 72], rdx ; SymEntry.index
|
||||||
|
mov [rsp + 80], rcx ; SymEntry.extra
|
||||||
|
jmp .insert_scope
|
||||||
|
|
||||||
.func:
|
.func:
|
||||||
|
; use function name as scope name
|
||||||
|
|
||||||
|
mov rbx, [rax + 8] ; AstNode.data
|
||||||
|
mov rdx, [rbx + 0] ; Func.name
|
||||||
|
mov rcx, [rbx + 8] ; Func.name_len
|
||||||
|
|
||||||
|
mov [rsp + 72], rdx ; SymEntry.index
|
||||||
|
mov [rsp + 80], rcx ; SymEntry.extra
|
||||||
|
|
||||||
|
.insert_scope:
|
||||||
; insert scope entry
|
; insert scope entry
|
||||||
mov byte [rsp + 32], SYM_KEY_SCOPE ; SymKey.kind
|
mov byte [rsp + 32], SYM_KEY_SCOPE ; SymKey.kind
|
||||||
mov rdx, [rsp + 16] ; index
|
mov rdx, [rsp + 16] ; index
|
||||||
|
|
@ -1253,13 +1277,6 @@ ast_build_symtable_for_each:
|
||||||
mov qword [rsp + 56], 1 ; SymKey.ident
|
mov qword [rsp + 56], 1 ; SymKey.ident
|
||||||
mov qword [rsp + 64], 0 ; SymKey.ident_len
|
mov qword [rsp + 64], 0 ; SymKey.ident_len
|
||||||
|
|
||||||
mov rbx, [rax + 8] ; AstNode.data
|
|
||||||
mov rdx, [rbx + 0] ; Func.name
|
|
||||||
mov rcx, [rbx + 8] ; Func.name_len
|
|
||||||
|
|
||||||
mov [rsp + 72], rdx ; SymEntry.index
|
|
||||||
mov [rsp + 80], rcx ; SymEntry.extra
|
|
||||||
|
|
||||||
mov rdi, [rsp + 8] ; Ctx.symtable
|
mov rdi, [rsp + 8] ; Ctx.symtable
|
||||||
lea rsi, [rsp + 32] ; &SymEntry
|
lea rsi, [rsp + 32] ; &SymEntry
|
||||||
mov rcx, 0 ; cmp_ctx
|
mov rcx, 0 ; cmp_ctx
|
||||||
|
|
@ -1316,7 +1333,7 @@ ast_build_symtable_for_each:
|
||||||
|
|
||||||
.arg:
|
.arg:
|
||||||
; insert variable entry
|
; insert variable entry
|
||||||
mov byte [rsp + 32], SYM_KEY_ARG ; SymKey.kind
|
mov byte [rsp + 32], SYM_KEY_VAR ; SymKey.kind
|
||||||
|
|
||||||
mov rdx, [rax + 24] ; AstNode.span
|
mov rdx, [rax + 24] ; AstNode.span
|
||||||
mov qword [rsp + 48], rdx ; SymKey.span
|
mov qword [rsp + 48], rdx ; SymKey.span
|
||||||
|
|
@ -1459,6 +1476,12 @@ ast_walk_for_each:
|
||||||
jmp .check_scope
|
jmp .check_scope
|
||||||
|
|
||||||
.block:
|
.block:
|
||||||
|
; push scope
|
||||||
|
push qword [rbp + 32] ; scope-ptr
|
||||||
|
push qword [rbp + 40] ; current_index
|
||||||
|
mov [rbp + 32], rsp ; update current_scope
|
||||||
|
|
||||||
|
; push statements onto stack
|
||||||
mov rbx, [rax + 8] ; AstNode.data
|
mov rbx, [rax + 8] ; AstNode.data
|
||||||
mov r15, [rax + 16] ; AstNode.extra
|
mov r15, [rax + 16] ; AstNode.extra
|
||||||
|
|
||||||
|
|
@ -1467,7 +1490,7 @@ ast_walk_for_each:
|
||||||
jle .stmt_loop_done
|
jle .stmt_loop_done
|
||||||
dec r15
|
dec r15
|
||||||
mov rdx, [rbx + r15*8] ; statement index
|
mov rdx, [rbx + r15*8] ; statement index
|
||||||
push rdx ; push statement index
|
push rdx ; push statement index
|
||||||
jmp .stmt_loop
|
jmp .stmt_loop
|
||||||
.stmt_loop_done:
|
.stmt_loop_done:
|
||||||
jmp .check_scope
|
jmp .check_scope
|
||||||
|
|
@ -1560,14 +1583,21 @@ ast_resolve_var_refs_for_each:
|
||||||
cmp bl, AST_VAR_REF
|
cmp bl, AST_VAR_REF
|
||||||
jne .epilogue
|
jne .epilogue
|
||||||
|
|
||||||
|
.var_ref:
|
||||||
; lookup variable in symbol table
|
; lookup variable in symbol table
|
||||||
|
|
||||||
; binary search lower bound
|
; binary search lower bound
|
||||||
mov byte [rsp + 24 + 0], SYM_KEY_START_LOCALS ; SymKey.kind
|
mov byte [rsp + 24 + 0], SYM_KEY_START_LOCALS ; SymKey.kind
|
||||||
mov qword [rsp + 24 + 8], 0 ; SymKey.scope_index
|
mov rax, [rsp + 80] ; scope
|
||||||
|
mov [rsp + 24 + 8], rax ; SymKey.scope_index
|
||||||
mov qword [rsp + 24 + 16], 0 ; SymKey.span
|
mov qword [rsp + 24 + 16], 0 ; SymKey.span
|
||||||
mov qword [rsp + 24 + 24], 1 ; SymKey.name
|
; name
|
||||||
mov qword [rsp + 24 + 32], 0 ; SymKey.name_len
|
mov rax, [rsp + 16] ; *AstNode
|
||||||
|
mov rbx, [rax + 8] ; AstNode.data
|
||||||
|
mov rax, [rbx + 8] ; AstVarRef.name
|
||||||
|
mov rbx, [rbx + 16] ; AstVarRef.name_len
|
||||||
|
mov [rsp + 24 + 24], rax ; SymKey.ident
|
||||||
|
mov [rsp + 24 + 32], rbx ; SymKey.ident_len
|
||||||
|
|
||||||
; binary search in symbol table
|
; binary search in symbol table
|
||||||
mov rdi, [rsp + 8] ; *Ctx
|
mov rdi, [rsp + 8] ; *Ctx
|
||||||
|
|
@ -1584,11 +1614,6 @@ ast_resolve_var_refs_for_each:
|
||||||
mov rax, [rsp + 16] ; *AstNode
|
mov rax, [rsp + 16] ; *AstNode
|
||||||
mov rbx, [rax + 24] ; AstNode.span
|
mov rbx, [rax + 24] ; AstNode.span
|
||||||
mov [rsp + 24 + 16], rbx ; SymKey.span
|
mov [rsp + 24 + 16], rbx ; SymKey.span
|
||||||
mov rbx, [rax + 8] ; AstNode.data
|
|
||||||
mov rax, [rbx + 8] ; AstVarRef.name
|
|
||||||
mov rbx, [rbx + 16] ; AstVarRef.name_len
|
|
||||||
mov [rsp + 24 + 24], rax ; SymKey.ident
|
|
||||||
mov [rsp + 24 + 32], rbx ; SymKey.ident_len
|
|
||||||
|
|
||||||
; binary search in symbol table
|
; binary search in symbol table
|
||||||
mov rdi, [rsp + 8] ; *Ctx
|
mov rdi, [rsp + 8] ; *Ctx
|
||||||
|
|
@ -1602,16 +1627,60 @@ ast_resolve_var_refs_for_each:
|
||||||
|
|
||||||
.fixup:
|
.fixup:
|
||||||
cmp rax, [rsp + 88] ; lower_bound
|
cmp rax, [rsp + 88] ; lower_bound
|
||||||
jl .panic
|
jl .parent
|
||||||
|
|
||||||
mov rdi, [rsp + 8] ; *Ctx
|
mov rdi, [rsp + 8] ; *Ctx
|
||||||
mov rsi, rax ; index
|
mov rsi, rax ; index
|
||||||
call vec_get
|
call vec_get
|
||||||
mov rax, [rax + 40] ; SymEntry.index
|
mov rbx, rax ; *SymEntry
|
||||||
|
|
||||||
|
; compare symbol ident with var_ref ident
|
||||||
|
mov rdi, [rbx + 24] ; SymEntry.key.ident
|
||||||
|
mov rsi, [rbx + 32] ; SymEntry.key.ident_len
|
||||||
|
|
||||||
|
mov rax, [rsp + 16] ; *AstNode
|
||||||
|
mov rax, [rax + 8] ; AstNode.data
|
||||||
|
mov rdx, [rax + 8] ; AstVarRef.name
|
||||||
|
mov rcx, [rax + 16] ; AstVarRef.name_len
|
||||||
|
call strcmp
|
||||||
|
test rax, rax
|
||||||
|
jnz .parent
|
||||||
|
|
||||||
|
; load SymEntry.index
|
||||||
|
mov rax, [rbx + 40] ; SymEntry.index
|
||||||
|
|
||||||
mov rdx, [rsp + 16] ; *AstNode
|
mov rdx, [rsp + 16] ; *AstNode
|
||||||
mov rdx, [rdx + 8] ; AstNode.data
|
mov rdx, [rdx + 8] ; AstNode.data
|
||||||
mov [rdx + 0], rax ; AstVarRef.resolved_index
|
mov [rdx + 0], rax ; AstVarRef.resolved_index
|
||||||
|
jmp .epilogue
|
||||||
|
|
||||||
|
.parent:
|
||||||
|
; binary search for parent scope
|
||||||
|
mov byte [rsp + 24 + 0], SYM_KEY_PARENT_SCOPE ; SymKey.kind
|
||||||
|
mov rax, [rsp + 80] ; scope
|
||||||
|
mov [rsp + 24 + 8], rax ; SymKey.scope_index
|
||||||
|
mov qword [rsp + 24 + 16], 0 ; SymKey.span
|
||||||
|
mov qword [rsp + 24 + 24], 1 ; SymKey.ident
|
||||||
|
mov qword [rsp + 24 + 32], 0 ; SymKey.ident_len
|
||||||
|
|
||||||
|
; binary search in symbol table
|
||||||
|
mov rdi, [rsp + 8] ; *Ctx
|
||||||
|
lea rsi, [rsp + 24] ; &SymKey
|
||||||
|
mov rdx, symkey_cmp ; cmp
|
||||||
|
mov rcx, 0 ; cmp_ctx
|
||||||
|
call vec_binary_search_by
|
||||||
|
test rdx, rdx
|
||||||
|
jnz .panic ; can't find the symbol entry for this var-ref
|
||||||
|
|
||||||
|
; load parent scope sym entry
|
||||||
|
mov rdi, [rsp + 8] ; *Ctx
|
||||||
|
mov rsi, rax ; index
|
||||||
|
call vec_get
|
||||||
|
mov rbx, rax ; *SymEntry
|
||||||
|
|
||||||
|
mov rdx, [rax + 40] ; SymEntry.index (parent scope)
|
||||||
|
mov [rsp + 80], rdx ; update scope
|
||||||
|
jmp .var_ref
|
||||||
|
|
||||||
.epilogue:
|
.epilogue:
|
||||||
add rsp, 96
|
add rsp, 96
|
||||||
|
|
|
||||||
24
lang/src/ast.inc
Normal file
24
lang/src/ast.inc
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
section .rdata
|
||||||
|
;; start-consts
|
||||||
|
AST_FUNCTION equ 1 ; :u8
|
||||||
|
AST_BLOCK equ 2 ; :u8
|
||||||
|
AST_VARIABLE equ 3 ; :u8
|
||||||
|
AST_NUMBER equ 4 ; :u8
|
||||||
|
AST_BINARY_OP equ 5 ; :u8
|
||||||
|
AST_RETURN_STATEMENT equ 6 ; :u8
|
||||||
|
AST_VALUE_TO_PLACE equ 7 ; :u8
|
||||||
|
AST_PLACE_TO_VALUE equ 8 ; :u8
|
||||||
|
AST_ASSIGNMENT equ 9 ; :u8
|
||||||
|
AST_DEREF equ 10 ; :u8
|
||||||
|
AST_ADDRESS_OF equ 11 ; :u8
|
||||||
|
AST_VAR_DECL equ 12 ; :u8
|
||||||
|
AST_VAR_REF equ 13 ; :u8
|
||||||
|
AST_ARG equ 14 ; :u8
|
||||||
|
|
||||||
|
TYPE_VOID equ 1 ; :u8
|
||||||
|
TYPE_BOOL equ 2 ; :u8
|
||||||
|
TYPE_I32 equ 3 ; :u8
|
||||||
|
TYPE_U32 equ 4 ; :u8
|
||||||
|
TYPE_STR equ 5 ; :u8
|
||||||
|
TYPE_POINTER equ 6 ; :u8
|
||||||
|
;; end-consts
|
||||||
321
lang/src/codegen.asm
Normal file
321
lang/src/codegen.asm
Normal file
|
|
@ -0,0 +1,321 @@
|
||||||
|
default rel
|
||||||
|
|
||||||
|
%include "src/ast.inc"
|
||||||
|
|
||||||
|
extern panic
|
||||||
|
extern vec_extend
|
||||||
|
extern vec_get
|
||||||
|
extern vec_push
|
||||||
|
extern vec_init_with
|
||||||
|
|
||||||
|
global codegen_function
|
||||||
|
global get_register_name
|
||||||
|
|
||||||
|
section .rdata
|
||||||
|
SECTION_TEXT db "section .text", 10
|
||||||
|
SECTION_TEXT_LEN equ $ - SECTION_TEXT
|
||||||
|
GLOBAL_ db "global "
|
||||||
|
GLOBAL_LEN equ $ - GLOBAL_
|
||||||
|
COLON_NL db ":", 10
|
||||||
|
COLON_NL_LEN equ $ - COLON_NL
|
||||||
|
RET_NL db "ret", 10
|
||||||
|
RET_NL_LEN equ $ - RET_NL
|
||||||
|
PROLOGUE db "push rbp", 10, "mov rbp, rsp", 10
|
||||||
|
PROLOGUE_LEN equ $ - PROLOGUE
|
||||||
|
EPILOGUE db "mov rsp, rbp", 10, "pop rbp", 10, "ret", 10
|
||||||
|
EPILOGUE_LEN equ $ - EPILOGUE
|
||||||
|
|
||||||
|
REGISTER_NAMES db "abcdsidibpspr8r9r10r11r12r13r14r15"
|
||||||
|
WIDTHS db "erxliwdbp"
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
|
||||||
|
;; ```rust
|
||||||
|
;; use super::FFISlice;
|
||||||
|
;; ```
|
||||||
|
;; rdi: register index
|
||||||
|
;; rsi: register width (1=byte,2=word,4=dword,8=qword)
|
||||||
|
;; rdx: *mut u8 (buffer, at least 4 bytes)
|
||||||
|
;; define-fn: fn get_register_name(reg_idx: u8, width: u8, buffer: *mut u8) -> FFISlice
|
||||||
|
get_register_name:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
push rdx
|
||||||
|
push rdi
|
||||||
|
|
||||||
|
cmp rdi, 8
|
||||||
|
jge .skip_prefix
|
||||||
|
mov rcx, 0
|
||||||
|
cmp rsi, 8
|
||||||
|
mov rax, 'r'
|
||||||
|
cmove rcx, rax
|
||||||
|
cmp rsi, 4
|
||||||
|
mov rax, 'e'
|
||||||
|
cmove rcx, rax
|
||||||
|
cmp cl, 0
|
||||||
|
je .skip_prefix
|
||||||
|
mov byte [rdx], cl
|
||||||
|
inc rdx
|
||||||
|
.skip_prefix:
|
||||||
|
push rsi
|
||||||
|
call write_register_name
|
||||||
|
pop rsi
|
||||||
|
mov rdi, [rsp]
|
||||||
|
|
||||||
|
cmp rdi, 4
|
||||||
|
jge .check81
|
||||||
|
cmp rsi, 2
|
||||||
|
jl .check81
|
||||||
|
mov byte [rdx], 'x'
|
||||||
|
inc rdx
|
||||||
|
jmp .done
|
||||||
|
.check81:
|
||||||
|
cmp rdi, 8
|
||||||
|
jge .ext_suffix
|
||||||
|
cmp rsi, 1
|
||||||
|
jne .done
|
||||||
|
mov byte [rdx], 'l'
|
||||||
|
inc rdx
|
||||||
|
jmp .done
|
||||||
|
.ext_suffix:
|
||||||
|
mov rcx, 0
|
||||||
|
cmp rsi, 4
|
||||||
|
mov rax, 'd'
|
||||||
|
cmove rcx, rax
|
||||||
|
cmp rsi, 2
|
||||||
|
mov rax, 'w'
|
||||||
|
cmove rcx, rax
|
||||||
|
cmp rsi, 1
|
||||||
|
mov rax, 'b'
|
||||||
|
cmove rcx, rax
|
||||||
|
cmp rcx, 0
|
||||||
|
je .done
|
||||||
|
mov byte [rdx], cl
|
||||||
|
inc rdx
|
||||||
|
|
||||||
|
.done:
|
||||||
|
pop rdi
|
||||||
|
pop rax
|
||||||
|
xchg rax, rdx
|
||||||
|
sub rax, rdx
|
||||||
|
xchg rax, rdx
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
.panic:
|
||||||
|
call panic
|
||||||
|
|
||||||
|
;; rdi: register index
|
||||||
|
;; rdx: *mut u8 (buffer, at least 2 bytes)
|
||||||
|
write_register_name:
|
||||||
|
cmp rdi, 4
|
||||||
|
jl .abcd
|
||||||
|
cmp rdi, 10
|
||||||
|
jl .two_digit
|
||||||
|
; 10,11,12,13,14,15
|
||||||
|
lea rsi, [rel REGISTER_NAMES + 16]
|
||||||
|
sub rdi, 10
|
||||||
|
lea rsi, [rsi + rdi * 2]
|
||||||
|
add rsi, rdi
|
||||||
|
mov al, [rsi + 0]
|
||||||
|
mov [rdx], al
|
||||||
|
inc rdx
|
||||||
|
mov al, [rsi + 1]
|
||||||
|
mov [rdx], al
|
||||||
|
inc rdx
|
||||||
|
mov al, [rsi + 2]
|
||||||
|
mov [rdx], al
|
||||||
|
inc rdx
|
||||||
|
jmp .done
|
||||||
|
.two_digit:
|
||||||
|
lea rsi, [rel REGISTER_NAMES + 4]
|
||||||
|
sub rdi, 4
|
||||||
|
lea rsi, [rsi + rdi * 2]
|
||||||
|
mov al, [rsi + 0]
|
||||||
|
mov [rdx], al
|
||||||
|
inc rdx
|
||||||
|
mov al, [rsi + 1]
|
||||||
|
mov [rdx], al
|
||||||
|
inc rdx
|
||||||
|
jmp .done
|
||||||
|
.abcd:
|
||||||
|
lea rsi, [rel REGISTER_NAMES + 0]
|
||||||
|
lea rsi, [rsi + rdi * 1]
|
||||||
|
mov al, [rsi + 0]
|
||||||
|
mov [rdx], al
|
||||||
|
inc rdx
|
||||||
|
.done:
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;; rdi: ctx
|
||||||
|
;; rsi: a: *const (index, offset)
|
||||||
|
;; rdx: b: *const (index, offset)
|
||||||
|
;; define-fn: fn stackvar_cmp(a: *const (u64, u64), b: *const (u64, u64)) -> i32
|
||||||
|
stackvar_cmp:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
mov rax, [rdi + 0] ; a.index
|
||||||
|
mov rcx, [rsi + 0] ; b.index
|
||||||
|
cmp rax, 0
|
||||||
|
jl .less
|
||||||
|
jg .greater
|
||||||
|
xor rax, rax
|
||||||
|
jmp .done
|
||||||
|
.less:
|
||||||
|
mov rax, -1
|
||||||
|
jmp .done
|
||||||
|
.greater:
|
||||||
|
mov rax, 1
|
||||||
|
|
||||||
|
.done:
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
;; start-structs
|
||||||
|
;; struct CodegenCtx {
|
||||||
|
;; ast: *const Ast,
|
||||||
|
;; text: Vec<u8>,
|
||||||
|
;; }
|
||||||
|
;; end-structs
|
||||||
|
|
||||||
|
;; rdi: *Ctx
|
||||||
|
;; rsi: function index
|
||||||
|
;; define-fn: fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> ()
|
||||||
|
codegen_function:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
push rbx
|
||||||
|
push r15
|
||||||
|
push r14
|
||||||
|
|
||||||
|
; scratch [88..104]
|
||||||
|
; register-bitset [72..88] [a,b,c,d,si,di,bp,sp,8,9,10,11,12,13,14,15]
|
||||||
|
; stack-vars: Vec<(index, offset)> [32..72]
|
||||||
|
; current_stack_size: [24..32]
|
||||||
|
; func_idx [16..24]
|
||||||
|
; ast [8..16]
|
||||||
|
; ctx [0..8]
|
||||||
|
sub rsp, 104
|
||||||
|
mov [rsp], rdi ; ctx
|
||||||
|
mov rax, [rdi]
|
||||||
|
mov [rsp + 8], rax ; ast
|
||||||
|
mov [rsp + 16], rsi ; func_idx
|
||||||
|
mov qword [rsp + 24], 0 ; current_stack_size = 0
|
||||||
|
|
||||||
|
lea rdi, [rsp + 32] ; stack-vars
|
||||||
|
mov rsi, 16 ; size_of::<(u64, u64)>
|
||||||
|
mov rdx, 0 ; drop = None
|
||||||
|
mov rcx, 16 ; initial capacity
|
||||||
|
call vec_init_with
|
||||||
|
|
||||||
|
bts qword [rsp + 72], 7 ; mark rsp as used
|
||||||
|
bts qword [rsp + 72], 6 ; mark rbp as used
|
||||||
|
|
||||||
|
; push "section .text\n"
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel SECTION_TEXT]
|
||||||
|
mov rdx, SECTION_TEXT_LEN
|
||||||
|
call vec_extend
|
||||||
|
|
||||||
|
mov rdi, [rsp + 8] ; ast
|
||||||
|
mov rsi, [rsp + 16] ; func_idx
|
||||||
|
call vec_get
|
||||||
|
cmp byte [rax + 0], AST_FUNCTION ; AstNode.kind
|
||||||
|
mov rbx, [rax + 8] ; AstNode.data
|
||||||
|
jne .panic
|
||||||
|
|
||||||
|
; push "global {function_name}\n"
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel GLOBAL_]
|
||||||
|
mov rdx, GLOBAL_LEN
|
||||||
|
call vec_extend
|
||||||
|
; get function name
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
mov rsi, [rbx + 0] ; AstFunction.name
|
||||||
|
mov rdx, [rbx + 8] ; AstFunction.name_len
|
||||||
|
call vec_extend
|
||||||
|
; push "\n"
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel COLON_NL]
|
||||||
|
inc rsi
|
||||||
|
mov rdx, 1
|
||||||
|
call vec_extend
|
||||||
|
; push "{function_name}:\n"
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
mov rsi, [rbx + 0] ; AstFunction.name
|
||||||
|
mov rdx, [rbx + 8] ; AstFunction.name_len
|
||||||
|
call vec_extend
|
||||||
|
; push ":\n"
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel COLON_NL]
|
||||||
|
mov rdx, 2
|
||||||
|
call vec_extend
|
||||||
|
|
||||||
|
; push prologue
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel PROLOGUE]
|
||||||
|
mov rdx, PROLOGUE_LEN
|
||||||
|
call vec_extend
|
||||||
|
|
||||||
|
; allocate args on stack
|
||||||
|
; rbx = *AstFunction
|
||||||
|
|
||||||
|
mov r15, [rbx + 24] ; AstFunction.args_len
|
||||||
|
xor r14, r14 ; arg index
|
||||||
|
.arg_loop:
|
||||||
|
cmp r14, r15
|
||||||
|
jge .arg_loop_done
|
||||||
|
mov rax, [rbx + 16] ; AstFunction.args
|
||||||
|
lea rsi, [rax + r14 * 8] ;
|
||||||
|
mov rsi, [rsi] ; AstFunction.args[i]
|
||||||
|
|
||||||
|
mov [rsp + 88], rsi
|
||||||
|
mov rax, [rsp + 24] ; current_stack_size
|
||||||
|
mov [rsp + 96], rax
|
||||||
|
add rax, 8 ; size_of::<u64>
|
||||||
|
mov [rsp + 24], rax ; current_stack_size += size_of::<u64>
|
||||||
|
lea rdi, [rsp + 32] ; stack-vars
|
||||||
|
lea rsi, [rsp + 88] ; &(index, offset)
|
||||||
|
call vec_push
|
||||||
|
inc r14
|
||||||
|
jmp .arg_loop
|
||||||
|
|
||||||
|
.arg_loop_done:
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rsi, [rsp + 24] ; &function_ctx
|
||||||
|
call codegen_block
|
||||||
|
|
||||||
|
|
||||||
|
; TODO: generate function body
|
||||||
|
|
||||||
|
; push "ret\n"
|
||||||
|
mov rdi, [rsp] ; ctx
|
||||||
|
lea rdi, [rdi + 8] ; &ctx.text
|
||||||
|
lea rsi, [rel RET_NL]
|
||||||
|
mov rdx, RET_NL_LEN
|
||||||
|
call vec_extend
|
||||||
|
|
||||||
|
add rsp, 104
|
||||||
|
pop r15
|
||||||
|
pop r14
|
||||||
|
pop rbx
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
.panic:
|
||||||
|
call panic
|
||||||
|
|
||||||
|
;; rdi: ctx
|
||||||
|
;; rsi: &function_ctx
|
||||||
|
codegen_block:
|
||||||
|
ret
|
||||||
|
|
@ -31,8 +31,6 @@ global is_whitespace
|
||||||
global is_id_continue
|
global is_id_continue
|
||||||
global is_id_start
|
global is_id_start
|
||||||
|
|
||||||
extern panic
|
|
||||||
|
|
||||||
;; ==============================
|
;; ==============================
|
||||||
;; Helper functions
|
;; Helper functions
|
||||||
;; ==============================
|
;; ==============================
|
||||||
|
|
@ -446,3 +444,8 @@ is_whitespace:
|
||||||
mov rax, 1
|
mov rax, 1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
extern panic_impl
|
||||||
|
global panic
|
||||||
|
panic:
|
||||||
|
and rsp, -16
|
||||||
|
call panic_impl
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,8 @@ expect_token:
|
||||||
add rsp, 0x30
|
add rsp, 0x30
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; Returns the next token if it matches the expected token, else panics
|
||||||
;; dil: expected token
|
;; dil: expected token
|
||||||
unwrap_token:
|
unwrap_token:
|
||||||
push rbp
|
push rbp
|
||||||
|
|
@ -561,6 +562,7 @@ unwrap_token:
|
||||||
call panic
|
call panic
|
||||||
|
|
||||||
;; returns 0 if token not found, else returns lexeme (ptr, len)
|
;; returns 0 if token not found, else returns lexeme (ptr, len)
|
||||||
|
;; doesn't advance the cursor
|
||||||
;; dil: expected token
|
;; dil: expected token
|
||||||
peek_expect_token:
|
peek_expect_token:
|
||||||
push rbp
|
push rbp
|
||||||
|
|
@ -573,6 +575,7 @@ peek_expect_token:
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; returns the next lexeme without advancing the cursor
|
||||||
;; rdi: out-struct pointer
|
;; rdi: out-struct pointer
|
||||||
peek_lexeme:
|
peek_lexeme:
|
||||||
push rbp
|
push rbp
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ extern allocate
|
||||||
|
|
||||||
global vec_init
|
global vec_init
|
||||||
global vec_init_with
|
global vec_init_with
|
||||||
|
global vec_extend
|
||||||
global vec_push
|
global vec_push
|
||||||
global vec_pop
|
global vec_pop
|
||||||
global vec_drop_last
|
global vec_drop_last
|
||||||
|
|
@ -29,13 +30,15 @@ global vec_tests
|
||||||
|
|
||||||
|
|
||||||
;; Byte vector structure
|
;; Byte vector structure
|
||||||
;; struct Vec {
|
;; start-structs
|
||||||
|
;; struct BlobVec {
|
||||||
;; data: *mut u8,
|
;; data: *mut u8,
|
||||||
;; len: usize,
|
;; len: usize,
|
||||||
;; capacity: usize,
|
;; cap: usize,
|
||||||
;; item_size: usize,
|
;; elem_size: usize,
|
||||||
;; drop: Option<fn(*mut u8)>,
|
;; drop: Option<extern "C" fn(*mut u8)>,
|
||||||
;; }
|
;; }
|
||||||
|
;; end-structs
|
||||||
;; size: 40 bytes
|
;; size: 40 bytes
|
||||||
;; align: 8 bytes
|
;; align: 8 bytes
|
||||||
|
|
||||||
|
|
@ -629,3 +632,49 @@ vec_insert_sorted:
|
||||||
add rsp, 0x18
|
add rsp, 0x18
|
||||||
pop rbp
|
pop rbp
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; rdi: *Vec
|
||||||
|
;; rsi: *const u8
|
||||||
|
;; rdx: number of elements
|
||||||
|
;; define-fn: fn vec_extend(vec: *mut BlobVec, elements: *const u8, count: usize) -> ()
|
||||||
|
vec_extend:
|
||||||
|
push rbp
|
||||||
|
mov rbp, rsp
|
||||||
|
|
||||||
|
; bytes [24..32]
|
||||||
|
; count [16..24]
|
||||||
|
; elements [8..16]
|
||||||
|
; vec [0..8]
|
||||||
|
sub rsp, 32
|
||||||
|
|
||||||
|
mov [rsp], rdi ; vec
|
||||||
|
mov [rsp + 8], rsi ; elements
|
||||||
|
mov [rsp + 16], rdx ; count
|
||||||
|
|
||||||
|
mov rax, [rdi + 24] ; item_size
|
||||||
|
mul rdx ; count * item_size
|
||||||
|
|
||||||
|
mov [rsp + 24], rax ; bytes
|
||||||
|
|
||||||
|
mov rsi, [rsp + 16] ; count
|
||||||
|
add rsi, [rdi + 8] ; vec.len + count
|
||||||
|
call vec_try_grow
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; vec
|
||||||
|
mov rsi, [rdi + 8] ; vec.len
|
||||||
|
mov rax, [rdi + 24] ; item_size
|
||||||
|
mul rsi ; vec.len * item_size
|
||||||
|
add rax, [rdi] ; vec.data + vec.len * item_size
|
||||||
|
mov rdi, rax ; dest
|
||||||
|
mov rsi, [rsp + 8] ; elements
|
||||||
|
mov rdx, [rsp + 24] ; bytes
|
||||||
|
call memcpy
|
||||||
|
|
||||||
|
mov rdi, [rsp] ; vec
|
||||||
|
mov rax, [rdi + 8] ; vec.len
|
||||||
|
add rax, [rsp + 16] ; vec.len + count
|
||||||
|
mov [rdi + 8], rax
|
||||||
|
|
||||||
|
add rsp, 32
|
||||||
|
pop rbp
|
||||||
|
ret
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
#[path = "shared/shared.rs"]
|
#[path = "shared/shared.rs"]
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
#[path = "shared/ast_debug.rs"]
|
||||||
|
mod ast_debug;
|
||||||
|
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
unsafe fn bump_init();
|
unsafe fn bump_init();
|
||||||
|
|
||||||
|
|
@ -57,207 +60,46 @@ fn main() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// print_ast(b"3 + 4", |ast| unsafe { parse_expr(ast) });
|
print_ast(b"3 + 4", |ast| unsafe { parse_expr(ast) });
|
||||||
// print_ast(b"fn main() -> void { return 1 + 2; }", |ast| unsafe {
|
print_ast(b"fn main() -> void { return 1 + 2; }", |ast| unsafe {
|
||||||
// parse_func(ast)
|
parse_func(ast)
|
||||||
// });
|
});
|
||||||
// print_ast(b"fn main() -> void { return (1 + (2)); }", |ast| unsafe {
|
print_ast(
|
||||||
// parse_func(ast)
|
b"fn main() -> void { ;;;return (1 + (2)); }",
|
||||||
// });
|
|ast| unsafe { parse_func(ast) },
|
||||||
// print_ast(
|
);
|
||||||
// b"fn main() -> void { return (1 + (2 * 3)) / 4; }",
|
print_ast(
|
||||||
// |ast| unsafe { parse_func(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 { return 1 + 2 * 3; }", |ast| unsafe {
|
||||||
// });
|
parse_func(ast)
|
||||||
|
});
|
||||||
|
|
||||||
// print_ast(b"fn main() -> void { let x: u32 = 4; }", |ast| unsafe {
|
print_ast(b"fn main() -> void { let x: u32 = 4; }", |ast| unsafe {
|
||||||
// parse_func(ast)
|
parse_func(ast)
|
||||||
// });
|
});
|
||||||
// print_ast(
|
print_ast(
|
||||||
// b"fn main(a: u32) -> void { let x: u32 = a + 4; }",
|
b"fn main(a: u32) -> void { let x: u32 = a + 4; }",
|
||||||
// |ast| unsafe { parse_func(ast) },
|
|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(
|
print_ast(
|
||||||
b"fn main(a: u32) -> void {
|
b"fn main(a: u32) -> void {
|
||||||
let y: u32 = a + 4;
|
let y: u32 = a + 4;
|
||||||
|
{
|
||||||
|
let y: u32 = 10;
|
||||||
|
}
|
||||||
let y: *u32 = &y;
|
let y: *u32 = &y;
|
||||||
return *y;
|
return *y;
|
||||||
}",
|
}",
|
||||||
|ast| unsafe { parse_func(ast) },
|
|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_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_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF,
|
|
||||||
};
|
|
||||||
match self.kind {
|
|
||||||
AST_NUMBER => {
|
|
||||||
write!(f, "Number({})", self.data as usize)
|
|
||||||
}
|
|
||||||
AST_DEREF => {
|
|
||||||
write!(f, "Deref(expr: {})", self.data as usize)
|
|
||||||
}
|
|
||||||
AST_ADDRESS_OF => {
|
|
||||||
write!(f, "AddressOf(expr: {})", self.data as usize)
|
|
||||||
}
|
|
||||||
AST_ARG => {
|
|
||||||
let arg = unsafe { self.data.cast::<util::defs::AstArgument>().read() };
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Arg(name: {:?}, arg_type: {})",
|
|
||||||
unsafe {
|
|
||||||
std::str::from_utf8(std::slice::from_raw_parts(arg.name, arg.name_len))
|
|
||||||
},
|
|
||||||
arg.arg_type,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
AST_VAR_REF => {
|
|
||||||
let var_ref = unsafe { self.data.cast::<util::defs::AstVarRef>().read() };
|
|
||||||
if var_ref.resolved != u64::MAX {
|
|
||||||
write!(f, "VarRef({})", var_ref.resolved)
|
|
||||||
} else {
|
|
||||||
write!(f, "VarRef(name: {:?})", unsafe {
|
|
||||||
std::str::from_utf8(std::slice::from_raw_parts(
|
|
||||||
var_ref.name,
|
|
||||||
var_ref.name_len,
|
|
||||||
))
|
|
||||||
},)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AST_VAR_DECL => {
|
|
||||||
let var_decl = unsafe { self.data.cast::<util::defs::AstVarDecl>().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,
|
|
||||||
operator,
|
|
||||||
right,
|
|
||||||
} = unsafe { self.data.cast::<util::defs::BinaryExpr>().read() };
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"BinaryOp(op: {}, left: {}, right: {})",
|
|
||||||
operator, left, right
|
|
||||||
)
|
|
||||||
}
|
|
||||||
AST_RETURN_STATEMENT => {
|
|
||||||
let return_expr_id = self.data as usize;
|
|
||||||
write!(f, "ReturnStatement(expr: {})", return_expr_id)
|
|
||||||
}
|
|
||||||
AST_FUNCTION => {
|
|
||||||
let func = unsafe { self.data.cast::<util::defs::AstFunction>().read() };
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Function(name: {:?}, args: {:?}, return_type: {}, body: {})",
|
|
||||||
unsafe {
|
|
||||||
std::str::from_utf8(std::slice::from_raw_parts(func.name, func.name_len))
|
|
||||||
},
|
|
||||||
unsafe {
|
|
||||||
std::slice::from_raw_parts(func.args.cast::<u64>(), func.args_len as usize)
|
|
||||||
},
|
|
||||||
func.return_type,
|
|
||||||
func.body
|
|
||||||
)
|
|
||||||
}
|
|
||||||
AST_BLOCK => {
|
|
||||||
write!(f, "Block(statements: {:?})", unsafe {
|
|
||||||
std::slice::from_raw_parts(self.data.cast::<u64>(), 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)
|
|
||||||
}
|
|
||||||
kind => write!(f, "UnknownNode(kind: {kind})"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Display for Ast {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
writeln!(f, "[")?;
|
|
||||||
for (i, item) in self.nodes.as_slice().iter().enumerate() {
|
|
||||||
if i > 0 {
|
|
||||||
writeln!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "\t{i}: {}", item)?;
|
|
||||||
}
|
|
||||||
writeln!(f, "\n]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Display for util::defs::SymEntry {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.debug_struct("SymEntry")
|
|
||||||
.field_with("key", |f| {
|
|
||||||
f.debug_struct("Key")
|
|
||||||
.field_with("kind", |f| {
|
|
||||||
f.write_str(match self.key.kind {
|
|
||||||
util::defs::SYM_KEY_SCOPE => "Scope",
|
|
||||||
util::defs::SYM_KEY_SCOPE_NAME => "ScopeName",
|
|
||||||
util::defs::SYM_KEY_PARENT_SCOPE => "ParentScope",
|
|
||||||
util::defs::SYM_KEY_ARG => "Argument",
|
|
||||||
util::defs::SYM_KEY_VAR => "Variable",
|
|
||||||
_ => "Unknown",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.field("scope", &self.key.scope_index)
|
|
||||||
.field("span", &self.key.span)
|
|
||||||
.field_with("ident", |f| {
|
|
||||||
f.write_str(unsafe {
|
|
||||||
&core::str::from_utf8_unchecked(core::slice::from_raw_parts(
|
|
||||||
self.key.ident,
|
|
||||||
self.key.ident_len,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.finish()
|
|
||||||
})
|
|
||||||
.field_with("value", |f| {
|
|
||||||
let stct = &mut f.debug_struct("Value");
|
|
||||||
if self.extra == 0 {
|
|
||||||
stct.field("ast_index", &self.index).finish()
|
|
||||||
} else if self.index != 0 {
|
|
||||||
stct.field_with("ident", |f| {
|
|
||||||
f.write_str(unsafe {
|
|
||||||
core::str::from_utf8_unchecked(core::slice::from_raw_parts(
|
|
||||||
self.index as *const u8,
|
|
||||||
self.extra as usize,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.finish()
|
|
||||||
} else {
|
|
||||||
stct.field("index", &self.index)
|
|
||||||
.field("extra", &self.extra)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
102
lang/tests/codegen.rs
Normal file
102
lang/tests/codegen.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
#![feature(debug_closure_helpers)]
|
||||||
|
|
||||||
|
#[path = "shared/shared.rs"]
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
#[path = "shared/ast_debug.rs"]
|
||||||
|
mod ast_debug;
|
||||||
|
|
||||||
|
use util::defs::{parse_func, Ast, AstNode};
|
||||||
|
|
||||||
|
unsafe extern "C" {
|
||||||
|
unsafe fn bump_init();
|
||||||
|
|
||||||
|
unsafe fn tokeniser_init_buf(bytes: *const u8, len: usize) -> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
bump_init();
|
||||||
|
}
|
||||||
|
println!("Bump allocator initialized.");
|
||||||
|
unsafe {
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(0, 4, buf.as_mut_ptr()).as_str(),
|
||||||
|
"eax"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(7, 8, buf.as_mut_ptr()).as_str(),
|
||||||
|
"rsp"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(7, 4, buf.as_mut_ptr()).as_str(),
|
||||||
|
"esp"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(7, 2, buf.as_mut_ptr()).as_str(),
|
||||||
|
"sp"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(7, 1, buf.as_mut_ptr()).as_str(),
|
||||||
|
"spl"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(9, 1, buf.as_mut_ptr()).as_str(),
|
||||||
|
"r9b"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(12, 1, buf.as_mut_ptr()).as_str(),
|
||||||
|
"r12b"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(12, 4, buf.as_mut_ptr()).as_str(),
|
||||||
|
"r12d"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
util::defs::get_register_name(8, 2, buf.as_mut_ptr()).as_str(),
|
||||||
|
"r8w"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_ast(src: &[u8], parser: impl FnOnce(&mut Ast) -> u64) {
|
||||||
|
unsafe {
|
||||||
|
tokeniser_init_buf(src.as_ptr(), src.len());
|
||||||
|
let mut ast = Ast {
|
||||||
|
nodes: util::vec::Vec::new(),
|
||||||
|
};
|
||||||
|
let expr_id = parser(&mut ast);
|
||||||
|
eprintln!("Parsed expression ID: {}", expr_id);
|
||||||
|
let mut symtable = core::mem::MaybeUninit::<util::defs::SymbolTable>::uninit();
|
||||||
|
util::defs::ast_build_symtable(&mut ast, expr_id, &mut symtable);
|
||||||
|
let mut symtable = symtable.assume_init();
|
||||||
|
util::defs::ast_resolve_var_refs(&mut ast, &mut symtable, expr_id);
|
||||||
|
|
||||||
|
println!("{:#}", &ast);
|
||||||
|
|
||||||
|
let mut codegen = util::defs::CodegenCtx {
|
||||||
|
ast: &mut ast,
|
||||||
|
text: util::vec::Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
util::defs::codegen_function(&mut codegen, expr_id);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Generated code:\n{}",
|
||||||
|
core::str::from_utf8(codegen.text.as_slice()).unwrap()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) },
|
||||||
|
// );
|
||||||
|
}
|
||||||
174
lang/tests/shared/ast_debug.rs
Normal file
174
lang/tests/shared/ast_debug.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
use super::util;
|
||||||
|
|
||||||
|
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_VALUE_TO_PLACE, AST_VAR_DECL, AST_VAR_REF,
|
||||||
|
};
|
||||||
|
match self.kind {
|
||||||
|
AST_NUMBER => {
|
||||||
|
write!(f, "Number({})", self.data as usize)
|
||||||
|
}
|
||||||
|
AST_DEREF => {
|
||||||
|
write!(f, "Deref(expr: {})", self.data as usize)
|
||||||
|
}
|
||||||
|
AST_ADDRESS_OF => {
|
||||||
|
write!(f, "AddressOf(expr: {})", self.data as usize)
|
||||||
|
}
|
||||||
|
AST_ARG => {
|
||||||
|
let arg = unsafe { self.data.cast::<util::defs::AstArgument>().read() };
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Arg(name: {:?}, arg_type: {})",
|
||||||
|
unsafe {
|
||||||
|
std::str::from_utf8(std::slice::from_raw_parts(arg.name, arg.name_len))
|
||||||
|
},
|
||||||
|
arg.arg_type,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AST_VAR_REF => {
|
||||||
|
let var_ref = unsafe { self.data.cast::<util::defs::AstVarRef>().read() };
|
||||||
|
if var_ref.resolved != u64::MAX {
|
||||||
|
write!(f, "VarRef({})", var_ref.resolved)
|
||||||
|
} else {
|
||||||
|
write!(f, "VarRef(name: {:?})", unsafe {
|
||||||
|
std::str::from_utf8(std::slice::from_raw_parts(
|
||||||
|
var_ref.name,
|
||||||
|
var_ref.name_len,
|
||||||
|
))
|
||||||
|
},)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AST_VAR_DECL => {
|
||||||
|
let var_decl = unsafe { self.data.cast::<util::defs::AstVarDecl>().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,
|
||||||
|
operator,
|
||||||
|
right,
|
||||||
|
} = unsafe { self.data.cast::<util::defs::BinaryExpr>().read() };
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"BinaryOp(op: {}, left: {}, right: {})",
|
||||||
|
operator, left, right
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AST_RETURN_STATEMENT => {
|
||||||
|
let return_expr_id = self.data as usize;
|
||||||
|
write!(f, "ReturnStatement(expr: {})", return_expr_id)
|
||||||
|
}
|
||||||
|
AST_FUNCTION => {
|
||||||
|
let func = unsafe { self.data.cast::<util::defs::AstFunction>().read() };
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Function(name: {:?}, args: {:?}, return_type: {}, body: {})",
|
||||||
|
unsafe {
|
||||||
|
std::str::from_utf8(std::slice::from_raw_parts(func.name, func.name_len))
|
||||||
|
},
|
||||||
|
unsafe {
|
||||||
|
std::slice::from_raw_parts(func.args.cast::<u64>(), func.args_len as usize)
|
||||||
|
},
|
||||||
|
func.return_type,
|
||||||
|
func.body
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AST_BLOCK => {
|
||||||
|
write!(f, "Block(statements: {:?})", unsafe {
|
||||||
|
std::slice::from_raw_parts(self.data.cast::<u64>(), 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)
|
||||||
|
}
|
||||||
|
kind => write!(f, "UnknownNode(kind: {kind})"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Display for util::defs::Ast {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
writeln!(f, "[")?;
|
||||||
|
for (i, item) in self.nodes.as_slice().iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
writeln!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(f, "\t{i}: {}", item)?;
|
||||||
|
}
|
||||||
|
write!(f, "\n]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Display for util::defs::SymEntry {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("SymEntry")
|
||||||
|
.field_with("key", |f| {
|
||||||
|
f.debug_struct("Key")
|
||||||
|
.field_with("kind", |f| {
|
||||||
|
f.write_str(match self.key.kind {
|
||||||
|
util::defs::SYM_KEY_SCOPE => "Scope",
|
||||||
|
util::defs::SYM_KEY_SCOPE_NAME => "ScopeName",
|
||||||
|
util::defs::SYM_KEY_PARENT_SCOPE => "ParentScope",
|
||||||
|
util::defs::SYM_KEY_ARG => "Argument",
|
||||||
|
util::defs::SYM_KEY_VAR => "Variable",
|
||||||
|
_ => "Unknown",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.field("scope", &self.key.scope_index)
|
||||||
|
.field("span", &self.key.span)
|
||||||
|
.field_with("ident", |f| {
|
||||||
|
f.write_str(unsafe {
|
||||||
|
&core::str::from_utf8_unchecked(core::slice::from_raw_parts(
|
||||||
|
self.key.ident,
|
||||||
|
self.key.ident_len,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.finish()
|
||||||
|
})
|
||||||
|
.field_with("value", |f| {
|
||||||
|
let stct = &mut f.debug_struct("Value");
|
||||||
|
if self.extra == 0 {
|
||||||
|
stct.field("ast_index", &self.index).finish()
|
||||||
|
} else if self.index != 0 {
|
||||||
|
stct.field_with("ident", |f| {
|
||||||
|
f.write_str(unsafe {
|
||||||
|
core::str::from_utf8_unchecked(core::slice::from_raw_parts(
|
||||||
|
self.index as *const u8,
|
||||||
|
self.extra as usize,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.finish()
|
||||||
|
} else {
|
||||||
|
stct.field("index", &self.index)
|
||||||
|
.field("extra", &self.extra)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,8 +17,19 @@ unsafe extern "C" {
|
||||||
pub unsafe fn ast_build_symtable(ast: *mut Ast, root_index: u64, symtable: *mut core::mem::MaybeUninit<SymbolTable>);
|
pub unsafe fn ast_build_symtable(ast: *mut Ast, root_index: u64, symtable: *mut core::mem::MaybeUninit<SymbolTable>);
|
||||||
pub unsafe fn ast_walk_for_each(ast: *mut Ast, start_index: u64, ctx: *mut (), for_each: unsafe extern "C" fn(ctx: *mut (), *mut Ast, node_index: u64, scope: u64));
|
pub unsafe fn ast_walk_for_each(ast: *mut Ast, start_index: u64, ctx: *mut (), for_each: unsafe extern "C" fn(ctx: *mut (), *mut Ast, node_index: u64, scope: u64));
|
||||||
pub unsafe fn ast_resolve_var_refs(ast: *mut Ast, ctx: *mut SymbolTable, root_index: u64);
|
pub unsafe fn ast_resolve_var_refs(ast: *mut Ast, ctx: *mut SymbolTable, root_index: u64);
|
||||||
|
pub unsafe fn get_register_name(reg_idx: u8, width: u8, buffer: *mut u8) -> FFISlice;
|
||||||
|
pub unsafe fn stackvar_cmp(a: *const (u64, u64), b: *const (u64, u64)) -> i32;
|
||||||
|
pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> ();
|
||||||
|
pub unsafe fn vec_extend(vec: *mut BlobVec, elements: *const u8, count: usize) -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const SYM_KEY_SCOPE: u8 = 1;
|
||||||
|
pub const SYM_KEY_SCOPE_NAME: u8 = 2;
|
||||||
|
pub const SYM_KEY_PARENT_SCOPE: u8 = 3;
|
||||||
|
pub const SYM_KEY_START_LOCALS: u8 = 4;
|
||||||
|
pub const SYM_KEY_ARG: u8 = 5;
|
||||||
|
pub const SYM_KEY_VAR: u8 = 6;
|
||||||
|
pub const SYM_KEY_END_LOCALS: u8 = 7;
|
||||||
pub const AST_FUNCTION: u8 = 1;
|
pub const AST_FUNCTION: u8 = 1;
|
||||||
pub const AST_BLOCK: u8 = 2;
|
pub const AST_BLOCK: u8 = 2;
|
||||||
pub const AST_VARIABLE: u8 = 3;
|
pub const AST_VARIABLE: u8 = 3;
|
||||||
|
|
@ -39,13 +50,6 @@ pub const TYPE_I32: u8 = 3;
|
||||||
pub const TYPE_U32: u8 = 4;
|
pub const TYPE_U32: u8 = 4;
|
||||||
pub const TYPE_STR: u8 = 5;
|
pub const TYPE_STR: u8 = 5;
|
||||||
pub const TYPE_POINTER: u8 = 6;
|
pub const TYPE_POINTER: u8 = 6;
|
||||||
pub const SYM_KEY_SCOPE: u8 = 1;
|
|
||||||
pub const SYM_KEY_SCOPE_NAME: u8 = 2;
|
|
||||||
pub const SYM_KEY_PARENT_SCOPE: u8 = 3;
|
|
||||||
pub const SYM_KEY_START_LOCALS: u8 = 4;
|
|
||||||
pub const SYM_KEY_ARG: u8 = 5;
|
|
||||||
pub const SYM_KEY_VAR: u8 = 6;
|
|
||||||
pub const SYM_KEY_END_LOCALS: u8 = 7;
|
|
||||||
pub const TOKEN_EOF: u8 = 0;
|
pub const TOKEN_EOF: u8 = 0;
|
||||||
pub const TOKEN_LET: u8 = 1;
|
pub const TOKEN_LET: u8 = 1;
|
||||||
pub const TOKEN_IF: u8 = 2;
|
pub const TOKEN_IF: u8 = 2;
|
||||||
|
|
@ -190,4 +194,23 @@ pub struct SymEntry {
|
||||||
pub extra: u64,
|
pub extra: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CodegenCtx {
|
||||||
|
pub ast: *const Ast,
|
||||||
|
pub text: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BlobVec {
|
||||||
|
pub data: *mut u8,
|
||||||
|
pub len: usize,
|
||||||
|
pub cap: usize,
|
||||||
|
pub elem_size: usize,
|
||||||
|
pub drop: Option<extern "C" fn(*mut u8)>,
|
||||||
|
}
|
||||||
|
|
||||||
use super::vec::Vec;
|
use super::vec::Vec;
|
||||||
|
|
||||||
|
use super::FFISlice;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ fn __do_panic() -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn panic() -> ! {
|
extern "C" fn panic_impl() -> ! {
|
||||||
__do_panic()
|
__do_panic()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,15 +52,7 @@ impl FFISlice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
pub use defs::BlobVec;
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BlobVec {
|
|
||||||
pub data: *mut u8,
|
|
||||||
pub len: usize,
|
|
||||||
pub cap: usize,
|
|
||||||
pub elem_size: usize,
|
|
||||||
pub drop: Option<extern "C" fn(*mut u8)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for BlobVec {
|
impl Default for BlobVec {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
@ -135,6 +127,18 @@ pub mod vec {
|
||||||
unsafe { core::slice::from_raw_parts_mut(self.vec.data as *mut T, self.vec.len) }
|
unsafe { core::slice::from_raw_parts_mut(self.vec.data as *mut T, self.vec.len) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extend(&mut self, elements: Box<[T]>) {
|
||||||
|
unsafe {
|
||||||
|
let elements =
|
||||||
|
core::mem::transmute::<Box<[T]>, Box<[core::mem::ManuallyDrop<T>]>>(elements);
|
||||||
|
super::defs::vec_extend(
|
||||||
|
&mut self.vec,
|
||||||
|
elements.as_ptr() as *const u8,
|
||||||
|
elements.len(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, value: T) {
|
pub fn push(&mut self, value: T) {
|
||||||
let value = core::mem::ManuallyDrop::new(value);
|
let value = core::mem::ManuallyDrop::new(value);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,11 @@ fn main() {
|
||||||
assert_eq!(vec.as_slice(), &[20, 30, 35, 40, 50]);
|
assert_eq!(vec.as_slice(), &[20, 30, 35, 40, 50]);
|
||||||
|
|
||||||
let mut vec = Vec::<u32>::new_with(100);
|
let mut vec = Vec::<u32>::new_with(100);
|
||||||
vec.insert_sorted(50, cmp);
|
_ = vec.insert_sorted(50, cmp);
|
||||||
assert_eq!(vec.as_slice(), &[50]);
|
assert_eq!(vec.as_slice(), &[50]);
|
||||||
|
|
||||||
|
// vec extend
|
||||||
|
let elements = Box::new([1, 2, 3, 4, 5]);
|
||||||
|
vec.extend(elements);
|
||||||
|
assert_eq!(vec.as_slice(), &[50, 1, 2, 3, 4, 5]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue