diff --git a/README.md b/README.md index 095849c..a004f0e 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ A very cool language ## Huh? * Indentation-based syntax -* Compiled to x86_64 Assembly +* Compiles to x86_64 Assembly * Sometimes works ## Syntax -```swift +```rust func fib[n: I64] : I64 if n <= 1 return n diff --git a/examples/euler8.zr b/examples/euler8.zr index 6a58314..0cab906 100644 --- a/examples/euler8.zr +++ b/examples/euler8.zr @@ -7,7 +7,7 @@ func main[] : I64 let s: I64 = 1 let j: I64 = 0 while j < 13 - s = s * Char.to_i64(String.nth(n, i + j)) + s = s * Char.parse_i64(String.nth(n, i + j)) j = j + 1 if s > out out = s diff --git a/examples/quicksort.zr b/examples/quicksort.zr index c013a8c..98e39cb 100644 --- a/examples/quicksort.zr +++ b/examples/quicksort.zr @@ -1,11 +1,13 @@ func quicksort[arr: Array] : I64 do_quicksort(arr, 0, Array.size(arr)-1) + return 0 func do_quicksort[arr: Array, low: I64, high: I64] : I64 if low < high let i: I64 = partition(arr, low, high) do_quicksort(arr, low, i - 1) do_quicksort(arr, i + 1, high) + return 0 func partition[arr: Array, low: I64, high: I64] : I64 let pivot: I64 = Array.nth(arr, high) diff --git a/examples/rule110.zr b/examples/rule110.zr index 4c9cee7..4e94cbe 100644 --- a/examples/rule110.zr +++ b/examples/rule110.zr @@ -15,14 +15,13 @@ func rule110_step[state: Array] : Array return new_state func to_str[state: Array]: String - // TODO: very leaky - let o: String = "" + let out: String = malloc(Array.size(state)) for i in 0:Array.size(state) if Array.nth(state, i) - o = String.concat(o, "#") + String.set(out, i, String.nth("#", 0)) else - o = String.concat(o, " ") - return o + String.set(out, i, String.nth(" ", 0)) + return out func main[] : I64 let SIZE: I64 = 60 diff --git a/src/builtin.s b/src/builtin.s deleted file mode 100644 index 6661326..0000000 --- a/src/builtin.s +++ /dev/null @@ -1,116 +0,0 @@ -String.nth: - movzx rax, byte [rdi + rsi] - ret - -String.set: - mov [rdi + rsi], dl - ret - -OS.time: - push rbx - sub rsp, 16 - mov rbx, rsp - mov rdi, rbx - xor esi, esi - call gettimeofday - imul rcx, qword [rbx], 1000 - mov rax, qword [rbx+8] - mov esi, 1000 - cqo - idiv rsi - add rax, rcx - add rsp, 16 - pop rbx - ret - -OS.listdir: - push r14 - push rbx - push rax - mov r14, rdi - call Array.new - mov rbx, rax - mov rdi, r14 - call opendir - mov r14, rax -.OS.listdir.1: - mov rdi, r14 - call readdir - test rax, rax - je .OS.listdir.3 - cmp byte [rax+19], 46 - jne .OS.listdir.2 - movzx ecx, byte [rax+20] - test ecx, ecx - je .OS.listdir.1 - cmp ecx, 46 - jne .OS.listdir.2 - cmp byte [rax+21], 0 - je .OS.listdir.1 -.OS.listdir.2: - add rax, 19 - mov rdi, rax - call strdup - mov rsi, rax - mov rdi, rbx - call Array.push - jmp .OS.listdir.1 -.OS.listdir.3: - mov rdi, r14 - call closedir - mov rax, rbx - add rsp, 8 - pop rbx - pop r14 - ret - -Array.nth: - mov rax, [rdi] - mov rax, [rax + rsi*8] - ret - -Array.set: - mov rax, [rdi] - mov [rax + rsi*8], rdx - ret - -Array.push: - push r14 - push rbx - push rax - mov r14, rsi - mov rbx, rdi - mov rax, [rdi] - mov rcx, [rdi + 16] - cmp rcx, [rdi + 8] - jne .Array.push.1 - lea rdx, [rcx + rcx] - mov rsi, 4 - test rcx, rcx - cmovnz rsi, rdx - mov [rbx + 8], rsi - shl rsi, 3 - mov rdi, rax - call realloc - mov [rbx], rax - mov rcx, [rbx + 16] -.Array.push.1: - mov [rax + rcx*8], r14 - inc qword [rbx + 16] - add rsp, 8 - pop rbx - pop r14 - ret - -Array.size: - mov rax, [rdi + 16] - ret - -Array.free: - push rbx - mov rbx, rdi - mov rdi, [rdi] - call free - mov rdi, rbx - pop rbx - jmp free diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index aed488c..aaff40c 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -95,7 +95,9 @@ impl CodegenX86_64 { pub fn emit_prologue(&mut self) -> Result<(), ZernError> { emit!( &mut self.output, - " + "section .note.GNU-stack + db 0 + section .text extern malloc extern calloc @@ -124,15 +126,125 @@ extern readdir extern closedir extern exit extern gettimeofday -", - ); - emit!(&mut self.output, "{}", include_str!("builtin.s")); - Ok(()) - } - pub fn emit_epilogue(&mut self) -> Result<(), ZernError> { - emit!(&mut self.output, "section .note.GNU-stack"); - emit!(&mut self.output, " db 0"); +String.nth: + movzx rax, byte [rdi + rsi] + ret + +String.set: + mov [rdi + rsi], dl + ret + +OS.time: + push rbx + sub rsp, 16 + mov rbx, rsp + mov rdi, rbx + xor esi, esi + call gettimeofday + imul rcx, qword [rbx], 1000 + mov rax, qword [rbx+8] + mov esi, 1000 + cqo + idiv rsi + add rax, rcx + add rsp, 16 + pop rbx + ret + +OS.listdir: + push r14 + push rbx + push rax + mov r14, rdi + call Array.new + mov rbx, rax + mov rdi, r14 + call opendir + mov r14, rax +.OS.listdir.1: + mov rdi, r14 + call readdir + test rax, rax + je .OS.listdir.3 + cmp byte [rax+19], 46 + jne .OS.listdir.2 + movzx ecx, byte [rax+20] + test ecx, ecx + je .OS.listdir.1 + cmp ecx, 46 + jne .OS.listdir.2 + cmp byte [rax+21], 0 + je .OS.listdir.1 +.OS.listdir.2: + add rax, 19 + mov rdi, rax + call strdup + mov rsi, rax + mov rdi, rbx + call Array.push + jmp .OS.listdir.1 +.OS.listdir.3: + mov rdi, r14 + call closedir + mov rax, rbx + add rsp, 8 + pop rbx + pop r14 + ret + +Array.nth: + mov rax, [rdi] + mov rax, [rax + rsi*8] + ret + +Array.set: + mov rax, [rdi] + mov [rax + rsi*8], rdx + ret + +Array.push: + push r14 + push rbx + push rax + mov r14, rsi + mov rbx, rdi + mov rax, [rdi] + mov rcx, [rdi + 16] + cmp rcx, [rdi + 8] + jne .Array.push.1 + lea rdx, [rcx + rcx] + mov rsi, 4 + test rcx, rcx + cmovnz rsi, rdx + mov [rbx + 8], rsi + shl rsi, 3 + mov rdi, rax + call realloc + mov [rbx], rax + mov rcx, [rbx + 16] +.Array.push.1: + mov [rax + rcx*8], r14 + inc qword [rbx + 16] + add rsp, 8 + pop rbx + pop r14 + ret + +Array.size: + mov rax, [rdi + 16] + ret + +Array.free: + push rbx + mov rbx, rdi + mov rdi, [rdi] + call free + mov rdi, rbx + pop rbx + jmp free +" + ); Ok(()) } @@ -220,8 +332,9 @@ extern gettimeofday self.compile_stmt(env, *body)?; - // TODO: default exit code only for main - emit!(&mut self.output, " mov rax, 0"); + if name.lexeme == "main" { + emit!(&mut self.output, " mov rax, 0"); + } emit!(&mut self.output, " mov rsp, rbp"); emit!(&mut self.output, " pop rbp"); diff --git a/src/main.rs b/src/main.rs index f5b91c5..46b6dd7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,6 @@ fn compile_file(path: String) -> Result<(), ZernError> { codegen.emit_prologue()?; compile_file_to(&mut codegen, "std.zr", include_str!("std.zr").into())?; compile_file_to(&mut codegen, filename, source)?; - codegen.emit_epilogue()?; // TODO if fs::write("out.s", codegen.get_output()).is_err() { diff --git a/src/parser.rs b/src/parser.rs index 2d93952..1c4d677 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -103,7 +103,6 @@ impl Parser { ); } - // TODO: synchronization after parse error if self.match_token(&[TokenType::KeywordLet]) { self.let_declaration() } else { diff --git a/src/std.zr b/src/std.zr index 0db1b96..a2f69ce 100644 --- a/src/std.zr +++ b/src/std.zr @@ -1,12 +1,18 @@ func panic[msg: String] : I64 printf("PANIC: %s\n", msg) exit(1) + return 0 func print[x: String] : I64 printf("%s\n", x) + return 0 func print_i64[x: I64] : I64 printf("%ld\n", x) + return 0 + +func String.is_whitespace[c: Char] : Bool + return c == 10 || c == 32 || c == 13 || c == 9 func String.concat[a: String, b: String] : String let c: String = malloc(strlen(a) + strlen(b) + 1) @@ -19,6 +25,18 @@ func String.substr[s: String, start: I64, length: I64] : String strlcpy(out, s + start, length + 1) return out +func String.trim[s: String] : String + let start: I64 = 0 + let end: I64 = strlen(s) - 1 + + while start <= end && String.is_whitespace(String.nth(s, start)) + start = start + 1 + + while end >= start && String.is_whitespace(String.nth(s, end)) + end = end - 1 + + return String.substr(s, start, end - start + 1) + func String.rev[s: String] : String let len: I64 = strlen(s) let out: String = malloc(len + 1) @@ -52,8 +70,9 @@ func IO.write_file[path: String, content: String] : I64 fwrite(content, 1, strlen(content), file) fclose(file) + return 0 -func Char.to_i64[c: Char]: I64 +func Char.parse_i64[c: Char]: I64 return c - 48 func I64.to_string[n: I64] : String diff --git a/test.zr b/test.zr index 4359b0e..095744e 100644 --- a/test.zr +++ b/test.zr @@ -16,6 +16,7 @@ func run_test[x: String] : I64 let run_end_time: I64 = OS.time() printf("\033[93mRunning %s...\033[0m %ldms\n", x, run_end_time - run_start_time) + return 0 func main[] : I64 system("cargo build --release")