diff --git a/examples/euler13.zr b/examples/euler13.zr new file mode 100644 index 0000000..27cf2d0 --- /dev/null +++ b/examples/euler13.zr @@ -0,0 +1,5 @@ +func main[] : I64 + 37107287533 + 46376937677 + 74324986199 + 91942213363 + 23067588207 + 89261670696 + 28112879812 + 44274228917 + 47451445736 + 70386486105 + 62176457141 + 64906352462 + 92575867718 + 58203565325 + 80181199384 + 35398664372 + 86515506006 + 71693888707 + 54370070576 + 53282654108 + 36123272525 + 45876576172 + 17423706905 + 81142660418 + 51934325451 + 62467221648 + 15732444386 + 55037687525 + 18336384825 + 80386287592 + 78182833757 + 16726320100 + 48403098129 + 87086987551 + 59959406895 + 69793950679 + 41052684708 + 65378607361 + 35829035317 + 94953759765 + 88902802571 + 25267680276 + 36270218540 + 24074486908 + 91430288197 + 34413065578 + 23053081172 + 11487696932 + 63783299490 + 67720186971 + 95548255300 + 76085327132 + 37774242535 + 23701913275 + 29798860272 + 18495701454 + 38298203783 + 34829543829 + 40957953066 + 29746152185 + 41698116222 + 62467957194 + 23189706772 + 86188088225 + 11306739708 + 82959174767 + 97623331044 + 42846280183 + 55121603546 + 32238195734 + 75506164965 + 62177842752 + 32924185707 + 99518671430 + 73267460800 + 76841822524 + 97142617910 + 87783646182 + 10848802521 + 71329612474 + 62184073572 + 66627891981 + 60661826293 + 85786944089 + 66024396409 + 64913982680 + 16730939319 + 94809377245 + 78639167021 + 15368713711 + 40789923115 + 44889911501 + 41503128880 + 81234880673 + 82616570773 + 22918802058 + 77158542502 + 72107838435 + 20849603980 + 53503534226 + |> I64.to_string() + |> substr(0, 10) + |> print() \ No newline at end of file diff --git a/examples/euler15.zr b/examples/euler15.zr new file mode 100644 index 0000000..79b8276 --- /dev/null +++ b/examples/euler15.zr @@ -0,0 +1,11 @@ +func main[] : I64 + let n: I64 = 40 + let r: I64 = 20 + let out: I64 = 1 + + let i: I64 = 1 + while i < r + 1 + out = out * (n - (r - i)) / i + i = i + 1 + + print_i64(out) \ No newline at end of file diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 599f066..9019f66 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -58,7 +58,7 @@ macro_rules! emit { } static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; -static TYPES: [&str; 3] = ["I64", "String", "Bool"]; +static TYPES: [&str; 5] = ["I64", "String", "Bool", "Ptr", "Char"]; pub struct CodegenX86_64 { output: String, @@ -85,6 +85,7 @@ impl CodegenX86_64 { pub fn get_output(&self) -> String { format!( "section .data + SASSERT db \"assertion failed on line %d\",10,0 {}{}", self.data_section, self.output ) @@ -104,38 +105,17 @@ extern strcmp extern strcat extern strcpy extern strdup +extern strlcpy extern puts +extern fopen +extern fseek +extern ftell +extern fread +extern rewind extern system extern exit copystr equ strdup -strrev: - push r14 - push rbx - push rax - mov rbx, rdi - call strlen - mov r14, rax - lea rdi, [rax + 1] - call malloc - mov rcx, rax - mov rsi, r14 - mov rdx, r14 -.strrev.1: - sub rdx, 1 - jb .strrev.2 - mov sil, byte [rbx + rsi - 1] - mov byte [rcx], sil - inc rcx - mov rsi, rdx - jmp .strrev.1 -.strrev.2: - mov byte [rax + r14], 0 - add rsp, 8 - pop rbx - pop r14 - ret - isqrt: xor rax, rax mov rcx, 1 @@ -170,6 +150,10 @@ isqrt: nth: movzx rax, byte [rdi + rsi] ret + +set: + mov [rdi + rsi], dl + ret ", ); Ok(()) @@ -275,6 +259,18 @@ nth: emit!(&mut self.output, " pop rbp"); emit!(&mut self.output, " ret"); } + Stmt::Assert { keyword, value } => { + self.compile_expr(env, value)?; + let skip_label = self.label(); + emit!(&mut self.output, " test rax, rax"); + emit!(&mut self.output, " jne {}", skip_label); + emit!(&mut self.output, " mov rdi, SASSERT"); + emit!(&mut self.output, " mov rsi, {}", keyword.loc.line); + emit!(&mut self.output, " call printf"); + emit!(&mut self.output, " mov rdi, 1"); + emit!(&mut self.output, " call exit"); + emit!(&mut self.output, "{}:", skip_label); + } } Ok(()) } @@ -431,6 +427,7 @@ nth: paren, args, } => { + // TODO: in function calls like a(1, b(2, 3)) the first argument will get overwritten when calling b let callee = match *callee { Expr::Variable(name) => name.lexeme, _ => return error!(&paren.loc, "tried to call a non-constant expression"), diff --git a/src/parser.rs b/src/parser.rs index 9dfcdcd..914bfae 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -31,6 +31,10 @@ pub enum Stmt { body: Box, }, Return(Expr), + Assert { + keyword: Token, + value: Expr, + }, } #[derive(Debug, Clone)] @@ -164,16 +168,17 @@ impl Parser { } else if self.match_token(&[TokenType::KeywordWhile]) { self.while_statement() } else if self.match_token(&[TokenType::KeywordReturn]) { - self.return_statement() + Ok(Stmt::Return(self.expression()?)) + } else if self.match_token(&[TokenType::KeywordAssert]) { + Ok(Stmt::Assert { + keyword: self.previous().clone(), + value: self.expression()?, + }) } else { Ok(Stmt::Expression(self.expression()?)) } } - fn return_statement(&mut self) -> Result { - Ok(Stmt::Return(self.expression()?)) - } - fn if_statement(&mut self) -> Result { let condition = self.expression()?; let then_branch = self.block()?; diff --git a/src/std.zr b/src/std.zr index 6175172..1c8e8e4 100644 --- a/src/std.zr +++ b/src/std.zr @@ -1,3 +1,7 @@ +func panic[msg: String] : I64 + printf("PANIC: %s\n", msg) + exit(1) + func print[x: String] : I64 printf("%s\n", x) @@ -10,7 +14,39 @@ func concat[a: String, b: String] : String strcat(c, b) return c -func Char.to_i64[c: I64]: I64 +func substr[s: String, start: I64, length: I64] : String + let out: String = malloc(length + 1) + strlcpy(out, s + start, length + 1) + return out + +func strrev[s: String] : String + let len: I64 = strlen(s) + let out: String = malloc(len + 1) + + let i: I64 = 0 + while i < len + let c: Char = nth(s, len - i - 1) + set(out, i, c) + i = i + 1 + set(out, len, 0) + return out + +func IO.read_file[path: String]: String + let file: Ptr = fopen(path, "rb") + if !file + panic("failed to open file") + + fseek(file, 0, 2) + let size: I64 = ftell(file) + rewind(file) + + let buffer: String = malloc(size + 1) + + let n: I64 = fread(buffer, 1, size, file) + set(buffer, n, 0) + return buffer + +func Char.to_i64[c: Char]: I64 return c - 48 func I64.to_string[n: I64] : String diff --git a/src/tokenizer.rs b/src/tokenizer.rs index c638a2d..cf50c1f 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -39,6 +39,7 @@ pub enum TokenType { KeywordWhile, KeywordFunc, KeywordReturn, + KeywordAssert, Indent, Dedent, @@ -311,6 +312,7 @@ impl Tokenizer { "while" => TokenType::KeywordWhile, "func" => TokenType::KeywordFunc, "return" => TokenType::KeywordReturn, + "assert" => TokenType::KeywordAssert, "true" => TokenType::True, "false" => TokenType::False, _ => TokenType::Identifier,