drop gcc by default, any type
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
/out*
|
/out*
|
||||||
/TODO
|
/TODO
|
||||||
/musl-*
|
|
||||||
/vscode
|
/vscode
|
||||||
|
|||||||
@@ -6,9 +6,8 @@ A very cool language
|
|||||||
* Clean indentation-based syntax
|
* Clean indentation-based syntax
|
||||||
* Compiles to x86_64 Assembly
|
* Compiles to x86_64 Assembly
|
||||||
* Growing [standard library](https://github.com/antpiasecki/zern/tree/main/src/std)
|
* Growing [standard library](https://github.com/antpiasecki/zern/tree/main/src/std)
|
||||||
* Produces tiny static executables (~30KB with musl)
|
* Produces tiny static executables (11KB for `hello.zr`)
|
||||||
* No libc required!
|
* No libc required!
|
||||||
* Sometimes works
|
|
||||||
* Has the pipe operator
|
* Has the pipe operator
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ macro_rules! emit {
|
|||||||
static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
|
||||||
// TODO: currently they are all just 64 bit values
|
// TODO: currently they are all just 64 bit values
|
||||||
static BUILTIN_TYPES: [&str; 6] = ["void", "u8", "i64", "str", "bool", "ptr"];
|
static BUILTIN_TYPES: [&str; 7] = ["void", "u8", "i64", "str", "bool", "ptr", "any"];
|
||||||
|
|
||||||
pub struct CodegenX86_64<'a> {
|
pub struct CodegenX86_64<'a> {
|
||||||
output: String,
|
output: String,
|
||||||
@@ -100,7 +100,7 @@ impl<'a> CodegenX86_64<'a> {
|
|||||||
format!("section .data\n{}{}", self.data_section, self.output)
|
format!("section .data\n{}{}", self.data_section, self.output)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_prologue(&mut self) -> Result<(), ZernError> {
|
pub fn emit_prologue(&mut self, emit_start: bool) -> Result<(), ZernError> {
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
"section .note.GNU-stack
|
"section .note.GNU-stack
|
||||||
@@ -109,6 +109,7 @@ impl<'a> CodegenX86_64<'a> {
|
|||||||
section .bss
|
section .bss
|
||||||
_heap_head: resq 1
|
_heap_head: resq 1
|
||||||
_heap_tail: resq 1
|
_heap_tail: resq 1
|
||||||
|
_environ: resq 1
|
||||||
|
|
||||||
section .text._builtin_heap_head
|
section .text._builtin_heap_head
|
||||||
_builtin_heap_head:
|
_builtin_heap_head:
|
||||||
@@ -141,14 +142,52 @@ _builtin_syscall:
|
|||||||
mov r9, [rsp+8]
|
mov r9, [rsp+8]
|
||||||
syscall
|
syscall
|
||||||
ret
|
ret
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
if emit_start {
|
||||||
|
emit!(
|
||||||
|
&mut self.output,
|
||||||
|
"
|
||||||
|
section .text._builtin_environ
|
||||||
|
_builtin_environ:
|
||||||
|
lea rax, [rel _environ]
|
||||||
|
mov rax, [rax]
|
||||||
|
ret
|
||||||
|
|
||||||
|
global _start
|
||||||
|
section .text
|
||||||
|
_start:
|
||||||
|
xor rbp, rbp
|
||||||
|
; setup args
|
||||||
|
pop rdi
|
||||||
|
mov rsi, rsp
|
||||||
|
; save environ
|
||||||
|
lea rdx, [rsi + rdi*8 + 8]
|
||||||
|
lea rax, [rel _environ]
|
||||||
|
mov [rax], rdx
|
||||||
|
; align stack
|
||||||
|
and rsp, -16
|
||||||
|
; main()
|
||||||
|
call main
|
||||||
|
; exit
|
||||||
|
mov rdi, rax
|
||||||
|
mov rax, 60
|
||||||
|
syscall
|
||||||
|
"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
emit!(
|
||||||
|
&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, [rel environ]
|
||||||
ret
|
ret
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
src/main.rs
12
src/main.rs
@@ -63,7 +63,7 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
|
|||||||
|
|
||||||
let mut analyzer = analyzer::Analyzer::new();
|
let mut analyzer = analyzer::Analyzer::new();
|
||||||
let mut codegen = codegen_x86_64::CodegenX86_64::new(&mut analyzer);
|
let mut codegen = codegen_x86_64::CodegenX86_64::new(&mut analyzer);
|
||||||
codegen.emit_prologue()?;
|
codegen.emit_prologue(!args.use_gcc)?;
|
||||||
compile_file_to(
|
compile_file_to(
|
||||||
&mut codegen,
|
&mut codegen,
|
||||||
"syscalls.zr",
|
"syscalls.zr",
|
||||||
@@ -82,15 +82,15 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
|
|||||||
|
|
||||||
run_command(format!("nasm -f elf64 -o {}.o {}.s", args.out, args.out));
|
run_command(format!("nasm -f elf64 -o {}.o {}.s", args.out, args.out));
|
||||||
|
|
||||||
if args.use_glibc {
|
if args.use_gcc {
|
||||||
run_command(format!(
|
run_command(format!(
|
||||||
"gcc -no-pie -o {} {}.o -flto -Wl,--gc-sections {}",
|
"gcc -no-pie -o {} {}.o -flto -Wl,--gc-sections {}",
|
||||||
args.out, args.out, args.cflags
|
args.out, args.out, args.cflags
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
run_command(format!(
|
run_command(format!(
|
||||||
"musl-gcc -static -o {} {}.o -flto -Wl,--gc-sections {}",
|
"ld -static -o {} {}.o --gc-sections -e _start",
|
||||||
args.out, args.out, args.cflags
|
args.out, args.out
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +123,8 @@ struct Args {
|
|||||||
#[arg(short = 'r', help = "Run the compiled executable")]
|
#[arg(short = 'r', help = "Run the compiled executable")]
|
||||||
run_exe: bool,
|
run_exe: bool,
|
||||||
|
|
||||||
#[arg(short = 'm', help = "Use glibc instead of musl")]
|
#[arg(short = 'm', help = "Use gcc")]
|
||||||
use_glibc: bool,
|
use_gcc: bool,
|
||||||
|
|
||||||
#[arg(short = 'C', default_value = "", help = "Extra flags to pass to gcc")]
|
#[arg(short = 'C', default_value = "", help = "Extra flags to pass to gcc")]
|
||||||
cflags: String,
|
cflags: String,
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ func io.read_line[]: str
|
|||||||
func io.read_file[path: str] : str
|
func io.read_file[path: str] : str
|
||||||
let fd: i64 = _builtin_syscall(SYS_openat, -100, path, 0, 0)
|
let fd: i64 = _builtin_syscall(SYS_openat, -100, path, 0, 0)
|
||||||
if fd <= 0
|
if fd <= 0
|
||||||
panic("failed to open file")
|
panic("failed to open file") // TODO
|
||||||
|
|
||||||
let size: i64 = _builtin_syscall(SYS_lseek, fd, 0, 2)
|
let size: i64 = _builtin_syscall(SYS_lseek, fd, 0, 2)
|
||||||
_builtin_syscall(SYS_lseek, fd, 0, 0)
|
_builtin_syscall(SYS_lseek, fd, 0, 0)
|
||||||
@@ -246,7 +246,7 @@ struct io.Buffer
|
|||||||
func io.read_binary_file[path: str] : io.Buffer
|
func io.read_binary_file[path: str] : io.Buffer
|
||||||
let fd: i64 = _builtin_syscall(SYS_openat, -100, path, 0, 0)
|
let fd: i64 = _builtin_syscall(SYS_openat, -100, path, 0, 0)
|
||||||
if fd < 0
|
if fd < 0
|
||||||
panic("failed to open file")
|
panic("failed to open file") // TODO
|
||||||
|
|
||||||
let buffer: io.Buffer = new io.Buffer
|
let buffer: io.Buffer = new io.Buffer
|
||||||
buffer->size = _builtin_syscall(SYS_lseek, fd, 0, 2)
|
buffer->size = _builtin_syscall(SYS_lseek, fd, 0, 2)
|
||||||
@@ -260,7 +260,7 @@ func io.read_binary_file[path: str] : io.Buffer
|
|||||||
func io.write_file[path: str, content: str] : void
|
func io.write_file[path: str, content: str] : void
|
||||||
let fd: ptr = _builtin_syscall(SYS_openat, -100, path, 0x241, 0o644)
|
let fd: ptr = _builtin_syscall(SYS_openat, -100, path, 0x241, 0o644)
|
||||||
if fd < 0
|
if fd < 0
|
||||||
panic("failed to open file")
|
panic("failed to open file") // TODO
|
||||||
|
|
||||||
_builtin_syscall(SYS_write, fd, content, str.len(content))
|
_builtin_syscall(SYS_write, fd, content, str.len(content))
|
||||||
_builtin_syscall(SYS_close, fd)
|
_builtin_syscall(SYS_close, fd)
|
||||||
@@ -402,7 +402,7 @@ func str.reverse[s: str] : str
|
|||||||
out[len] = 0
|
out[len] = 0
|
||||||
return out
|
return out
|
||||||
|
|
||||||
// not sure this covers all wacky edge cases
|
// not sure this covers all the wacky edge cases
|
||||||
func str.from_i64[n: i64] : str
|
func str.from_i64[n: i64] : str
|
||||||
if n == 0
|
if n == 0
|
||||||
return str.copy("0")
|
return str.copy("0")
|
||||||
@@ -588,17 +588,17 @@ struct Array
|
|||||||
func array.new[] : Array
|
func array.new[] : Array
|
||||||
return new Array
|
return new Array
|
||||||
|
|
||||||
func array.nth[xs: Array, n: i64] : i64
|
func array.nth[xs: Array, n: i64] : any
|
||||||
if n < 0 || n >= xs->size
|
if n < 0 || n >= xs->size
|
||||||
panic("array.nth out of bounds")
|
panic("array.nth out of bounds")
|
||||||
return mem.read64(xs->data + n * 8)
|
return mem.read64(xs->data + n * 8)
|
||||||
|
|
||||||
func array.set[xs: Array, n: i64, x: i64] : void
|
func array.set[xs: Array, n: i64, x: any] : void
|
||||||
if n < 0 || n >= xs->size
|
if n < 0 || n >= xs->size
|
||||||
panic("array.set out of bounds")
|
panic("array.set out of bounds")
|
||||||
mem.write64(xs->data + n * 8, x)
|
mem.write64(xs->data + n * 8, x)
|
||||||
|
|
||||||
func array.push[xs: Array, x: i64] : void
|
func array.push[xs: Array, x: any] : void
|
||||||
if xs->size == xs->capacity
|
if xs->size == xs->capacity
|
||||||
let new_capacity = 4
|
let new_capacity = 4
|
||||||
if xs->capacity != 0
|
if xs->capacity != 0
|
||||||
@@ -614,10 +614,10 @@ func array.free[xs: Array] : void
|
|||||||
mem.free(xs->data)
|
mem.free(xs->data)
|
||||||
mem.free(xs)
|
mem.free(xs)
|
||||||
|
|
||||||
func array.pop[xs: Array] : i64
|
func array.pop[xs: Array] : any
|
||||||
if xs->size == 0
|
if xs->size == 0
|
||||||
panic("array.pop on empty array")
|
panic("array.pop on empty array")
|
||||||
let x: i64 = array.nth(xs, xs->size - 1)
|
let x: any = array.nth(xs, xs->size - 1)
|
||||||
xs->size = xs->size - 1
|
xs->size = xs->size - 1
|
||||||
return x
|
return x
|
||||||
|
|
||||||
@@ -661,7 +661,7 @@ func alg._partition[arr: Array, low: i64, high: i64] : i64
|
|||||||
array.set(arr, high, temp)
|
array.set(arr, high, temp)
|
||||||
return i + 1
|
return i + 1
|
||||||
|
|
||||||
func alg.count[arr: Array, item: i64] : i64
|
func alg.count[arr: Array, item: any] : i64
|
||||||
let count = 0
|
let count = 0
|
||||||
for i in 0..arr->size
|
for i in 0..arr->size
|
||||||
if array.nth(arr, i) == item
|
if array.nth(arr, i) == item
|
||||||
@@ -681,7 +681,7 @@ func alg.filter[arr: Array, fn: ptr] : Array
|
|||||||
array.push(out, array.nth(arr, i))
|
array.push(out, array.nth(arr, i))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
func alg.reduce[arr: Array, fn: ptr, acc: i64] : i64
|
func alg.reduce[arr: Array, fn: ptr, acc: any] : any
|
||||||
for i in 0..arr->size
|
for i in 0..arr->size
|
||||||
acc = fn(acc, array.nth(arr, i))
|
acc = fn(acc, array.nth(arr, i))
|
||||||
return acc
|
return acc
|
||||||
@@ -709,15 +709,15 @@ struct os.Timeval
|
|||||||
func os.time[] : i64
|
func os.time[] : i64
|
||||||
let tv: os.Timeval = new os.Timeval
|
let tv: os.Timeval = new os.Timeval
|
||||||
_builtin_syscall(SYS_gettimeofday, tv, 0)
|
_builtin_syscall(SYS_gettimeofday, tv, 0)
|
||||||
|
let out: i64 = tv->tv_sec * 1000 + tv->tv_usec / 1000
|
||||||
mem.free(tv)
|
mem.free(tv)
|
||||||
return tv->tv_sec * 1000 + tv->tv_usec / 1000
|
return out
|
||||||
|
|
||||||
// voodoo magic
|
// voodoo magic
|
||||||
func os.shell[command: str] : i64
|
func os.shell[command: str] : i64
|
||||||
let pid: i64 = _builtin_syscall(SYS_fork)
|
let pid: i64 = _builtin_syscall(SYS_fork)
|
||||||
if pid == 0
|
if pid == 0
|
||||||
// leaky but not sure where can i free it
|
let argv: Array = ["sh", "-c", command, 0] // gets freed after child process exits
|
||||||
let argv: Array = ["sh", "-c", command, 0]
|
|
||||||
_builtin_syscall(SYS_execve, "/bin/sh", argv->data, _builtin_environ())
|
_builtin_syscall(SYS_execve, "/bin/sh", argv->data, _builtin_environ())
|
||||||
_builtin_syscall(SYS_exit, 1)
|
_builtin_syscall(SYS_exit, 1)
|
||||||
else
|
else
|
||||||
@@ -799,6 +799,7 @@ func net.listen[packed_host: i64, port: i64] : i64
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
// TODO: resolve DNS
|
||||||
func net.connect[packed_host: i64, port: i64] : i64
|
func net.connect[packed_host: i64, port: i64] : i64
|
||||||
let s: i64 = _builtin_syscall(SYS_socket, 2, 1, 0)
|
let s: i64 = _builtin_syscall(SYS_socket, 2, 1, 0)
|
||||||
if s < 0
|
if s < 0
|
||||||
|
|||||||
Reference in New Issue
Block a user