can syscall!
This commit is contained in:
parent
b66b4f6668
commit
927b8517c5
|
|
@ -3,7 +3,7 @@
|
|||
section .bss
|
||||
buf resb 0x100
|
||||
align 8,db 0
|
||||
atoms times 20 resb 8
|
||||
atoms times 24 resb 8
|
||||
global env
|
||||
env resq 1
|
||||
env_tail resq 1
|
||||
|
|
@ -57,7 +57,7 @@ strcmp:
|
|||
xor eax, eax
|
||||
.strcmp_loop:
|
||||
cmp rsi, rax
|
||||
je .strcmp_equal
|
||||
jz .strcmp_equal
|
||||
movzx ecx, byte [rdx + rax]
|
||||
cmp byte [rdi + rax], cl
|
||||
lea rax, [rax + 1]
|
||||
|
|
@ -134,6 +134,10 @@ align 8,db 0
|
|||
ATOM_IF equ 15
|
||||
ATOM_LET equ 16
|
||||
ATOM_LET_STAR equ 17
|
||||
ATOM_STR_LEN equ 18
|
||||
ATOM_LIST_LEN equ 19
|
||||
ATOM_STR_PARTS equ 20
|
||||
ATOM_SYSCALL equ 21
|
||||
|
||||
QUOTE_STR db "quote"
|
||||
QUOTE_STR_LEN equ $ - QUOTE_STR
|
||||
|
|
@ -171,6 +175,21 @@ align 8,db 0
|
|||
LET_STR_LEN equ $ - LET_STR
|
||||
LET_STAR_STR db "let*"
|
||||
LET_STAR_STR_LEN equ $ - LET_STAR_STR
|
||||
STR_LEN_STR db "str-len"
|
||||
STR_LEN_STR_LEN equ $ - STR_LEN_STR
|
||||
LIST_LEN_STR db "list-len"
|
||||
LIST_LEN_STR_LEN equ $ - LIST_LEN_STR
|
||||
STR_PARTS_STR db "str-parts"
|
||||
STR_PARTS_STR_LEN equ $ - STR_PARTS_STR
|
||||
SYSCALL_STR db "syscall"
|
||||
SYSCALL_STR_LEN equ $ - SYSCALL_STR
|
||||
|
||||
SPACE_CHAR db "\Space"
|
||||
SPACE_CHAR_LEN equ $ - SPACE_CHAR
|
||||
NL_CHAR db "\NL"
|
||||
NL_CHAR_LEN equ $ - NL_CHAR
|
||||
TAB_CHAR db "\Tab"
|
||||
TAB_CHAR_LEN equ $ - TAB_CHAR
|
||||
|
||||
;; folds all elements in the list $rdi using the binary function $rdx in the environment $rsi with an accumulator value of $rcx, returning the result in $rax
|
||||
;; fn fold_list(List<T>, Env, (U, T, Env) -> U, U) -> U
|
||||
|
|
@ -602,11 +621,11 @@ p_if:
|
|||
call get_car
|
||||
mov rsi, rax
|
||||
call get_cdr
|
||||
mov rdi, rax
|
||||
call get_car
|
||||
test cl, cl
|
||||
cmovnz rsi, rax
|
||||
mov rdi, rsi
|
||||
call get_car
|
||||
mov rdi, rax
|
||||
mov rsi, qword [rsp + 8] ; restore $rsi = env
|
||||
call eval
|
||||
add rsp, 16
|
||||
|
|
@ -698,8 +717,221 @@ p_let_star:
|
|||
call eval
|
||||
add rsp, 24
|
||||
ret
|
||||
; p_let_rec:
|
||||
; p_let_rec:
|
||||
|
||||
;; returns the length of the input list as a number
|
||||
p_list_len:
|
||||
call eval_list
|
||||
xor rcx, rcx ; acc = 0
|
||||
.len_loop:
|
||||
mov rdi, rax ; list
|
||||
call is_nil
|
||||
test al, al
|
||||
jnz .len_done
|
||||
inc rcx
|
||||
call get_cdr
|
||||
jmp .len_loop
|
||||
.len_done:
|
||||
push rcx
|
||||
mov rdi, 16
|
||||
mov rsi, 8
|
||||
call alloc
|
||||
mov dword [rax], 1 ; refcount = 1
|
||||
pop rcx
|
||||
mov qword [rax + 8], rcx ; value = length
|
||||
mov rdi, rax
|
||||
mov rsi, OBJ_NUM
|
||||
call obj_set_tag
|
||||
ret
|
||||
|
||||
;; concatenates a list of strings into a single string
|
||||
;; (str_concat "Hello," " my" " name is" " Alice") -> "Hello, my name is Alice"
|
||||
p_str_concat:
|
||||
;; appends a list of chars to a string
|
||||
;; (str_append "hello" \Space \w \o \r \l \d) -> "hello world"
|
||||
p_str_append:
|
||||
;; return the nth element of a string
|
||||
p_str_nth:
|
||||
;; returns a new string that is a substring from a a+b of the input string
|
||||
;; (substr "hello world" 0 5) -> "hello"
|
||||
p_str_substr:
|
||||
;; returns 't if the haystack-string contains the needle-char , and nil otherwise
|
||||
p_str_contains_char:
|
||||
;; returns 't if the haystack-string contains the needle-string, and nil otherwise
|
||||
;; (contains_str? "hello world" "lo wo") -> 't
|
||||
p_str_contains_str:
|
||||
|
||||
;; returns the length of the input string as a number
|
||||
p_str_len:
|
||||
call eval_list
|
||||
mov rdi, rax
|
||||
call get_car
|
||||
mov rdi, rax
|
||||
call obj_tag_part
|
||||
cmp al, OBJ_STR
|
||||
jne do_panic_abort
|
||||
call obj_addr_part
|
||||
movzx rax, dword [rax + 4]
|
||||
push rax
|
||||
mov rdi, 16
|
||||
mov rsi, 8
|
||||
call alloc
|
||||
mov rdi, rax
|
||||
mov dword [rdi], 1 ; refcount = 1
|
||||
pop rax
|
||||
mov qword [rdi + 8], rax ; value = string length
|
||||
mov rsi, OBJ_NUM
|
||||
call obj_set_tag
|
||||
ret
|
||||
|
||||
;; returns the pointer and length part of the string object as a pair of numbers
|
||||
p_str_decompose:
|
||||
call eval_list
|
||||
mov rdi, rax
|
||||
call get_car
|
||||
mov rdi, rax
|
||||
call obj_tag_part
|
||||
cmp al, OBJ_STR
|
||||
jne do_panic_abort
|
||||
sub rsp, 16
|
||||
call obj_addr_part
|
||||
mov edi, dword [rax + 4] ; length
|
||||
mov rsi, qword [rax + 8] ; ptr
|
||||
mov dword [rsp], edi
|
||||
mov qword [rsp + 8], rsi
|
||||
mov rdi, 16
|
||||
mov rsi, 8
|
||||
call alloc
|
||||
mov rdi, rax
|
||||
mov dword [rdi], 1 ; refcount = 1
|
||||
movzx rax, dword [rsp] ; length
|
||||
mov qword [rdi + 8], rax ; value = length
|
||||
mov rsi, OBJ_NUM
|
||||
call obj_set_tag
|
||||
mov qword [rsp], rax ; length number
|
||||
|
||||
mov rdi, 16
|
||||
mov rsi, 8
|
||||
call alloc
|
||||
mov rdi, rax
|
||||
mov dword [rdi], 1 ; refcount = 1
|
||||
mov rax, qword [rsp + 8] ; ptr
|
||||
mov qword [rdi + 8], rax ; value = ptr
|
||||
mov rsi, OBJ_NUM
|
||||
call obj_set_tag
|
||||
mov rdi, rax
|
||||
mov rsi, qword [rsp] ; length number
|
||||
call cons
|
||||
add rsp, 16
|
||||
ret
|
||||
|
||||
|
||||
;; returns the ascii value of the char
|
||||
p_char_code:
|
||||
call eval_list
|
||||
mov rdi, rax
|
||||
call get_car
|
||||
mov rdi, rax
|
||||
call obj_tag_part
|
||||
cmp al, OBJ_BYTE
|
||||
jne do_panic_abort
|
||||
shr rax, 8
|
||||
and rax, 0xFF
|
||||
push rax
|
||||
mov rdi, 16
|
||||
mov rsi, 8
|
||||
call alloc
|
||||
mov dword [rax], 1 ; refcount = 1
|
||||
mov rdi, rax
|
||||
pop rax
|
||||
mov qword [rdi + 8], rax ; value = char code
|
||||
mov rsi, OBJ_NUM
|
||||
call obj_set_tag
|
||||
ret
|
||||
|
||||
;; returns a char object representing the ascii value
|
||||
p_make_char:
|
||||
call eval_list
|
||||
mov rdi, rax
|
||||
call get_car
|
||||
mov rdi, rax
|
||||
call obj_tag_part
|
||||
cmp al, OBJ_NUM
|
||||
jne do_panic_abort
|
||||
call obj_addr_part
|
||||
mov rcx, qword [rax + 8] ; char code
|
||||
xor rax, rax
|
||||
mov ah, cl
|
||||
mov al, 0 ; OBJ_BYTE
|
||||
ret
|
||||
|
||||
;; performs a system call, returning the result as a number
|
||||
;; (syscall num arg1 arg2 arg3) -> syscall(num, arg1, arg2, arg3)
|
||||
p_syscall:
|
||||
push r12
|
||||
call eval_list
|
||||
mov rdi, rax
|
||||
; r11 = syscall num
|
||||
; r12 = arg0
|
||||
xor r11, r11
|
||||
xor r12, r12
|
||||
call ._next_arg ; syacall num
|
||||
jnz .do_syscall
|
||||
mov r11, rcx
|
||||
call ._next_arg ; arg0
|
||||
jnz .do_syscall
|
||||
mov r12, rcx
|
||||
call ._next_arg ; arg1
|
||||
jnz .do_syscall
|
||||
mov rsi, rcx
|
||||
call ._next_arg ; arg2
|
||||
jnz .do_syscall
|
||||
mov rdx, rcx
|
||||
call ._next_arg ; arg3
|
||||
jz .do_syscall
|
||||
mov r10, rcx
|
||||
call ._next_arg ; arg4
|
||||
jz .do_syscall
|
||||
mov r8, rcx
|
||||
call ._next_arg ; arg5
|
||||
jz .do_syscall
|
||||
mov r9, rcx
|
||||
.do_syscall:
|
||||
mov rax, r11 ; syscall num
|
||||
mov rdi, r12 ; arg0
|
||||
syscall
|
||||
push rax
|
||||
mov rdi, 16
|
||||
mov rsi, 8
|
||||
call alloc
|
||||
mov rdi, rax
|
||||
mov dword [rdi], 1 ; refcount = 1
|
||||
pop rax
|
||||
mov qword [rdi + 8], rax ; value = syscall result
|
||||
mov rsi, OBJ_NUM
|
||||
call obj_set_tag
|
||||
pop r12
|
||||
ret
|
||||
;; fn _next_arg(list) -> ($rcx=arg, $rdi=rest)
|
||||
._next_arg:
|
||||
call is_nil
|
||||
test al, al
|
||||
jnz ._next_arg_done
|
||||
call get_car
|
||||
mov rcx, rax ; arg
|
||||
call get_cdr
|
||||
mov rdi, rax ; rest
|
||||
xchg rdi, rcx
|
||||
call obj_tag_part
|
||||
cmp al, OBJ_NUM
|
||||
jne do_panic_abort
|
||||
call obj_addr_part
|
||||
mov rdi, qword [rax + 8] ; arg value
|
||||
xchg rdi, rcx
|
||||
mov al, 0
|
||||
test al, al
|
||||
._next_arg_done:
|
||||
ret
|
||||
|
||||
global init_env
|
||||
;; appends var=$rdi bound to val=$rsi to the global environment
|
||||
|
|
@ -809,6 +1041,22 @@ init_env:
|
|||
lea rsi, [rel p_let_star]
|
||||
call genv_append_atom_prim_by_idx
|
||||
|
||||
mov rdi, ATOM_STR_LEN
|
||||
lea rsi, [rel p_str_len]
|
||||
call genv_append_atom_prim_by_idx
|
||||
|
||||
mov rdi, ATOM_LIST_LEN
|
||||
lea rsi, [rel p_list_len]
|
||||
call genv_append_atom_prim_by_idx
|
||||
|
||||
mov rdi, ATOM_STR_PARTS
|
||||
lea rsi, [rel p_str_decompose]
|
||||
call genv_append_atom_prim_by_idx
|
||||
|
||||
mov rdi, ATOM_SYSCALL
|
||||
lea rsi, [rel p_syscall]
|
||||
call genv_append_atom_prim_by_idx
|
||||
|
||||
mov rax, qword [rel env]
|
||||
ret
|
||||
|
||||
|
|
@ -957,6 +1205,30 @@ init_atoms:
|
|||
lea rcx, [rel atoms]
|
||||
mov qword [rcx + ATOM_LET_STAR * 8], rax ; atoms[17] = "let*"
|
||||
|
||||
mov rdi, STR_LEN_STR
|
||||
mov rsi, STR_LEN_STR_LEN
|
||||
call make_atom
|
||||
lea rcx, [rel atoms]
|
||||
mov qword [rcx + ATOM_STR_LEN * 8], rax ; atoms[18] = "str-len"
|
||||
|
||||
mov rdi, LIST_LEN_STR
|
||||
mov rsi, LIST_LEN_STR_LEN
|
||||
call make_atom
|
||||
lea rcx, [rel atoms]
|
||||
mov qword [rcx + ATOM_LIST_LEN * 8], rax ; atoms[21] = "list-len"
|
||||
|
||||
mov rdi, STR_PARTS_STR
|
||||
mov rsi, STR_PARTS_STR_LEN
|
||||
call make_atom
|
||||
lea rcx, [rel atoms]
|
||||
mov qword [rcx + ATOM_STR_PARTS * 8], rax ; atoms[19] = "str-parts"
|
||||
|
||||
mov rdi, SYSCALL_STR
|
||||
mov rsi, SYSCALL_STR_LEN
|
||||
call make_atom
|
||||
lea rcx, [rel atoms]
|
||||
mov qword [rcx + ATOM_SYSCALL * 8], rax ; atoms[20] = "syscall"
|
||||
|
||||
ret
|
||||
|
||||
|
||||
|
|
@ -964,6 +1236,8 @@ init_atoms:
|
|||
;; returns 0 if the objects pointed at by $rdi and $rsi are equal, and 1 otherwise.
|
||||
obj_eq:
|
||||
sub rsp, 24
|
||||
cmp rdi, rsi
|
||||
je .equal
|
||||
mov qword [rsp], rdi ; save obj1
|
||||
mov qword [rsp + 8], rsi ; save obj2
|
||||
call obj_tag_part
|
||||
|
|
@ -972,6 +1246,8 @@ obj_eq:
|
|||
call obj_tag_part
|
||||
cmp al, byte [rsp + 16] ; compare tag2 with tag1
|
||||
jne .not_equal
|
||||
cmp al, OBJ_BYTE
|
||||
je .compare_bytes
|
||||
cmp al, OBJ_ATOM
|
||||
je .compare_atoms
|
||||
cmp al, OBJ_STR
|
||||
|
|
@ -985,6 +1261,8 @@ obj_eq:
|
|||
cmp al, OBJ_PRIM
|
||||
je .compare_prims
|
||||
jmp .equal
|
||||
.compare_bytes:
|
||||
jmp do_panic_abort
|
||||
.compare_atoms:
|
||||
.compare_strs:
|
||||
call obj_addr_part
|
||||
|
|
@ -1257,8 +1535,10 @@ is_ch:
|
|||
|
||||
next_token:
|
||||
push r14
|
||||
push rdi
|
||||
xor r14, r14
|
||||
sub rsp, 16
|
||||
mov qword [rsp + 8], 0 ; flags
|
||||
mov qword [rsp], rdi ; source iterator
|
||||
.skip_spaces:
|
||||
mov rsi, ' '
|
||||
call is_ch
|
||||
|
|
@ -1275,7 +1555,11 @@ next_token:
|
|||
cmp al, ')'
|
||||
je .leading_kw
|
||||
cmp al, "'"
|
||||
jne .eat
|
||||
je .leading_kw
|
||||
cmp al, `"`
|
||||
sete al
|
||||
mov byte [rsp + 8], al ; set string-ness if the next char is a quote
|
||||
jmp .eat
|
||||
.leading_kw:
|
||||
mov rdi, qword [rsp]
|
||||
call getc
|
||||
|
|
@ -1287,11 +1571,46 @@ next_token:
|
|||
.eat:
|
||||
mov rdi, qword [rsp]
|
||||
call getc
|
||||
; handle escapes if we're in an escape sequence
|
||||
cmp byte [rsp + 9], 1
|
||||
jne .skip_escape
|
||||
movzx ecx, al
|
||||
cmp al, `n`
|
||||
mov edi, `\n`
|
||||
cmove ecx, edi
|
||||
cmp al, `t`
|
||||
mov edi, `\t`
|
||||
cmove ecx, edi
|
||||
cmp al, `r`
|
||||
mov edi, `\r`
|
||||
cmove ecx, edi
|
||||
lea rdi, [rel buf]
|
||||
mov byte [rdi + r14], cl
|
||||
mov byte [rsp + 9], 0
|
||||
inc r14
|
||||
jmp .eat
|
||||
.skip_escape:
|
||||
cmp al, `\\`
|
||||
sete cl
|
||||
mov byte [rsp + 9], cl
|
||||
je .eat
|
||||
|
||||
lea rcx, [rel buf]
|
||||
lea rcx, [rcx + r14]
|
||||
mov byte [rcx], al
|
||||
inc r14
|
||||
|
||||
cmp al, `"`
|
||||
sete dl
|
||||
mov cl, byte [rsp + 8] ; get string-ness
|
||||
xchg cl, dl
|
||||
shl dl, cl ; string-ness = 2^(num_quotes_eaten)
|
||||
mov byte [rsp + 8], dl
|
||||
cmp dl, 2
|
||||
jg .done
|
||||
cmp dl, 0
|
||||
jne .eat
|
||||
|
||||
mov rdi, qword [rsp]
|
||||
mov rsi, ' '
|
||||
call is_ch
|
||||
|
|
@ -1315,7 +1634,7 @@ next_token:
|
|||
lea rcx, [rel buf]
|
||||
lea rax, [rcx + r14]
|
||||
mov byte [rax], 0
|
||||
pop rdi
|
||||
add rsp, 16
|
||||
pop r14
|
||||
mov al, byte [rel buf]
|
||||
ret
|
||||
|
|
@ -1328,6 +1647,8 @@ parse_cur_token:
|
|||
je .quote
|
||||
cmp byte [rel buf], `"`
|
||||
je .string
|
||||
cmp byte [rel buf], `\\`
|
||||
je .char
|
||||
pop rdi
|
||||
call parse_atom
|
||||
ret
|
||||
|
|
@ -1340,7 +1661,56 @@ parse_cur_token:
|
|||
call parse_quote
|
||||
ret
|
||||
.string:
|
||||
pop rdi
|
||||
call parse_string
|
||||
ret
|
||||
.char:
|
||||
pop rdi
|
||||
call parse_char
|
||||
ret
|
||||
|
||||
;; fn parse_string(&mut iter) -> Char
|
||||
parse_char:
|
||||
sub rsp, 8
|
||||
lea rdi, [rel buf]
|
||||
call strlen
|
||||
mov qword [rsp], rax ; len
|
||||
lea rdi, [rel buf]
|
||||
mov rsi, rax
|
||||
lea rdx, [rel SPACE_CHAR]
|
||||
mov rcx, SPACE_CHAR_LEN
|
||||
call strcmp
|
||||
test al, al
|
||||
je .is_space
|
||||
lea rdi, [rel buf]
|
||||
mov rsi, qword [rsp] ; len
|
||||
lea rdx, [rel NL_CHAR]
|
||||
mov rcx, NL_CHAR_LEN
|
||||
call strcmp
|
||||
test al, al
|
||||
je .is_newline
|
||||
lea rdi, [rel buf]
|
||||
mov rsi, qword [rsp] ; len
|
||||
lea rdx, [rel TAB_CHAR]
|
||||
mov rcx, TAB_CHAR_LEN
|
||||
call strcmp
|
||||
test al, al
|
||||
je .is_tab
|
||||
lea rdi, [rel buf]
|
||||
mov ah, byte [rdi + 1] ; get the char after the backslash
|
||||
.done:
|
||||
add rsp, 8
|
||||
mov al, 0 ; OBJ_BYTE
|
||||
ret
|
||||
.is_space:
|
||||
mov ah, ' '
|
||||
jmp .done
|
||||
.is_newline:
|
||||
mov ah, `\n`
|
||||
jmp .done
|
||||
.is_tab:
|
||||
mov ah, `\t`
|
||||
jmp .done
|
||||
|
||||
;; fn parse_string(&mut iter) -> Box<[u8]>
|
||||
parse_string:
|
||||
|
|
@ -1349,7 +1719,7 @@ parse_string:
|
|||
.loop:
|
||||
; scan for closing quote
|
||||
lea rax, [rel buf]
|
||||
mov al, byte [rax + r12]
|
||||
mov al, byte [rax + r12 + 1]
|
||||
; cmp al, `\\`
|
||||
; je .escape
|
||||
cmp al, `"`
|
||||
|
|
@ -1363,10 +1733,11 @@ parse_string:
|
|||
mov rsi, 1
|
||||
call alloc
|
||||
lea rdi, [rel buf]
|
||||
inc rdi
|
||||
mov rsi, rax
|
||||
mov rdx, r12
|
||||
call memcpy
|
||||
push rax
|
||||
call memcpy
|
||||
mov rdi, 16
|
||||
mov rsi, 8
|
||||
call alloc
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ impl fmt::Debug for Object {
|
|||
return write!(f, "nil");
|
||||
}
|
||||
match self.tag() {
|
||||
0 => write!(f, "'{}'", (self.0.addr() >> 8) as u8 as char),
|
||||
1 => unsafe {
|
||||
let car = self.ptr().byte_add(8).cast::<Object>().read();
|
||||
let cdr = self.ptr().byte_add(16).cast::<Object>().read();
|
||||
|
|
@ -154,7 +155,15 @@ fn test_parse_list() {
|
|||
let env = unsafe { *ENV_INIT };
|
||||
println!("env: {:?}\n", env);
|
||||
|
||||
let input = b"(let ((x 10) (y 20)) (+ x y))";
|
||||
// let input = b"(let ((x 10) (y 20)) (+ x y))";
|
||||
let input = b"(if () 1 2)";
|
||||
// let hello_world = b"(let* (
|
||||
// (msg \"hello world\\n\")
|
||||
// (msg-parts (str-parts msg))
|
||||
// (ptr (car msg-parts))
|
||||
// (len (cdr msg-parts))
|
||||
// (fd 1))
|
||||
// (syscall 1 fd ptr len))";
|
||||
let mut src = Source::from(&input[..]);
|
||||
let sexp = unsafe { parse_next_token(&raw mut src) };
|
||||
println!("> {:?}", sexp);
|
||||
|
|
|
|||
Loading…
Reference in a new issue