Compare commits

...

6 Commits

50 changed files with 616 additions and 164 deletions

View File

@@ -16,13 +16,13 @@ func main[] : i64
else if op == '<'
p = p - 1
else if op == '+'
str.set(memory, p, memory[p] + 1)
memory[p] = memory[p] + 1
else if op == '-'
str.set(memory, p, memory[p] - 1)
memory[p] = memory[p] - 1
else if op == '.'
io.print_char(memory[p])
else if op == ','
str.set(memory, p, io.read_char())
memory[p] = io.read_char()
else if op == '['
if !memory[p]
i = i + 1

328
examples/chip8.zr Normal file
View File

@@ -0,0 +1,328 @@
// needs to be compiled with -m -C="-lraylib"
extern InitWindow
extern SetTargetFPS
extern WindowShouldClose
extern BeginDrawing
extern ClearBackground
extern DrawRectangle
extern EndDrawing
extern IsKeyDown
extern printf // TODO: replace with std
extern rand // TODO: replace with std
struct CHIP8
memory: ptr
pc: i64
stack: array
sp: i64
reg: ptr
I: i64
delay_timer: i64
sound_timer: i64
keyboard: array
display: ptr
keyboard_map: array
func chip8_create[] : CHIP8
let c: CHIP8 = new CHIP8
c->memory = mem.alloc(4096)
mem.zero(c->memory, 4096)
c->display = mem.alloc(64*32)
mem.zero(c->display, 64*32)
c->reg = mem.alloc(16)
mem.zero(c->reg, 16)
c->stack = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
c->keyboard = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
let fonts: array = [0xf0, 0x90, 0x90, 0x90, 0xf0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xf0, 0x10, 0xf0, 0x80, 0xf0, 0xf0, 0x10, 0xf0, 0x10, 0xf0, 0x90, 0x90, 0xf0, 0x10, 0x10, 0xf0, 0x80, 0xf0, 0x10, 0xf0, 0xf0, 0x80, 0xf0, 0x90, 0xf0, 0xf0, 0x10, 0x20, 0x40, 0x40, 0xf0, 0x90, 0xf0, 0x90, 0xf0, 0xf0, 0x90, 0xf0, 0x10, 0xf0, 0xf0, 0x90, 0xf0, 0x90, 0x90, 0xe0, 0x90, 0xe0, 0x90, 0xe0, 0xf0, 0x80, 0x80, 0x80, 0xf0, 0xe0, 0x90, 0x90, 0x90, 0xe0, 0xf0, 0x80, 0xf0, 0x80, 0xf0, 0xf0, 0x80, 0xf0, 0x80, 0x80]
for i in 0..80
c->memory[i] = array.nth(fonts, i)
mem.free(fonts)
c->pc = 0x200
// see KeyboardKey in raylib.h
c->keyboard_map = [49, 50, 51, 52, 53, 265, 32, 263, 264, 262, 87, 69, 82, 84, 89, 85]
return c
func chip8_disassemble[c: CHIP8, ins_count: i64] : void
for i in 0..ins_count
printf("0x%x: ", c->pc)
let high: i64 = c->memory[c->pc]
let low: i64 = c->memory[c->pc + 1]
c->pc = c->pc + 2
let ins: i64 = (high << 8) | low
let nnn: i64 = ins & 0x0fff
let kk: i64 = ins & 0x00ff
let n: i64 = ins & 0x000f
let x: i64 = (ins >> 8) & 0x0f
let y: i64 = (ins >> 4) & 0x0f
let op: i64 = (ins >> 12) & 0x0f
if op == 0x0
if nnn == 0x0e0
io.println("CLS")
else if nnn == 0x0ee
io.println("RET")
else
io.print("SYS ")
io.println_i64(nnn)
else if op == 0x1
printf("JP 0x%x\n", nnn)
else if op == 0x2
io.print("CALL ")
io.println_i64(nnn)
else if op == 0x3
printf("SE V%x, %u\n", x, kk)
else if op == 0x4
printf("SNE V%x, %u\n", x, kk)
else if op == 0x5
printf("SE V%x, V%x\n", x, y)
else if op == 0x6
printf("LD V%x, %u\n", x, kk)
else if op == 0x7
printf("ADD V%x, %u\n", x, kk)
else if op == 0x8
if n == 0x0
printf("LD V%x, V%x\n", x, y)
else if n == 0x1
printf("OR V%x, V%x\n", x, y)
else if n == 0x2
printf("AND V%x, V%x\n", x, y)
else if n == 0x3
printf("XOR V%x, V%x\n", x, y)
else if n == 0x4
printf("ADD V%x, V%x\n", x, y)
else if n == 0x5
printf("SUB V%x, V%x\n", x, y)
else if n == 0x6
printf("SHR V%x\n", x)
else if n == 0x7
printf("SUBN V%x, V%x\n", x, y)
else if n == 0xE
printf("SHL V%x\n", x)
else
printf("??? (%x)\n", ins)
else if op == 0x9
printf("SNE V%x, V%x\n", x, y)
else if op == 0xa
printf("LD I, 0x%x\n", nnn)
else if op == 0xb
printf("JP V0, %u\n", nnn)
else if op == 0xc
printf("RND V%x, %u\n", x, kk)
else if op == 0xd
printf("DRW V%x, V%x, %u\n", x, y, n)
else if op == 0xe
if kk == 0x9e
printf("SKP V%x\n", x)
else if kk == 0xa1
printf("SKNP V%x\n", x)
else
printf("??? (%x)\n", ins)
else if op == 0xf
if kk == 0x07
printf("LD V%x, DT\n", x)
else if kk == 0x0A
printf("LD V%x, K\n", x)
else if kk == 0x15
printf("LD DT, V%x\n", x)
else if kk == 0x18
printf("LD ST, V%x\n", x)
else if kk == 0x1E
printf("ADD I, V%x\n", x)
else if kk == 0x29
printf("LD F, V%x\n", x)
else if kk == 0x33
printf("LD B, V%x\n", x)
else if kk == 0x55
printf("LD [I], V%x\n", x)
else if kk == 0x65
printf("LD V%x, [I]\n", x)
else
printf("??? (%x)\n", ins)
else
printf("??? (%x)\n", ins)
func chip8_step[c: CHIP8] : void
let high: i64 = c->memory[c->pc]
let low: i64 = c->memory[c->pc + 1]
c->pc = c->pc + 2
let ins: i64 = (high << 8) | low
let nnn: i64 = ins & 0x0fff
let kk: i64 = ins & 0x00ff
let n: i64 = ins & 0x000f
let x: i64 = (ins >> 8) & 0x0f
let y: i64 = (ins >> 4) & 0x0f
let op: i64 = (ins >> 12) & 0x0f
if op == 0x0
if nnn == 0x0e0
mem.zero(c->display, 64 * 32)
else if nnn == 0x0ee
c->pc = array.nth(c->stack, c->sp)
c->sp = c->sp - 1
else if op == 0x1
c->pc = nnn
else if op == 0x2
c->sp = c->sp + 1
array.set(c->stack, c->sp, c->pc)
c->pc = nnn
else if op == 0x3
if c->reg[x] == kk
c->pc = c->pc + 2
else if op == 0x4
if c->reg[x] != kk
c->pc = c->pc + 2
else if op == 0x5
if c->reg[x] == c->reg[y]
c->pc = c->pc + 2
else if op == 0x6
c->reg[x] = kk
else if op == 0x7
c->reg[x] = c->reg[x] + kk
else if op == 0x8
if n == 0x0
c->reg[x] = c->reg[y]
else if n == 0x1
c->reg[x] = c->reg[x] | c->reg[y]
else if n == 0x2
c->reg[x] = c->reg[x] & c->reg[y]
else if n == 0x3
c->reg[x] = c->reg[x] ^ c->reg[y]
else if n == 0x4
let res: i64 = c->reg[x] + c->reg[y]
c->reg[0xf] = res > 0xff
c->reg[x] = res
else if n == 0x5
c->reg[0xf] = c->reg[x] > c->reg[y]
c->reg[x] = c->reg[x] - c->reg[y]
else if n == 0x6
c->reg[0xf] = c->reg[x] & 0x1
c->reg[x] = c->reg[x] >> 1
else if n == 0x7
c->reg[0xf] = c->reg[y] > c->reg[x]
c->reg[x] = c->reg[y] - c->reg[x]
else if n == 0xE
c->reg[0xf] = (c->reg[x] & 0x80) >> 7
c->reg[x] = c->reg[x] << 1
else if op == 0x9
if c->reg[x] != c->reg[y]
c->pc = c->pc + 2
else if op == 0xa
c->I = nnn
else if op == 0xb
c->pc = nnn + c->reg[0]
else if op == 0xc
c->reg[x] = (rand() % 256) & kk
else if op == 0xd
c->reg[0xf] = 0
for row in 0..n
for col in 0..8
if (c->memory[c->I + row] & (0x80 >> col)) != 0
let pixel_x: i64 = (c->reg[x] + col) % 64
let pixel_y: i64 = (c->reg[y] + row) % 32
let offset: i64 = pixel_x + (pixel_y * 64)
if c->display[offset] == 1
c->reg[0xf] = 1
c->display[offset] = c->display[offset] ^ 1
else if op == 0xe
if kk == 0x9e
if IsKeyDown(array.nth(c->keyboard_map, c->reg[x]))
c->pc = c->pc + 2
else if kk == 0xa1
if !IsKeyDown(array.nth(c->keyboard_map, c->reg[x]))
c->pc = c->pc + 2
else if op == 0xf
if kk == 0x07
c->reg[x] = c->delay_timer
else if kk == 0x0A
let key_pressed: bool = false
while !key_pressed && !WindowShouldClose()
for i in 0..16
if IsKeyDown(array.nth(c->keyboard_map, i))
key_pressed = true
break
else if kk == 0x15
c->delay_timer = c->reg[x]
else if kk == 0x18
c->sound_timer = c->reg[x]
else if kk == 0x1E
c->I = c->I + c->reg[x]
else if kk == 0x29
c->I = c->reg[x] * 5
else if kk == 0x33
c->memory[c->I] = c->reg[x] / 100
c->memory[c->I + 1] = (c->reg[x] / 10) % 10
c->memory[c->I + 2] = c->reg[x] % 10
else if kk == 0x55
for i in 0..x+1
c->memory[c->I + i] = c->reg[i]
else if kk == 0x65
for i in 0..x+1
c->reg[i] = c->memory[c->I + i]
func chip8_free[c: CHIP8] : void
mem.free(c->memory)
array.free(c->stack)
mem.free(c->reg)
array.free(c->keyboard)
mem.free(c->display)
array.free(c->keyboard_map)
mem.free(c)
func main[argc: i64, argv: ptr] : i64
let path: str = 0
let disassemble: bool = 0
for i in 1..argc
let arg: str = mem.read64(argv + i * 8)
if str.equal(arg, "-d")
disassemble = 1
else
path = arg
if path == 0
io.println("Usage: chip8 -d <path>")
return 1
let c: CHIP8 = chip8_create()
let bytes_size: ptr = 0
let bytes: ptr = io.read_binary_file(path, ^bytes_size)
for i in 0..bytes_size
c->memory[0x200 + i] = bytes[i]
if disassemble
chip8_disassemble(c, bytes_size / 2)
return 0
InitWindow(640, 320, "CHIP-8")
SetTargetFPS(60)
while !WindowShouldClose()
if c->delay_timer > 0
c->delay_timer = c->delay_timer - 1
if c->sound_timer > 0
c->sound_timer = c->sound_timer - 1
// TODO: buzzer
for i in 0..25
chip8_step(c)
BeginDrawing()
ClearBackground(0xffffffff)
for y in 0..32
for x in 0..64
if c->display[x + y * 64] == 1
DrawRectangle(x * 10, y * 10, 10, 10, 0xff000000)
EndDrawing()

