assert, IO.read_file, set, substr, strrev
This commit is contained in:
5
examples/euler13.zr
Normal file
5
examples/euler13.zr
Normal 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
11
examples/euler15.zr
Normal 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)
|
||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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()?;
|
||||||
|
|||||||
38
src/std.zr
38
src/std.zr
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user