Compare commits

...

3 Commits

Author SHA1 Message Date
43a20c99f6 remove enums 2026-06-26 17:38:55 +02:00
6fe971c615 simplify emit_debug with gas magic 2026-06-26 16:50:05 +02:00
8ad69be5aa switched to gnu assembler for 5x speed up 2026-06-26 16:30:04 +02:00
9 changed files with 140 additions and 158 deletions

View File

@@ -77,14 +77,12 @@ pub struct CodegenX86_64<'a> {
data_counter: usize, data_counter: usize,
pub symbol_table: &'a SymbolTable, pub symbol_table: &'a SymbolTable,
pub expr_types: &'a HashMap<usize, String>, pub expr_types: &'a HashMap<usize, String>,
emit_debug: bool,
} }
impl<'a> CodegenX86_64<'a> { impl<'a> CodegenX86_64<'a> {
pub fn new( pub fn new(
symbol_table: &'a SymbolTable, symbol_table: &'a SymbolTable,
expr_types: &'a HashMap<usize, String>, expr_types: &'a HashMap<usize, String>,
emit_debug: bool,
) -> CodegenX86_64<'a> { ) -> CodegenX86_64<'a> {
CodegenX86_64 { CodegenX86_64 {
output: String::new(), output: String::new(),
@@ -93,7 +91,6 @@ impl<'a> CodegenX86_64<'a> {
data_counter: 1, data_counter: 1,
symbol_table, symbol_table,
expr_types, expr_types,
emit_debug,
} }
} }
@@ -103,58 +100,60 @@ impl<'a> CodegenX86_64<'a> {
} }
pub fn get_output(&self) -> String { pub fn get_output(&self) -> String {
format!("section .data\n{}{}", self.data_section, self.output) format!(".section .data\n{}{}", self.data_section, self.output)
} }
pub fn emit_prologue(&mut self, use_crt: bool) -> Result<(), ZernError> { pub fn emit_prologue(&mut self, use_crt: bool) -> Result<(), ZernError> {
emit!( emit!(
&mut self.output, &mut self.output,
"section .note.GNU-stack ".intel_syntax noprefix
db 0
section .bss .section .note.GNU-stack
_heap_head: resq 1 .byte 0
_heap_tail: resq 1
_environ: resq 1
section .text._builtin_heap_head .section .bss
_heap_head: .zero 8
_heap_tail: .zero 8
_environ: .zero 8
.section .text._builtin_heap_head
_builtin_heap_head: _builtin_heap_head:
lea rax, [rel _heap_head] lea rax, [rip + _heap_head]
ret ret
section .text._builtin_heap_tail .section .text._builtin_heap_tail
_builtin_heap_tail: _builtin_heap_tail:
lea rax, [rel _heap_tail] lea rax, [rip + _heap_tail]
ret ret
section .text._builtin_read64 .section .text._builtin_read64
_builtin_read64: _builtin_read64:
mov rax, QWORD [rdi] mov rax, QWORD PTR [rdi]
ret ret
section .text._builtin_set64 .section .text._builtin_set64
_builtin_set64: _builtin_set64:
mov [rdi], rsi mov [rdi], rsi
ret ret
section .text._builtin_cvtsi2sd .section .text._builtin_cvtsi2sd
_builtin_cvtsi2sd: _builtin_cvtsi2sd:
cvtsi2sd xmm0, rdi cvtsi2sd xmm0, rdi
movq rax, xmm0 movq rax, xmm0
ret ret
section .text._builtin_cvttsd2si .section .text._builtin_cvttsd2si
_builtin_cvttsd2si: _builtin_cvttsd2si:
cvttsd2si rax, xmm0 cvttsd2si rax, xmm0
ret ret
section .text._builtin_f64_to_float .section .text._builtin_f64_to_float
_builtin_f64_to_float: _builtin_f64_to_float:
cvtsd2ss xmm0, xmm0 cvtsd2ss xmm0, xmm0
movd eax, xmm0 movd eax, xmm0
ret ret
section .text._builtin_syscall .section .text._builtin_syscall
_builtin_syscall: _builtin_syscall:
mov rax, rdi mov rax, rdi
mov rdi, rsi mov rdi, rsi
@@ -172,26 +171,26 @@ _builtin_syscall:
emit!( emit!(
&mut self.output, &mut self.output,
" "
section .text._builtin_environ .section .text._builtin_environ
_builtin_environ: _builtin_environ:
lea rax, [rel _environ] lea rax, [rip + _environ]
mov rax, [rax] mov rax, [rax]
ret ret
global _start .globl _start
section .text .section .text
_start: _start:
xor rbp, rbp xor rbp, rbp
; setup args // setup args
pop rdi pop rdi
mov rsi, rsp mov rsi, rsp
; save environ // save environ
lea rdx, [rsi + rdi*8 + 8] lea rdx, [rsi + rdi*8 + 8]
lea rax, [rel _environ] lea rax, [rip + _environ]
mov [rax], rdx mov [rax], rdx
; align stack // align stack
and rsp, -16 and rsp, -16
; exit(main()) // exit(main())
call main call main
mov rdi, rax mov rdi, rax
mov rax, 60 mov rax, 60
@@ -202,10 +201,10 @@ _start:
emit!( emit!(
&mut self.output, &mut self.output,
" "
section .text._builtin_environ .section .text._builtin_environ
_builtin_environ: _builtin_environ:
extern environ .extern environ
mov rax, [rel environ] mov rax, [rip + environ]
ret ret
" "
); );
@@ -239,7 +238,7 @@ _builtin_environ:
self.compile_expr(env, initializer)?; self.compile_expr(env, initializer)?;
let offset = env.define_var(name.lexeme.clone(), var_type); let offset = env.define_var(name.lexeme.clone(), var_type);
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
} }
Stmt::Assign { left, op, value } => { Stmt::Assign { left, op, value } => {
self.compile_expr(env, value)?; self.compile_expr(env, value)?;
@@ -250,7 +249,7 @@ _builtin_environ:
let var = env.get_var(&name.lexeme).unwrap(); let var = env.get_var(&name.lexeme).unwrap();
emit!( emit!(
&mut self.output, &mut self.output,
" mov QWORD [rbp-{}], rax", " mov QWORD PTR [rbp-{}], rax",
var.stack_offset, var.stack_offset,
); );
} }
@@ -266,7 +265,7 @@ _builtin_environ:
emit!(&mut self.output, " pop rbx"); emit!(&mut self.output, " pop rbx");
emit!(&mut self.output, " add rbx, rax"); emit!(&mut self.output, " add rbx, rax");
emit!(&mut self.output, " pop rax"); emit!(&mut self.output, " pop rax");
emit!(&mut self.output, " mov BYTE [rbx], al"); emit!(&mut self.output, " mov BYTE PTR [rbx], al");
} }
ExprKind::MemberAccess { left, field } => { ExprKind::MemberAccess { left, field } => {
emit!(&mut self.output, " push rax"); emit!(&mut self.output, " push rax");
@@ -275,7 +274,7 @@ _builtin_environ:
self.compile_expr(env, left)?; self.compile_expr(env, left)?;
emit!(&mut self.output, " pop rbx"); emit!(&mut self.output, " pop rbx");
emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset); emit!(&mut self.output, " mov QWORD PTR [rax+{}], rbx", offset);
} }
_ => return error!(&op.loc, "invalid assignment target"), _ => return error!(&op.loc, "invalid assignment target"),
}; };
@@ -302,7 +301,12 @@ _builtin_environ:
env.define_var(target.lexeme.clone(), types[i].to_string()) env.define_var(target.lexeme.clone(), types[i].to_string())
} }
}; };
emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg); emit!(
&mut self.output,
" mov QWORD PTR [rbp-{}], {}",
offset,
reg
);
} }
} }
Stmt::Const { .. } => { Stmt::Const { .. } => {
@@ -365,14 +369,11 @@ _builtin_environ:
exported, exported,
} => { } => {
let name = &name.lexeme; let name = &name.lexeme;
if self.emit_debug || *exported || name == "main" { if *exported || name == "main" {
emit!( emit!(&mut self.output, ".globl {0}", name);
&mut self.output,
"global {0}:function ({0}.end - {0})",
name
);
} }
emit!(&mut self.output, "section .text.{}", name); emit!(&mut self.output, ".type {0}, @function", name);
emit!(&mut self.output, ".section .text.{}", name);
emit!(&mut self.output, "{}:", name); emit!(&mut self.output, "{}:", name);
emit!(&mut self.output, " push rbp"); emit!(&mut self.output, " push rbp");
emit!(&mut self.output, " mov rbp, rsp"); emit!(&mut self.output, " mov rbp, rsp");
@@ -388,15 +389,20 @@ _builtin_environ:
param.var_type.lexeme.clone(), param.var_type.lexeme.clone(),
); );
if let Some(reg) = REGISTERS.get(i) { if let Some(reg) = REGISTERS.get(i) {
emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg); emit!(
&mut self.output,
" mov QWORD PTR [rbp-{}], {}",
offset,
reg
);
} else { } else {
let stack_offset = 16 + 8 * (i - REGISTERS.len()); let stack_offset = 16 + 8 * (i - REGISTERS.len());
emit!( emit!(
&mut self.output, &mut self.output,
" mov rax, QWORD [rbp+{}]", " mov rax, QWORD PTR [rbp+{}]",
stack_offset stack_offset
); );
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
} }
} }
} }
@@ -423,7 +429,7 @@ _builtin_environ:
emit!(&mut self.output, " ret"); emit!(&mut self.output, " ret");
} }
emit!(&mut self.output, ".end:"); emit!(&mut self.output, ".size {0}, . - {0}", name);
// patch the stack size after we know how much we actually need // patch the stack size after we know how much we actually need
let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15); let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15);
@@ -465,21 +471,29 @@ _builtin_environ:
let offset = env.define_var(var.lexeme.clone(), "i64".into()); let offset = env.define_var(var.lexeme.clone(), "i64".into());
self.compile_expr(env, start)?; self.compile_expr(env, start)?;
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
self.compile_expr(env, end)?; self.compile_expr(env, end)?;
let end_offset = env.next_offset; let end_offset = env.next_offset;
env.next_offset += 8; env.next_offset += 8;
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", end_offset); emit!(
&mut self.output,
" mov QWORD PTR [rbp-{}], rax",
end_offset
);
emit!(&mut self.output, "{}:", env.loop_begin_label); emit!(&mut self.output, "{}:", env.loop_begin_label);
emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset); emit!(&mut self.output, " mov rax, QWORD PTR [rbp-{}]", offset);
emit!(&mut self.output, " mov rcx, QWORD [rbp-{}]", end_offset); emit!(
&mut self.output,
" mov rcx, QWORD PTR [rbp-{}]",
end_offset
);
emit!(&mut self.output, " cmp rax, rcx"); emit!(&mut self.output, " cmp rax, rcx");
emit!(&mut self.output, " jge {}", env.loop_end_label); emit!(&mut self.output, " jge {}", env.loop_end_label);
self.compile_stmt(env, body)?; self.compile_stmt(env, body)?;
emit!(&mut self.output, "{}:", env.loop_continue_label); emit!(&mut self.output, "{}:", env.loop_continue_label);
emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset); emit!(&mut self.output, " mov rax, QWORD PTR [rbp-{}]", offset);
emit!(&mut self.output, " add rax, 1"); emit!(&mut self.output, " add rax, 1");
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
emit!(&mut self.output, " jmp {}", env.loop_begin_label); emit!(&mut self.output, " jmp {}", env.loop_begin_label);
emit!(&mut self.output, "{}:", env.loop_end_label); emit!(&mut self.output, "{}:", env.loop_end_label);
env.pop_scope(); env.pop_scope();
@@ -495,14 +509,11 @@ _builtin_environ:
emit!(&mut self.output, " jmp {}", env.loop_continue_label); emit!(&mut self.output, " jmp {}", env.loop_continue_label);
} }
Stmt::Extern(name) => { Stmt::Extern(name) => {
emit!(&mut self.output, "extern {}", name.lexeme); emit!(&mut self.output, ".extern {}", name.lexeme);
} }
Stmt::Struct { .. } => { Stmt::Struct { .. } => {
// handled in SymbolTable // handled in SymbolTable
} }
Stmt::Enum { .. } => {
// handled in SymbolTable
}
} }
Ok(()) Ok(())
} }
@@ -610,11 +621,8 @@ _builtin_environ:
emit!(&mut self.output, " mov rax, {}", token.lexeme); emit!(&mut self.output, " mov rax, {}", token.lexeme);
} }
TokenType::FloatLiteral => { TokenType::FloatLiteral => {
emit!( let value: f64 = token.lexeme.parse().unwrap();
&mut self.output, emit!(&mut self.output, " mov rax, {}", value.to_bits());
" mov rax, __float64__({})",
token.lexeme
);
} }
TokenType::CharLiteral => { TokenType::CharLiteral => {
emit!( emit!(
@@ -635,10 +643,10 @@ _builtin_environ:
.chain(std::iter::once("0".into())) .chain(std::iter::once("0".into()))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(","); .join(",");
emit!(&mut self.data_section, " {} db {}", label, charcodes); emit!(&mut self.data_section, " {}: .byte {}", label, charcodes);
self.data_counter += 1; self.data_counter += 1;
emit!(&mut self.output, " mov rax, {}", label); emit!(&mut self.output, " lea rax, [rip + {}]", label);
} }
TokenType::True => { TokenType::True => {
emit!(&mut self.output, " mov rax, 1"); emit!(&mut self.output, " mov rax, 1");
@@ -679,7 +687,7 @@ _builtin_environ:
let var = env.get_var(&name.lexeme).unwrap(); let var = env.get_var(&name.lexeme).unwrap();
emit!( emit!(
&mut self.output, &mut self.output,
" mov rax, QWORD [rbp-{}]", " mov rax, QWORD PTR [rbp-{}]",
var.stack_offset, var.stack_offset,
); );
} }
@@ -767,12 +775,12 @@ _builtin_environ:
self.compile_expr(env, index)?; self.compile_expr(env, index)?;
emit!(&mut self.output, " pop rbx"); emit!(&mut self.output, " pop rbx");
emit!(&mut self.output, " add rax, rbx"); emit!(&mut self.output, " add rax, rbx");
emit!(&mut self.output, " movzx rax, BYTE [rax]"); emit!(&mut self.output, " movzx rax, BYTE PTR [rax]");
} }
ExprKind::AddrOf { op, expr } => match &expr.kind { ExprKind::AddrOf { op, expr } => match &expr.kind {
ExprKind::Variable(name) => { ExprKind::Variable(name) => {
if self.symbol_table.functions.contains_key(&name.lexeme) { if self.symbol_table.functions.contains_key(&name.lexeme) {
emit!(&mut self.output, " mov rax, {}", name.lexeme); emit!(&mut self.output, " lea rax, [rip + {}]", name.lexeme);
} else { } else {
let var = match env.get_var(&name.lexeme) { let var = match env.get_var(&name.lexeme) {
Some(x) => x, Some(x) => x,
@@ -785,7 +793,7 @@ _builtin_environ:
}; };
emit!( emit!(
&mut self.output, &mut self.output,
" lea rax, QWORD [rbp-{}]", " lea rax, QWORD PTR [rbp-{}]",
var.stack_offset, var.stack_offset,
); );
} }
@@ -821,7 +829,7 @@ _builtin_environ:
ExprKind::MemberAccess { left, field } => { ExprKind::MemberAccess { left, field } => {
let offset = self.get_field_offset(left, field)?; let offset = self.get_field_offset(left, field)?;
self.compile_expr(env, left)?; self.compile_expr(env, left)?;
emit!(&mut self.output, " mov rax, QWORD [rax+{}]", offset); emit!(&mut self.output, " mov rax, QWORD PTR [rax+{}]", offset);
} }
ExprKind::Cast { expr, type_name: _ } => { ExprKind::Cast { expr, type_name: _ } => {
self.compile_expr(env, expr)?; self.compile_expr(env, expr)?;
@@ -857,7 +865,11 @@ _builtin_environ:
let mut int_idx = 0; let mut int_idx = 0;
for (i, arg_type) in arg_types.iter().enumerate().take(to_register) { for (i, arg_type) in arg_types.iter().enumerate().take(to_register) {
let offset = 8 * (arg_count - 1 - i); let offset = 8 * (arg_count - 1 - i);
emit!(&mut self.output, " mov rax, QWORD [rsp + {}]", offset); emit!(
&mut self.output,
" mov rax, QWORD PTR [rsp + {}]",
offset
);
if arg_type == "f64" { if arg_type == "f64" {
emit!(&mut self.output, " movq xmm{}, rax", fp_idx); emit!(&mut self.output, " movq xmm{}, rax", fp_idx);
fp_idx += 1; fp_idx += 1;
@@ -875,7 +887,7 @@ _builtin_environ:
let offset = 8 * (arg_count - 1 - arg_idx); let offset = 8 * (arg_count - 1 - arg_idx);
emit!( emit!(
&mut self.output, &mut self.output,
" mov rax, QWORD [rsp + {}]", " mov rax, QWORD PTR [rsp + {}]",
offset + 8 * i offset + 8 * i
); );
emit!(&mut self.output, " push rax"); emit!(&mut self.output, " push rax");

View File

@@ -38,8 +38,7 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?; typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?;
} }
let mut codegen = let mut codegen = codegen_x86_64::CodegenX86_64::new(&symbol_table, &typechecker.expr_types);
codegen_x86_64::CodegenX86_64::new(&symbol_table, &typechecker.expr_types, args.emit_debug);
codegen.emit_prologue(args.use_crt)?; codegen.emit_prologue(args.use_crt)?;
for stmt in statements { for stmt in statements {
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?; codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?;
@@ -50,7 +49,9 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
fs::write(format!("{out}.s"), codegen.get_output()).unwrap(); fs::write(format!("{out}.s"), codegen.get_output()).unwrap();
run_command(format!("nasm -f elf64 -o {out}.o {out}.s")); let debug_flag = if args.emit_debug { "-g" } else { "" };
run_command(format!("as --64 {debug_flag} -o {out}.o {out}.s"));
if args.use_crt { if args.use_crt {
run_command(format!( run_command(format!(

View File

@@ -77,10 +77,6 @@ pub enum Stmt {
name: Token, name: Token,
fields: Vec<Param>, fields: Vec<Param>,
}, },
Enum {
name: Token,
variants: Vec<Token>,
},
} }
pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0); pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0);
@@ -195,9 +191,6 @@ impl Parser {
if self.match_token(&[TokenType::KeywordStruct]) { if self.match_token(&[TokenType::KeywordStruct]) {
return self.struct_declaration(); return self.struct_declaration();
} }
if self.match_token(&[TokenType::KeywordEnum]) {
return self.enum_declaration();
}
return error!( return error!(
self.peek().loc, self.peek().loc,
"statements not allowed outside function body" "statements not allowed outside function body"
@@ -281,21 +274,6 @@ impl Parser {
Ok(Stmt::Struct { name, fields }) Ok(Stmt::Struct { name, fields })
} }
fn enum_declaration(&mut self) -> Result<Stmt, ZernError> {
let name = self.consume(TokenType::Identifier, "expected enum name")?;
self.consume(TokenType::Indent, "expected indent after enum name")?;
let mut variants = vec![];
while !self.eof() && !self.check(&TokenType::Dedent) {
variants.push(self.consume(TokenType::Identifier, "expected variant name")?);
}
self.consume(TokenType::Dedent, "expected dedent after enum variants")?;
Ok(Stmt::Enum { name, variants })
}
fn const_declaration(&mut self) -> Result<Stmt, ZernError> { fn const_declaration(&mut self) -> Result<Stmt, ZernError> {
let name = self.consume(TokenType::Identifier, "expected const name")?; let name = self.consume(TokenType::Identifier, "expected const name")?;
self.consume(TokenType::Equal, "expected '=' after const name")?; self.consume(TokenType::Equal, "expected '=' after const name")?;

View File

@@ -75,8 +75,6 @@ impl SymbolTable {
} }
let mut value = if value.lexeme.starts_with("0x") { let mut value = if value.lexeme.starts_with("0x") {
u64::from_str_radix(&value.lexeme[2..], 16).unwrap() u64::from_str_radix(&value.lexeme[2..], 16).unwrap()
} else if value.lexeme.starts_with("0o") {
u64::from_str_radix(&value.lexeme[2..], 8).unwrap()
} else { } else {
value.lexeme.parse().unwrap() value.lexeme.parse().unwrap()
} as i64; } as i64;
@@ -146,16 +144,6 @@ impl SymbolTable {
self.structs.insert(name.lexeme.clone(), fields_map); self.structs.insert(name.lexeme.clone(), fields_map);
} }
Stmt::Enum { name, variants } => {
// TODO: distinct enum types
for (i, v) in variants.iter().enumerate() {
let variant = format!("{}.{}", name.lexeme, v.lexeme);
if self.is_name_defined(&variant) {
return error!(name.loc, format!("tried to redefine '{}'", variant));
}
self.constants.insert(variant, i as i64);
}
}
_ => {} _ => {}
} }
Ok(()) Ok(())

View File

@@ -58,7 +58,6 @@ pub enum TokenType {
KeywordStruct, KeywordStruct,
KeywordNew, KeywordNew,
KeywordAs, KeywordAs,
KeywordEnum,
Indent, Indent,
Dedent, Dedent,
@@ -345,10 +344,6 @@ impl Tokenizer {
while self.peek().is_ascii_hexdigit() { while self.peek().is_ascii_hexdigit() {
self.advance(); self.advance();
} }
} else if self.match_char('o') {
while matches!(self.peek(), '0'..='7') {
self.advance();
}
} else { } else {
while self.peek().is_ascii_digit() { while self.peek().is_ascii_digit() {
self.advance(); self.advance();
@@ -399,7 +394,6 @@ impl Tokenizer {
"struct" => TokenType::KeywordStruct, "struct" => TokenType::KeywordStruct,
"new" => TokenType::KeywordNew, "new" => TokenType::KeywordNew,
"as" => TokenType::KeywordAs, "as" => TokenType::KeywordAs,
"enum" => TokenType::KeywordEnum,
"true" => TokenType::True, "true" => TokenType::True,
"false" => TokenType::False, "false" => TokenType::False,
_ => TokenType::Identifier, _ => TokenType::Identifier,
@@ -412,7 +406,7 @@ impl Tokenizer {
} }
if self.peek() != '"' { if self.peek() != '"' {
return error!(self.loc, "expected '#' after 'include '"); return error!(self.loc, "expected '\"' after 'include '");
} }
self.advance(); self.advance();
@@ -422,7 +416,7 @@ impl Tokenizer {
} }
if self.eof() { if self.eof() {
return error!(self.loc, "unterminated string after 'include'"); return error!(self.loc, "unterminated string after 'include '");
} }
let path: String = self.source[path_start..self.current].iter().collect(); let path: String = self.source[path_start..self.current].iter().collect();

View File

@@ -361,7 +361,6 @@ impl<'a> TypeChecker<'a> {
} }
} }
} }
Stmt::Enum { .. } => {}
} }
Ok(()) Ok(())
} }

View File

@@ -1,28 +1,4 @@
const STDIN = 0 include "std/posix.zr"
const STDOUT = 1
const SIGABRT = 6
const AT_FDCWD = -100
const S_IFDIR = 0o040000
const S_IFMT = 0o170000
const PROT_READ = 1
const PROT_WRITE = 2
const MAP_PRIVATE = 2
const MAP_ANONYMOUS = 32
const O_RDONLY = 0
const O_WRONLY = 1
const O_CREAT = 64
const O_TRUNC = 512
const SEEK_SET = 0
const SEEK_END = 2
const F_OK = 0
const SYS_read = 0 const SYS_read = 0
const SYS_write = 1 const SYS_write = 1

27
std/posix.zr Normal file
View File

@@ -0,0 +1,27 @@
const STDIN_FILENO = 0
const STDOUT_FILENO = 1
const SIGABRT = 6
const AT_FDCWD = -100
const S_IFDIR = 16384
const S_IFMT = 61440
const PROT_READ = 1
const PROT_WRITE = 2
const MAP_PRIVATE = 2
const MAP_ANONYMOUS = 32
const O_RDONLY = 0
const O_WRONLY = 1
const O_CREAT = 64
const O_TRUNC = 512
const SEEK_SET = 0
const SEEK_END = 2
const F_OK = 0
const CLOCK_REALTIME = 0

View File

@@ -1,4 +1,4 @@
include "std/linux_constants.zr" include "std/linux.zr"
func panic[msg: str] : void func panic[msg: str] : void
io.print("PANIC: ") io.print("PANIC: ")
@@ -265,7 +265,7 @@ func io.printf[..] : void
s += 1 s += 1
func io.print_sized[x: ptr, size: i64] : void func io.print_sized[x: ptr, size: i64] : void
_builtin_syscall(SYS_write, STDOUT, x, size) _builtin_syscall(SYS_write, STDOUT_FILENO, x, size)
func io.print[x: str] : void func io.print[x: str] : void
io.print_sized(x as ptr, x->len()) io.print_sized(x as ptr, x->len())
@@ -381,7 +381,7 @@ func f64.to_str_buf[x: i64, buf: ptr] : void
func io.read_char[] : u8 func io.read_char[] : u8
c := 0 as u8 c := 0 as u8
_builtin_syscall(SYS_read, STDIN, ^c, 1) _builtin_syscall(SYS_read, STDIN_FILENO, ^c, 1)
return c return c
func io.read_line[] : str func io.read_line[] : str
@@ -438,7 +438,7 @@ func io.write_file[path: str, content: str] : bool
return io.write_binary_file(path, content as ptr, content->len()) return io.write_binary_file(path, content as ptr, content->len())
func io.write_binary_file[path: str, content: ptr, size: i64] : bool func io.write_binary_file[path: str, content: ptr, size: i64] : bool
fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_WRONLY|O_CREAT|O_TRUNC, 0o644) fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_WRONLY|O_CREAT|O_TRUNC, math.octal_to_decimal(644))
if fd < 0 if fd < 0
return false return false
@@ -901,6 +901,17 @@ func math.pow[b: i64, e: i64] : i64
func math.lcm[a: i64, b: i64] : i64 func math.lcm[a: i64, b: i64] : i64
return (a / math.gcd(a, b)) * b return (a / math.gcd(a, b)) * b
func math.octal_to_decimal[octal: i64] : i64
decimal := 0
base := 1
while octal > 0
digit := octal % 10
decimal += digit * base
base = base * 8
octal = octal / 10
return decimal
struct Blob struct Blob
data: ptr data: ptr
size: i64 size: i64
@@ -1146,6 +1157,12 @@ func os.sleep[ms: i64] : void
req->tv_nsec = (ms % 1000) * 1000000 req->tv_nsec = (ms % 1000) * 1000000
_builtin_syscall(SYS_nanosleep, req, 0) _builtin_syscall(SYS_nanosleep, req, 0)
func os.time[] : i64
ts := new os.Timespec
_builtin_syscall(SYS_clock_gettime, CLOCK_REALTIME, ts)
out := ts->tv_sec * 1000 + ts->tv_nsec / 1000000
return out
func os.urandom_buf[buf: ptr, n: i64] : void func os.urandom_buf[buf: ptr, n: i64] : void
pos := 0 pos := 0
while pos < n while pos < n
@@ -1164,16 +1181,6 @@ func os.urandom_i64[] : i64
os.urandom_buf(^n, 8) os.urandom_buf(^n, 8)
return n return n
struct os.Timeval
tv_sec: i64
tv_usec: i64
func os.time[] : i64
tv := new os.Timeval
_builtin_syscall(SYS_gettimeofday, tv, 0)
out := tv->tv_sec * 1000 + tv->tv_usec / 1000
return out
func os.run_shell_command[command: str] : i64, bool func os.run_shell_command[command: str] : i64, bool
pid := _builtin_syscall(SYS_fork) pid := _builtin_syscall(SYS_fork)
if pid < 0 if pid < 0