View File

@@ -32,7 +32,7 @@ func main[] : i64
let base_point: ptr = mem.alloc(32)
mem.zero(base_point, 32)
mem.write8(base_point, 9)
base_point[0] = 9
let alice_private: ptr = str.hex_decode("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a")
io.print("A_priv: ")

View File

@@ -44,11 +44,11 @@ func part2[lines: array] : void
for y in 1..str.len(array.nth(lines, x))-1
if array.nth(lines, x)[y] == 'A'
let s: str = mem.alloc(5)
str.set(s, 0, array.nth(lines, x - 1)[y - 1])
str.set(s, 1, array.nth(lines, x + 1)[y - 1])
str.set(s, 2, array.nth(lines, x + 1)[y + 1])
str.set(s, 3, array.nth(lines, x - 1)[y + 1])
str.set(s, 4, 0)
s[0] = array.nth(lines, x - 1)[y - 1]
s[1] = array.nth(lines, x + 1)[y - 1]
s[2] = array.nth(lines, x + 1)[y + 1]
s[3] = array.nth(lines, x - 1)[y + 1]
s[4] = 0
if str.equal(s, "MSSM") || str.equal(s, "SMMS") || str.equal(s, "MMSS") || str.equal(s, "SSMM")
out = out + 1

View File

@@ -8,9 +8,9 @@ func part1[lines: array] : void
for j in 0..str.len(line)
for k in (j+1)..str.len(line)
let s: str = mem.alloc(3)
str.set(s, 0, line[j])
str.set(s, 1, line[k])
str.set(s, 2, 0)
s[0] = line[j]
s[1] = line[k]
s[2] = 0
let n: i64 = str.parse_i64(s)
if n > largest
largest = n

