From 2b6f39135a3b3cf1490d3028b773f9f354ac2e73 Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 16 Jun 2025 17:22:20 +0200 Subject: [PATCH] hex, base64, Math.urandom, IO.read_line --- examples/guess_number.zr | 14 ++++++ src/codegen_x86_64.rs | 19 ++++++-- src/std.zr | 102 +++++++++++++++++++++++++++++++++++++-- src/tokenizer.rs | 2 +- 4 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 examples/guess_number.zr diff --git a/examples/guess_number.zr b/examples/guess_number.zr new file mode 100644 index 0000000..bb2c007 --- /dev/null +++ b/examples/guess_number.zr @@ -0,0 +1,14 @@ +func main[] : I64 + let answer: I64 = Math.abs(Math.urandom()) % 100 + + while true + print("Guess a number: ") + let guess: I64 = IO.read_line() |> String.trim() |> I64.parse() + + if guess == answer + print("You win!") + return 0 + else if guess < answer + print("Too low!") + else + print("Too high!") \ No newline at end of file diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 81336bd..b0625d3 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -74,7 +74,7 @@ impl CodegenX86_64 { output: String::new(), data_section: String::new(), label_counter: 0, - data_counter: 0, + data_counter: 1, } } @@ -86,7 +86,7 @@ impl CodegenX86_64 { pub fn get_output(&self) -> String { format!( "section .data - SASSERT db \"assertion failed on line %d\",10,0 + S0 db \"assertion failed on line %d\",10,0 {}{}", self.data_section, self.output ) @@ -99,6 +99,7 @@ impl CodegenX86_64 { db 0 section .text +extern stdin extern malloc extern calloc extern realloc @@ -112,6 +113,7 @@ extern strcat extern strcpy extern strdup extern strlcpy +extern fgets extern fopen extern fseek extern ftell @@ -126,6 +128,16 @@ extern closedir extern exit extern gettimeofday +section .text.deref +deref: + mov rax, qword [rdi] + ret + +section .text.IO.stdin +IO.stdin: + mov rax, [rel stdin] + ret + section .text.Bit.lshift Bit.lshift: mov rcx, rsi @@ -386,7 +398,7 @@ Array.free: 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 rdi, S0"); emit!(&mut self.output, " mov rsi, {}", keyword.loc.line); emit!(&mut self.output, " call printf"); emit!(&mut self.output, " mov rdi, 1"); @@ -605,6 +617,7 @@ Array.free: emit!(&mut self.output, " call Array.new"); emit!(&mut self.output, " mov r12, rax"); + // TODO: nested array literals probably dont work for expr in exprs { self.compile_expr(env, expr)?; emit!(&mut self.output, " mov rsi, rax"); diff --git a/src/std.zr b/src/std.zr index 7badd1a..557192e 100644 --- a/src/std.zr +++ b/src/std.zr @@ -52,6 +52,11 @@ func String.rev[s: String] : String String.set(out, len, 0) return out +func IO.read_line[]: String + let buffer: String = malloc(1024) + fgets(buffer, 1024, IO.stdin()) + return buffer + func IO.read_file[path: String]: String let file: Ptr = fopen(path, "rb") if !file @@ -149,10 +154,64 @@ func Math.is_prime[n: I64]: I64 i = i + 6 return true +func Math.urandom[]: I64 + let buffer: Ptr = malloc(8) + let file: Ptr = fopen("/dev/urandom", "r") + fread(buffer, 8, 1, file) + fclose(file) + let n: I64 = deref(buffer) + free(buffer) + return n + func Array.new[] : Array return calloc(1, 24) -func Math.Crypto.rc4[key: String, plaintext: String]: String +func Crypto.hex_encode[s: String] : String + let hex_chars: String = "0123456789abcdef" + let s_len: I64 = strlen(s) + let j: I64 = 0 + let out: String = malloc(s_len*2+1) + + for i in 0..s_len + let high: U8 = Bit.and(Bit.rshift(String.nth(s, i), 4), 15) + let low: U8 = Bit.and(String.nth(s, i), 15) + String.set(out, j, String.nth(hex_chars, high)) + String.set(out, j+1, String.nth(hex_chars, low)) + j = j + 2 + + String.set(out, j, 0) + return out + +func Crypto.from_hex_digit[d: U8] : I64 + if d == 97 + return 10 + if d == 98 + return 11 + if d == 99 + return 12 + if d == 100 + return 13 + if d == 101 + return 14 + if d == 102 + return 15 + return U8.parse_i64(d) + +func Crypto.hex_decode[s: String] : String + let s_len: I64 = strlen(s) + let i: I64 = 0 + let j: I64 = 0 + let out: String = malloc(s_len/2+1) + + while i < s_len + String.set(out, j, Crypto.from_hex_digit(String.nth(s, i)) * 16 + Crypto.from_hex_digit(String.nth(s, i+1))) + i = i + 2 + j = j + 1 + + String.set(out, j, 0) + return out + +func Crypto.rc4[key: String, plaintext: String]: String let S: String = malloc(256) for i in 0..256 String.set(S, i, i) @@ -184,7 +243,7 @@ func Math.Crypto.rc4[key: String, plaintext: String]: String free(S) return ciphertext -func Math.Crypto.base64_encode[s: String] : String +func Crypto.base64_encode[s: String] : String let chars: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" let s_len: I64 = strlen(s) let output: String = malloc(s_len*2) @@ -217,4 +276,41 @@ func Math.Crypto.base64_encode[s: String] : String String.set(output, j-1, equals) String.set(output, j, 0) - return output \ No newline at end of file + return output + +func Crypto.base64_decode[s: String] : String + let chars: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + let s_len: I64 = strlen(s) + let out: String = malloc(s_len) + let i: I64 = 0 + let j: I64 = 0 + + while String.nth(s, s_len-1) == 61 + s_len = s_len - 1 + + while i < s_len + let s1: U8 = String.find(chars, String.nth(s, i)) + let s2: U8 = 0 + if i + 1 < s_len + s2 = String.find(chars, String.nth(s, i+1)) + let s3: U8 = 0 + if i + 2 < s_len + s3 = String.find(chars, String.nth(s, i+2)) + let s4: U8 = 0 + if i + 3 < s_len + s4 = String.find(chars, String.nth(s, i+3)) + i = i + 4 + + let triple: U8 = Bit.or(Bit.or(Bit.or(Bit.lshift(s1, 18), Bit.lshift(s2, 12)), Bit.lshift(s3, 6)), s4) + + String.set(out, j, Bit.and(Bit.rshift(triple, 16), 255)) + j = j + 1 + if s3 != 64 + String.set(out, j, Bit.and(Bit.rshift(triple, 8), 255)) + j = j + 1 + if s4 != 64 + String.set(out, j, Bit.and(triple, 255)) + j = j + 1 + + String.set(out, j, 0) + return out \ No newline at end of file diff --git a/src/tokenizer.rs b/src/tokenizer.rs index d670a58..9ebefd2 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -231,7 +231,7 @@ impl Tokenizer { self.handle_indentation()?; } '0'..='9' => self.scan_number(), - 'A'..='Z' | 'a'..='z' | '_' | '.' => self.scan_identifier(), + 'A'..='Z' | 'a'..='z' | '_' => self.scan_identifier(), _ => return error!(self.loc, "unexpected character"), } Ok(())