implement String.nth and OS.time in stdlib
This commit is contained in:
@@ -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])
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
51
src/main.rs
51
src/main.rs
@@ -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(())
|
||||||
|
|||||||
@@ -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]
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/std.zr
13
src/std.zr
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user