View File

@@ -8,6 +8,7 @@ use crate::{
pub struct Analyzer {
pub functions: HashMap<String, i32>,
pub constants: HashMap<String, u64>,
pub structs: HashMap<String, HashMap<String, usize>>,
}
impl Analyzer {
@@ -15,6 +16,7 @@ impl Analyzer {
Analyzer {
functions: HashMap::new(),
constants: HashMap::new(),
structs: HashMap::new(),
}
}
@@ -117,7 +119,17 @@ impl Analyzer {
}
self.functions.insert(name.lexeme.clone(), -1);
}
Stmt::Struct { name: _, fields: _ } => todo!(),
Stmt::Struct { name, fields } => {
let mut fields_map: HashMap<String, usize> = HashMap::new();
let mut offset: usize = 0;
for field in fields {
fields_map.insert(field.var_name.lexeme.clone(), offset);
offset += 8;
}
self.structs.insert(name.lexeme.clone(), fields_map);
}
}
Ok(())
}
@@ -138,7 +150,8 @@ impl Analyzer {
self.analyze_expr(right)?;
}
Expr::Variable(_) => {}
Expr::Assign { name: _, value } => {
Expr::Assign { left, op: _, value } => {
self.analyze_expr(left)?;
self.analyze_expr(value)?;
}
Expr::Call {
@@ -190,6 +203,9 @@ impl Analyzer {
self.analyze_expr(expr)?;
}
Expr::New(_) => {}
Expr::MemberAccess { left, field: _ } => {
self.analyze_expr(left)?;
}
}
Ok(())
}

