implement String.nth and OS.time in stdlib

This commit is contained in:
2025-06-29 16:10:39 +02:00
parent 21cac533f2
commit 62dd8b0d52
6 changed files with 37 additions and 90 deletions

View File

@@ -22,7 +22,9 @@ func partition[arr: Array, low: I64, high: I64] : I64
return i + 1 return i + 1
func main[] : I64 func main[] : I64
let arr: Array = [340, 252, 352, 117, 650, 652, 322, 175, 714, 268, 725, 664] let arr: Array = []
for i in 0..10
Array.push(arr, Math.abs(Math.urandom() % 1000))
for i in 0..Array.size(arr) for i in 0..Array.size(arr)
print_i64(arr[i]) print_i64(arr[i])

View File

@@ -84,7 +84,6 @@ impl CodegenX86_64 {
pub fn get_output(&self) -> String { pub fn get_output(&self) -> String {
format!( format!(
"section .data "section .data
S0 db \"assertion failed on line %d\",10,0
{}{}", {}{}",
self.data_section, self.output self.data_section, self.output
) )
@@ -150,34 +149,11 @@ Bit.rshift:
sar rax, cl sar rax, cl
ret ret
section .text.String.nth
String.nth:
movzx rax, byte [rdi + rsi]
ret
section .text.String.set section .text.String.set
String.set: String.set:
mov [rdi + rsi], dl mov [rdi + rsi], dl
ret ret
section .text.OS.time
OS.time:
push rbx
sub rsp, 16
mov rbx, rsp
mov rdi, rbx
xor esi, esi
call gettimeofday
imul rcx, qword [rbx], 1000
mov rax, qword [rbx+8]
mov esi, 1000
cqo
idiv rsi
add rax, rcx
add rsp, 16
pop rbx
ret
section .text.OS.listdir section .text.OS.listdir
OS.listdir: OS.listdir:
push r14 push r14
@@ -373,18 +349,6 @@ Array.free:
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, S0");
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);
}
Stmt::For { Stmt::For {
var, var,
start, start,

View File

@@ -29,6 +29,17 @@ fn compile_file_to(
Ok(()) Ok(())
} }
fn run_command(cmd: String) {
if !Command::new("sh")
.args(["-c", &cmd])
.status()
.unwrap()
.success()
{
process::exit(1);
}
}
fn compile_file(args: Args) -> Result<(), ZernError> { fn compile_file(args: Args) -> Result<(), ZernError> {
let source = match fs::read_to_string(&args.path) { let source = match fs::read_to_string(&args.path) {
Ok(x) => x, Ok(x) => x,
@@ -46,41 +57,17 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
compile_file_to(&mut codegen, filename, source)?; compile_file_to(&mut codegen, filename, source)?;
if !args.output_asm { if !args.output_asm {
if fs::write(format!("{}.s", args.out), codegen.get_output()).is_err() { fs::write(format!("{}.s", args.out), codegen.get_output()).unwrap();
eprintln!("\x1b[91mERROR\x1b[0m: failed to write to {}.s", args.out);
process::exit(1);
}
if !Command::new("sh") run_command(format!("nasm -f elf64 -o {}.o {}.s", args.out, args.out));
.args([
"-c",
&format!("nasm -f elf64 -o {}.o {}.s", args.out, args.out),
])
.status()
.unwrap()
.success()
{
process::exit(1);
}
// TODO: drop libc entirely // TODO: drop libc entirely
if !Command::new("sh") run_command(format!(
.args([ "./musl-1.2.4/root/bin/musl-gcc -static -o {} {}.o -flto -Wl,--gc-sections {}",
"-c", args.out, args.out, args.cflags
&format!( ));
"./musl-1.2.4/root/bin/musl-gcc -static -o {} {}.o -flto -Wl,--gc-sections {}", } else {
args.out, args.out, args.cflags fs::write(&args.out, codegen.get_output()).unwrap();
),
])
.status()
.unwrap()
.success()
{
process::exit(1);
}
} else if fs::write(&args.out, codegen.get_output()).is_err() {
eprintln!("\x1b[91mERROR\x1b[0m: failed to write to {}", args.out);
process::exit(1);
} }
Ok(()) Ok(())

View File

@@ -37,10 +37,6 @@ pub enum Stmt {
body: Box<Stmt>, body: Box<Stmt>,
}, },
Return(Expr), Return(Expr),
Assert {
keyword: Token,
value: Expr,
},
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -197,11 +193,6 @@ impl Parser {
self.for_statement() self.for_statement()
} else if self.match_token(&[TokenType::KeywordReturn]) { } else if self.match_token(&[TokenType::KeywordReturn]) {
Ok(Stmt::Return(self.expression()?)) 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()?))
} }
@@ -490,7 +481,8 @@ impl Parser {
fn consume(&mut self, token_type: TokenType, message: &str) -> Result<Token, ZernError> { fn consume(&mut self, token_type: TokenType, message: &str) -> Result<Token, ZernError> {
if self.check(&token_type) { if self.check(&token_type) {
Ok(self.advance().clone()) self.current += 1;
Ok(self.previous().clone())
} else { } else {
error!(self.previous().loc, format!("{}", message)) error!(self.previous().loc, format!("{}", message))
} }
@@ -499,7 +491,7 @@ impl Parser {
fn match_token(&mut self, token_types: &[TokenType]) -> bool { fn match_token(&mut self, token_types: &[TokenType]) -> bool {
for x in token_types { for x in token_types {
if self.check(x) { if self.check(x) {
self.advance(); self.current += 1;
return true; return true;
} }
} }
@@ -514,13 +506,6 @@ impl Parser {
} }
} }
fn advance(&mut self) -> &Token {
if !self.eof() {
self.current += 1;
}
self.previous()
}
fn peek(&self) -> &Token { fn peek(&self) -> &Token {
&self.tokens[self.current] &self.tokens[self.current]
} }

View File

@@ -8,6 +8,9 @@ func print[x: String] : I64
func print_i64[x: I64] : I64 func print_i64[x: I64] : I64
printf("%ld\n", x) printf("%ld\n", x)
func String.nth[s: String, n: I64] : U8
return deref(s + n)
func String.is_whitespace[c: U8] : Bool func String.is_whitespace[c: U8] : Bool
return c == ' ' || c == 10 || c == 13 || c == 9 return c == ' ' || c == 10 || c == 13 || c == 9
@@ -167,6 +170,14 @@ func Math.urandom[]: I64
func Array.new[] : Array func Array.new[] : Array
return calloc(1, 24) return calloc(1, 24)
func OS.time[] : I64
let tv: Ptr = malloc(16)
gettimeofday(tv, 0)
let seconds: I64 = deref(tv)
let microseconds: I64 = deref(tv+8)
free(tv)
return seconds * 1000 + microseconds / 1000
func Crypto.hex_encode[s: String] : String func Crypto.hex_encode[s: String] : String
let hex_chars: String = "0123456789abcdef" let hex_chars: String = "0123456789abcdef"
let s_len: I64 = strlen(s) let s_len: I64 = strlen(s)
@@ -293,7 +304,7 @@ func Crypto.base64_decode[s: String] : String
s4 = String.find(chars, String.nth(s, i+3)) s4 = String.find(chars, String.nth(s, i+3))
i = i + 4 i = i + 4
let triple: U8 = Bit.lshift(s1, 18) || Bit.lshift(s2, 12) || Bit.lshift(s3, 6) || s4 let triple: I64 = Bit.lshift(s1, 18) || Bit.lshift(s2, 12) || Bit.lshift(s3, 6) || s4
String.set(out, j, Bit.rshift(triple, 16) && 255) String.set(out, j, Bit.rshift(triple, 16) && 255)
j = j + 1 j = j + 1

View File

@@ -43,7 +43,6 @@ pub enum TokenType {
KeywordIn, KeywordIn,
KeywordFunc, KeywordFunc,
KeywordReturn, KeywordReturn,
KeywordAssert,
Indent, Indent,
Dedent, Dedent,
@@ -336,7 +335,6 @@ impl Tokenizer {
"in" => TokenType::KeywordIn, "in" => TokenType::KeywordIn,
"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,