assert, IO.read_file, set, substr, strrev

This commit is contained in:
2025-06-02 17:41:52 +02:00
parent e647e7f508
commit 89d54dfc81
6 changed files with 90 additions and 34 deletions

5
examples/euler13.zr Normal file
View File

@@ -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()

11
examples/euler15.zr Normal file
View File

@@ -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)

View File

@@ -58,7 +58,7 @@ macro_rules! emit {
} }
static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; 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 { pub struct CodegenX86_64 {
output: String, output: String,
@@ -85,6 +85,7 @@ impl CodegenX86_64 {
pub fn get_output(&self) -> String { pub fn get_output(&self) -> String {
format!( format!(
"section .data "section .data
SASSERT db \"assertion failed on line %d\",10,0
{}{}", {}{}",
self.data_section, self.output self.data_section, self.output
) )
@@ -104,38 +105,17 @@ extern strcmp
extern strcat extern strcat
extern strcpy extern strcpy
extern strdup extern strdup
extern strlcpy
extern puts extern puts
extern fopen
extern fseek
extern ftell
extern fread
extern rewind
extern system extern system
extern exit extern exit
copystr equ strdup 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: isqrt:
xor rax, rax xor rax, rax
mov rcx, 1 mov rcx, 1
@@ -170,6 +150,10 @@ isqrt:
nth: nth:
movzx rax, byte [rdi + rsi] movzx rax, byte [rdi + rsi]
ret ret
set:
mov [rdi + rsi], dl
ret
", ",
); );
Ok(()) Ok(())
@@ -275,6 +259,18 @@ nth:
emit!(&mut self.output, " pop rbp"); emit!(&mut self.output, " pop rbp");
emit!(&mut self.output, " ret"); 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(()) Ok(())
} }
@@ -431,6 +427,7 @@ nth:
paren, paren,
args, args,
} => { } => {
// TODO: in function calls like a(1, b(2, 3)) the first argument will get overwritten when calling b
let callee = match *callee { let callee = match *callee {
Expr::Variable(name) => name.lexeme, Expr::Variable(name) => name.lexeme,
_ => return error!(&paren.loc, "tried to call a non-constant expression"), _ => return error!(&paren.loc, "tried to call a non-constant expression"),

View File

@@ -31,6 +31,10 @@ pub enum Stmt {
body: Box<Stmt>, body: Box<Stmt>,
}, },
Return(Expr), Return(Expr),
Assert {
keyword: Token,
value: Expr,
},
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -164,16 +168,17 @@ impl Parser {
} else if self.match_token(&[TokenType::KeywordWhile]) { } else if self.match_token(&[TokenType::KeywordWhile]) {
self.while_statement() self.while_statement()
} else if self.match_token(&[TokenType::KeywordReturn]) { } 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 { } else {
Ok(Stmt::Expression(self.expression()?)) Ok(Stmt::Expression(self.expression()?))
} }
} }
fn return_statement(&mut self) -> Result<Stmt, ZernError> {
Ok(Stmt::Return(self.expression()?))
}
fn if_statement(&mut self) -> Result<Stmt, ZernError> { fn if_statement(&mut self) -> Result<Stmt, ZernError> {
let condition = self.expression()?; let condition = self.expression()?;
let then_branch = self.block()?; let then_branch = self.block()?;

View File

@@ -1,3 +1,7 @@
func panic[msg: String] : I64
printf("PANIC: %s\n", msg)
exit(1)
func print[x: String] : I64 func print[x: String] : I64
printf("%s\n", x) printf("%s\n", x)
@@ -10,7 +14,39 @@ func concat[a: String, b: String] : String
strcat(c, b) strcat(c, b)
return c 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 return c - 48
func I64.to_string[n: I64] : String func I64.to_string[n: I64] : String

View File

@@ -39,6 +39,7 @@ pub enum TokenType {
KeywordWhile, KeywordWhile,
KeywordFunc, KeywordFunc,
KeywordReturn, KeywordReturn,
KeywordAssert,
Indent, Indent,
Dedent, Dedent,
@@ -311,6 +312,7 @@ impl Tokenizer {
"while" => TokenType::KeywordWhile, "while" => TokenType::KeywordWhile,
"func" => TokenType::KeywordFunc, "func" => TokenType::KeywordFunc,
"return" => TokenType::KeywordReturn, "return" => TokenType::KeywordReturn,
"assert" => TokenType::KeywordAssert,
"true" => TokenType::True, "true" => TokenType::True,
"false" => TokenType::False, "false" => TokenType::False,
_ => TokenType::Identifier, _ => TokenType::Identifier,