View File

@@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Write};
use crate::{
analyzer::Analyzer,
parser::{Expr, Stmt},
tokenizer::{TokenType, ZernError, error},
tokenizer::{Token, TokenType, ZernError, error},
};
struct Var {
@@ -69,6 +69,9 @@ macro_rules! emit {
static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
// TODO: currently they are all just 64 bit values
static BUILTIN_TYPES: [&str; 7] = ["void", "u8", "i64", "str", "bool", "ptr", "array"];
pub struct CodegenX86_64<'a> {
output: String,
data_section: String,
@@ -108,11 +111,6 @@ _builtin_read64:
mov rax, qword [rdi]
ret
section .text._builtin_set8
_builtin_set8:
mov [rdi], sil
ret
section .text._builtin_set64
_builtin_set64:
mov [rdi], rsi
@@ -170,6 +168,10 @@ _builtin_environ:
},
};
if !self.is_valid_type_name(&var_type) {
return error!(&name.loc, "unrecognized type: ".to_owned() + &var_type);
}
self.compile_expr(env, initializer)?;
let offset = env.define_var(name.lexeme.clone(), var_type);
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
@@ -238,6 +240,13 @@ _builtin_environ:
emit!(&mut self.output, " sub rsp, 256"); // TODO
for (i, param) in params.iter().enumerate() {
if !self.is_valid_type_name(&param.var_type.lexeme) {
return error!(
&name.loc,
"unrecognized type: ".to_owned() + &param.var_type.lexeme
);
}
let offset = env
.define_var(param.var_name.lexeme.clone(), param.var_type.lexeme.clone());
if let Some(reg) = REGISTERS.get(i) {
@@ -504,14 +513,19 @@ _builtin_environ:
);
}
}
Expr::Assign { name, value } => {
Expr::Assign { left, op, value } => {
self.compile_expr(env, value)?;
match left.as_ref() {
Expr::Variable(name) => {
// TODO: move to analyzer
let var = match env.get_var(&name.lexeme) {
Some(x) => x,
None => {
return error!(name.loc, format!("undefined variable: {}", &name.lexeme));
return error!(
name.loc,
format!("undefined variable: {}", &name.lexeme)
);
}
};
emit!(
@@ -520,6 +534,28 @@ _builtin_environ:
var.stack_offset,
);
}
Expr::Index { expr, index } => {
emit!(&mut self.output, " push rax");
self.compile_expr(env, expr)?;
emit!(&mut self.output, " push rax");
self.compile_expr(env, index)?;
emit!(&mut self.output, " pop rbx");
emit!(&mut self.output, " add rbx, rax");
emit!(&mut self.output, " pop rax");
emit!(&mut self.output, " mov BYTE [rbx], al");
}
Expr::MemberAccess { left, field } => {
emit!(&mut self.output, " push rax");
let offset = self.get_field_offset(env, left, field)?;
self.compile_expr(env, left)?;
emit!(&mut self.output, " pop rbx");
emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset);
}
_ => return error!(&op.loc, "invalid assignment target"),
};
}
Expr::Call {
callee,
paren: _,
@@ -627,8 +663,70 @@ _builtin_environ:
return error!(&op.loc, "can only take address of variables and functions");
}
},
Expr::New(_) => todo!(),
Expr::New(struct_name) => {
let struct_fields = &self.analyzer.structs[&struct_name.lexeme];
let memory_size = struct_fields.len() * 8;
emit!(&mut self.output, " mov rdi, {}", memory_size);
emit!(&mut self.output, " call mem.alloc");
emit!(&mut self.output, " push rax");
emit!(&mut self.output, " mov rdi, rax");
emit!(&mut self.output, " mov rsi, {}", memory_size);
emit!(&mut self.output, " call mem.zero");
emit!(&mut self.output, " pop rax");
}
Expr::MemberAccess { left, field } => {
let offset = self.get_field_offset(env, left, field)?;
self.compile_expr(env, left)?;
emit!(&mut self.output, " mov rax, QWORD [rax+{}]", offset);
}
}
Ok(())
}
fn is_valid_type_name(&self, name: &str) -> bool {
if BUILTIN_TYPES.contains(&name) {
return true;
}
if self.analyzer.structs.contains_key(name) {
return true;
}
false
}
fn get_field_offset(
&self,
env: &mut Env,
left: &Expr,
field: &Token,
) -> Result<usize, ZernError> {
let struct_name = match left {
Expr::Variable(name) => match env.get_var(&name.lexeme) {
Some(v) => v.var_type.clone(),
None => {
return error!(name.loc, format!("undefined variable: {}", &name.lexeme));
}
},
_ => {
return error!(
&field.loc,
"cannot determine struct type for member assignment"
);
}
};
let fields = match self.analyzer.structs.get(&struct_name) {
Some(f) => f,
None => {
return error!(&field.loc, format!("unknown struct type: {}", struct_name));
}
};
let offset = match fields.get(&field.lexeme) {
Some(o) => *o,
None => return error!(&field.loc, format!("unknown field: {}", &field.lexeme)),
};
Ok(offset)
}
}

View File

@@ -71,7 +71,8 @@ pub enum Expr {
},
Variable(Token),
Assign {
name: Token,
left: Box<Expr>,
op: Token,
value: Box<Expr>,
},
Call {
@@ -89,11 +90,12 @@ pub enum Expr {
expr: Box<Expr>,
},
New(Token),
MemberAccess {
left: Box<Expr>,
field: Token,
},
}
// TODO: currently they are all just 64 bit values
static TYPES: [&str; 7] = ["void", "u8", "i64", "str", "bool", "ptr", "array"];
pub struct Parser {
tokens: Vec<Token>,
current: usize,
@@ -159,9 +161,6 @@ impl Parser {
self.consume(TokenType::Colon, "expected ':' after parameter name")?;
let var_type = self.consume(TokenType::Identifier, "expected parameter type")?;
if !TYPES.contains(&var_type.lexeme.as_str()) {
return error!(&name.loc, format!("unknown type: {}", var_type.lexeme));
}
params.push(Param { var_type, var_name });
if !self.match_token(&[TokenType::Comma]) {
@@ -173,9 +172,6 @@ impl Parser {
self.consume(TokenType::RightBracket, "expected ']' after arguments")?;
self.consume(TokenType::Colon, "expected ':' after '['")?;
let return_type = self.consume(TokenType::Identifier, "expected return type")?;
if !TYPES.contains(&return_type.lexeme.as_str()) {
return error!(&name.loc, format!("unknown type: {}", return_type.lexeme));
}
self.is_inside_function = true;
let body = Box::new(self.block()?);
@@ -201,9 +197,6 @@ impl Parser {
self.consume(TokenType::Colon, "expected ':' after field name")?;
let var_type = self.consume(TokenType::Identifier, "expected field type")?;
if !TYPES.contains(&var_type.lexeme.as_str()) {
return error!(&name.loc, format!("unknown type: {}", var_type.lexeme));
}
fields.push(Param { var_type, var_name });
}
@@ -218,9 +211,6 @@ impl Parser {
let var_type = if self.match_token(&[TokenType::Colon]) {
let token = self.consume(TokenType::Identifier, "expected variable type")?;
if !TYPES.contains(&token.lexeme.as_str()) {
return error!(&name.loc, format!("unknown type: {}", token.lexeme));
}
Some(token)
} else {
None
@@ -332,13 +322,11 @@ impl Parser {
let equals = self.previous().clone();
let value = self.assignment()?;
return match expr {
Expr::Variable(name) => Ok(Expr::Assign {
name,
return Ok(Expr::Assign {
left: Box::new(expr),
op: equals,
value: Box::new(value),
}),
_ => return error!(equals.loc, "invalid assignment target"),
};
});
}
Ok(expr)
@@ -521,6 +509,13 @@ impl Parser {
expr: Box::new(expr),
index: Box::new(index),
}
} else if self.match_token(&[TokenType::Arrow]) {
let field =
self.consume(TokenType::Identifier, "expected field name after '->'")?;
expr = Expr::MemberAccess {
left: Box::new(expr),
field,
};
} else {
break;
}

View File

@@ -85,9 +85,9 @@ func crypto.blake2b.hash[outlen: i64, key: ptr, keylen: i64, input: ptr, inputle
if keylen > 0
for i in 0..keylen
mem.write8(block + i, key[i])
block[i] = key[i]
for i in (keylen)..128
mem.write8(block + i, 0)
block[i] = 0
c = 128
else
c = 0
@@ -99,7 +99,7 @@ func crypto.blake2b.hash[outlen: i64, key: ptr, keylen: i64, input: ptr, inputle
t1 = t1 + 1
crypto.blake2b._compress(h, block, t0, t1, 0, iv, sigma)
c = 0
mem.write8(block + c, input[i])
block[c] = input[i]
c = c + 1
t0 = t0 + c
@@ -108,11 +108,11 @@ func crypto.blake2b.hash[outlen: i64, key: ptr, keylen: i64, input: ptr, inputle
if c < 128
for i in (c)..128
mem.write8(block + i, 0)
block[i] = 0
crypto.blake2b._compress(h, block, t0, t1, 1, iv, sigma)
for i in 0..outlen
mem.write8(out + i, ((mem.read64(h + (i >> 3) * 8) >> (8 * (i & 7))) & 0xff))
out[i] = (mem.read64(h + (i >> 3) * 8) >> (8 * (i & 7))) & 0xff
mem.zero_and_free(h, 8 * 8)
mem.zero_and_free(block, 128)
@@ -210,10 +210,9 @@ func crypto.xchacha20._stream[key: ptr, nonce: ptr, out: ptr, len: i64] : void
crypto.xchacha20._hchacha20(key, nonce, subkey)
let nonce12: ptr = mem.alloc(12)
for i in 0..12
mem.write8(nonce12 + i, 0)
mem.zero(nonce12, 12)
for i in 0..8
mem.write8(nonce12 + 4 + i, nonce[16 + i])
nonce12[i + 4] = nonce[16 + i]
let blocknum = 0
let remaining: i64 = len
@@ -225,7 +224,7 @@ func crypto.xchacha20._stream[key: ptr, nonce: ptr, out: ptr, len: i64] : void
if remaining < 64
take = remaining
for i in 0..take
mem.write8(out + (len - remaining) + i, block[i])
out[len - remaining + i] = block[i]
remaining = remaining - take
blocknum = blocknum + 1
mem.zero_and_free(block, 64)
@@ -237,13 +236,13 @@ func crypto.xchacha20._stream[key: ptr, nonce: ptr, out: ptr, len: i64] : void
func crypto.xchacha20.xor_no_auth[key: ptr, nonce: ptr, input: ptr, len: i64] : ptr
if len <= 0
let out: ptr = mem.alloc(1)
mem.write8(out, 0)
out[0] = 0
return out
let out: ptr = mem.alloc(len)
let ks: ptr = mem.alloc(len)
crypto.xchacha20._stream(key, nonce, ks, len)
for i in 0..len
mem.write8(out + i, input[i] ^ ks[i])
out[i] = input[i] ^ ks[i]
mem.zero_and_free(ks, len)
return out
@@ -328,8 +327,8 @@ func crypto.x25519.pack[out: ptr, input: ptr] : void
for i in 0..16
let v: i64 = mem.read64(t + i * 8)
mem.write8(out + i * 2, v & 0xff)
mem.write8(out + i * 2 + 1, (v >> 8) & 0xff)
out[i * 2] = v & 0xff
out[i * 2 + 1] = (v >> 8) & 0xff
mem.zero_and_free(t, 16 * 8)
mem.zero_and_free(m, 16 * 8)
@@ -353,9 +352,9 @@ func crypto.x25519.scalarmult[scalar: ptr, point: ptr] : ptr
// copy and clamp scalar
for i in 0..32
mem.write8(clamped + i, scalar[i])
mem.write8(clamped, clamped[0] & 0xf8)
mem.write8(clamped + 31, (clamped[31] & 0x7f) | 0x40)
clamped[i] = scalar[i]
clamped[0] = clamped[0] & 0xf8
clamped[31] = (clamped[31] & 0x7f) | 0x40
// load point
crypto.x25519.unpack(x, point)

View File

@@ -21,7 +21,7 @@ func mem.zero_and_free[x: ptr, size: i64] : void
func mem.zero[x: ptr, size: i64] : void
for i in 0..size
mem.write8(x + i, 0)
x[i] = 0
func mem.read8[x: ptr] : u8
return x[0]
@@ -35,14 +35,11 @@ func mem.read32[x: ptr] : i64
func mem.read64[x: ptr] : i64
return _builtin_read64(x)
func mem.write8[x: ptr, d: u8] : void
_builtin_set8(x, d)
func mem.write32[x: ptr, d: i64] : void
mem.write8(x, d & 0xff)
mem.write8(x + 1, (d >> 8) & 0xff)
mem.write8(x + 2, (d >> 16) & 0xff)
mem.write8(x + 3, (d >> 24) & 0xff)
x[0] = d & 0xff
x[1] = (d >> 8) & 0xff
x[2] = (d >> 16) & 0xff
x[3] = (d >> 24) & 0xff
func mem.write64[x: ptr, d: i64] : void
_builtin_set64(x, d)
@@ -80,8 +77,9 @@ func io.read_line[]: str
let buffer: str = mem.alloc(MAX_SIZE + 1)
let n: i64 = _builtin_syscall(SYS_read, 0, buffer, MAX_SIZE)
if n < 0
mem.free(buffer)
return ""
str.set(buffer, n, 0)
buffer[n] = 0
return buffer
func io.read_file[path: str] : str
@@ -94,8 +92,22 @@ func io.read_file[path: str]: str
let buffer: str = mem.alloc(size + 1)
let n: i64 = _builtin_syscall(SYS_read, fd, buffer, size)
str.set(buffer, n, 0)
_builtin_syscall(SYS_close, fd)
buffer[n] = 0
return buffer
func io.read_binary_file[path: str, len_ptr: ptr] : ptr
let fd: i64 = _builtin_syscall(SYS_openat, -100, path, 0, 0)
if fd < 0
dbg.panic("failed to open file")
let size: i64 = _builtin_syscall(SYS_lseek, fd, 0, 2)
_builtin_syscall(SYS_lseek, fd, 0, 0)
let buffer: ptr = mem.alloc(size)
_builtin_syscall(SYS_read, fd, buffer, size)
_builtin_syscall(SYS_close, fd)
mem.write64(len_ptr, size)
return buffer
func io.write_file[path: str, content: str] : void
@@ -116,12 +128,9 @@ func str.copy[s: str] : str
let size: i64 = str.len(s) + 1
let dup: str = mem.alloc(size)
for i in 0..size
str.set(dup, i, s[i])
dup[i] = s[i]
return dup
func str.set[s: str, n: i64, c: u8] : void
mem.write8(s + n, c)
func str.equal[a: str, b: str] : bool
let i = 0
while a[i] != 0 && b[i] != 0
@@ -156,10 +165,10 @@ func str.concat[a: str, b: str] : str
let b_len: i64 = str.len(b)
let out: str = mem.alloc(a_len + b_len + 1)
for i in 0..a_len
str.set(out, i, a[i])
out[i] = a[i]
for i in 0..b_len
str.set(out, a_len + i, b[i])
str.set(out, a_len + b_len, 0)
out[a_len + i] = b[i]
out[a_len + b_len] = 0
return out
func str.find[haystack: str, needle: str] : i64
@@ -185,8 +194,8 @@ func str.substr[s: str, start: i64, length: i64] : str
let out: str = mem.alloc(length + 1)
for i in 0..length
str.set(out, i, s[start + i])
str.set(out, length, 0)
out[i] = s[start + i]
out[length] = 0
return out
func str.trim[s: str] : str
@@ -242,8 +251,8 @@ func str.reverse[s: str] : str
let out: str = mem.alloc(len + 1)
for i in 0..len
str.set(out, i, s[len - i - 1])
str.set(out, len, 0)
out[i] = s[len - i - 1]
out[len] = 0
return out
// not sure this covers all wacky edge cases
@@ -258,21 +267,21 @@ func str.from_i64[n: i64] : str
let i = 0
while n > 0
let d: u8 = n % 10
str.set(buf, i, '0' + d)
buf[i] = '0' + d
n = n / 10
i = i + 1
if neg
str.set(buf, i, '-')
buf[i] = '-'
i = i + 1
str.set(buf, i, 0)
buf[i] = 0
let s: str = str.reverse(buf)
mem.free(buf)
return s
func str.from_char[c: u8] : str
let s: str = mem.alloc(2)
str.set(s, 0, c)
str.set(s, 1, 0)
s[0] = c
s[1] = 0
return s
func str.parse_i64[s: str] : i64
@@ -301,11 +310,11 @@ func str.hex_encode[s: str, s_len: i64] : str
for i in 0..s_len
let high: u8 = (s[i] >> 4) & 15
let low: u8 = s[i] & 15
str.set(out, j, hex_chars[high])
str.set(out, j + 1, hex_chars[low])
out[j] = hex_chars[high]
out[j + 1] = hex_chars[low]
j = j + 2
str.set(out, j, 0)
out[j] = 0
return out
func str._hex_digit_to_int[d: u8] : i64
@@ -322,11 +331,11 @@ func str.hex_decode[s: str] : str
let out: str = mem.alloc(s_len / 2 + 1)
while i < s_len
str.set(out, j, str._hex_digit_to_int(s[i]) * 16 + str._hex_digit_to_int(s[i + 1]))
out[j] = str._hex_digit_to_int(s[i]) * 16 + str._hex_digit_to_int(s[i + 1])
i = i + 2
j = j + 1
str.set(out, j, 0)
out[j] = 0
return out
func math.gcd[a: i64, b: i64] : i64
@@ -606,14 +615,14 @@ func net.listen[packed_host: i64, port: i64] : i64
let sa: ptr = mem.alloc(16)
mem.zero(sa, 16)
mem.write8(sa + 0, 2)
mem.write8(sa + 1, 0)
mem.write8(sa + 2, (port >> 8) & 255)
mem.write8(sa + 3, port & 255)
mem.write8(sa + 4, (packed_host >> 24) & 255)
mem.write8(sa + 5, (packed_host >> 16) & 255)
mem.write8(sa + 6, (packed_host >> 8) & 255)
mem.write8(sa + 7, packed_host & 255)
sa[0] = 2
sa[1] = 0
sa[2] = (port >> 8) & 255
sa[3] = port & 255
sa[4] = (packed_host >> 24) & 255
sa[5] = (packed_host >> 16) & 255
sa[6] = (packed_host >> 8) & 255
sa[7] = packed_host & 255
if _builtin_syscall(SYS_bind, s, sa, 16) < 0
_builtin_syscall(SYS_close, s)
@@ -640,13 +649,13 @@ func net.connect[host: str, port: i64] : i64
let sa: ptr = mem.alloc(16)
mem.zero(sa, 16)
mem.write8(sa + 0, 2)
mem.write8(sa + 2, (port >> 8) & 255)
mem.write8(sa + 3, port & 255)
mem.write8(sa + 4, ip_ptr[0])
mem.write8(sa + 5, ip_ptr[1])
mem.write8(sa + 6, ip_ptr[2])
mem.write8(sa + 7, ip_ptr[3])
sa[0] = 2
sa[2] = (port >> 8) & 255
sa[3] = port & 255
sa[4] = ip_ptr[0]
sa[5] = ip_ptr[1]
sa[6] = ip_ptr[2]
sa[7] = ip_ptr[3]
if _builtin_syscall(SYS_connect, s, sa, 16) < 0
mem.free(sa)

View File

@@ -23,6 +23,7 @@ pub enum TokenType {
DoubleDot,
ShiftLeft,
ShiftRight,
Arrow,
Equal,
DoubleEqual,
@@ -155,10 +156,16 @@ impl Tokenizer {
'+' => self.add_token(TokenType::Plus),
'*' => self.add_token(TokenType::Star),
',' => self.add_token(TokenType::Comma),
'-' => self.add_token(TokenType::Minus),
'%' => self.add_token(TokenType::Mod),
'^' => self.add_token(TokenType::Xor),
':' => self.add_token(TokenType::Colon),
'-' => {
if self.match_char('>') {
self.add_token(TokenType::Arrow)
} else {
self.add_token(TokenType::Minus)
}
}
'.' => {
if self.match_char('.') {
self.add_token(TokenType::DoubleDot)