This commit is contained in:
2025-06-01 21:48:47 +02:00
parent 437697b287
commit e647e7f508
20 changed files with 167 additions and 147 deletions

View File

@@ -2,6 +2,11 @@
A very cool language A very cool language
## Huh?
* Indentation-based syntax
* Compiled to x86_64 Assembly
* Sometimes works
## Syntax ## Syntax
```go ```go
func fib[n: I64] : I64 func fib[n: I64] : I64

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func main[] : I64 func main[] : I64
let sum: I64 = 0 let sum: I64 = 0

View File

@@ -1,27 +1,9 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func is_prime[n: I64]: I64
if n <= 1
return false
if n == 2 || n == 3
return true
if n % 2 == 0 || n % 3 == 0
return false
let i: I64 = 5
while i * i <= n
if n % i == 0 || n % (i + 2) == 0
return false
i = i + 6
return true
func main[] : I64 func main[] : I64
let sum: I64 = 0 let sum: I64 = 0
let i: I64 = 0 let i: I64 = 0
while i < 2000000 while i < 2000000
if is_prime(i) if Math.is_prime(i)
sum = sum + i sum = sum + i
i = i + 1 i = i + 1
print_i64(sum) print_i64(sum)

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func num_divisors[n: I64] : I64 func num_divisors[n: I64] : I64
let end: I64 = isqrt(n) let end: I64 = isqrt(n)

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func collatz_num[n: I64] : I64 func collatz_num[n: I64] : I64
if n % 2 == 0 if n % 2 == 0
return n / 2 return n / 2

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func main[] : I64 func main[] : I64
let sum: I64 = 0 let sum: I64 = 0
let a: I64 = 0 let a: I64 = 0

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func main[] : I64 func main[] : I64
let n: I64 = 600851475143 let n: I64 = 600851475143
let f: I64 = 2 let f: I64 = 2

View File

@@ -1,11 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func I64.to_string[n: I64] : String
let x: I64 = malloc(21)
sprintf(x, "%ld", n)
return x
func main[] : I64 func main[] : I64
let out: I64 = 0 let out: I64 = 0

View File

@@ -1,21 +1,8 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func gcd[a: I64, b: I64] : I64
while b != 0
let tmp: I64 = b
b = a % b
a = tmp
return a
func lcm[a: I64, b: I64] : I64
return (a * b) / gcd(a, b)
func main[] : I64 func main[] : I64
let out: I64 = 1 let out: I64 = 1
let i: I64 = 1 let i: I64 = 1
while i < 21 while i < 21
out = lcm(out, i) out = Math.lcm(out, i)
i = i + 1 i = i + 1
print_i64(out) print_i64(out)

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func main[] : I64 func main[] : I64
let sum_of_squares: I64 = 0 let sum_of_squares: I64 = 0
let i: I64 = 1 let i: I64 = 1

View File

@@ -1,27 +1,9 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func is_prime[n: I64]: I64
if n <= 1
return false
if n == 2 || n == 3
return true
if n % 2 == 0 || n % 3 == 0
return false
let i: I64 = 5
while i * i <= n
if n % i == 0 || n % (i + 2) == 0
return false
i = i + 6
return true
func main[] : I64 func main[] : I64
let found: I64 = 0 let found: I64 = 0
let i: I64 = 1 let i: I64 = 1
while 1 while 1
if is_prime(i) if Math.is_prime(i)
found = found + 1 found = found + 1
if found == 10001 if found == 10001
print_i64(i) print_i64(i)

View File

@@ -1,9 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func char_to_i64[c: I64]: I64
return c - 48
func main[] : I64 func main[] : I64
let n: String = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450" let n: String = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450"
@@ -14,7 +8,7 @@ func main[] : I64
let s: I64 = 1 let s: I64 = 1
let j: I64 = 0 let j: I64 = 0
while j < 13 while j < 13
s = s * char_to_i64(nth(n, i + j)) s = s * Char.to_i64(nth(n, i + j))
j = j + 1 j = j + 1
if s > out if s > out
out = s out = s

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func main[] : I64 func main[] : I64
let a: I64 = 1 let a: I64 = 1
while a < 1000 while a < 1000

View File

@@ -1,6 +1,3 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func main[] : I64 func main[] : I64
let a: I64 = 0 let a: I64 = 0
let b: I64 = 1 let b: I64 = 1

View File

@@ -1,12 +1,7 @@
func print_i64[x: I64] : I64
printf("%ld\n", x)
func I64.to_string[n: I64] : String
let x: String = malloc(21)
sprintf(x, "%ld", n)
return x
func main[] : I64 func main[] : I64
let s: String = I64.to_string(58394) let a: String = I64.to_string(58394)
print_i64(strlen(s)) print_i64(strlen(a))
free(s) let b: String = concat(a, "test")
print_i64(strlen(b))
free(a)
free(b)

View File

@@ -101,11 +101,14 @@ extern printf
extern sprintf extern sprintf
extern strlen extern strlen
extern strcmp extern strcmp
extern strcat
extern strcpy
extern strdup
extern puts extern puts
extern system extern system
print equ puts extern exit
copystr equ strdup
; generated with clang
strrev: strrev:
push r14 push r14
push rbx push rbx
@@ -118,15 +121,15 @@ strrev:
mov rcx, rax mov rcx, rax
mov rsi, r14 mov rsi, r14
mov rdx, r14 mov rdx, r14
.LBB0_1: .strrev.1:
sub rdx, 1 sub rdx, 1
jb .LBB0_2 jb .strrev.2
mov sil, byte [rbx + rsi - 1] mov sil, byte [rbx + rsi - 1]
mov byte [rcx], sil mov byte [rcx], sil
inc rcx inc rcx
mov rsi, rdx mov rsi, rdx
jmp .LBB0_1 jmp .strrev.1
.LBB0_2: .strrev.2:
mov byte [rax + r14], 0 mov byte [rax + r14], 0
add rsp, 8 add rsp, 8
pop rbx pop rbx
@@ -138,30 +141,30 @@ isqrt:
mov rcx, 1 mov rcx, 1
mov rbx, rdi mov rbx, rdi
shl rcx, 62 shl rcx, 62
.LBB0_3: .isqrt.1:
cmp rcx, 0 cmp rcx, 0
je .LBB0_5 je .isqrt.5
cmp rcx, rbx cmp rcx, rbx
jbe .LBB0_4 jbe .isqrt.2
shr rcx, 2 shr rcx, 2
jmp .LBB0_3 jmp .isqrt.1
.LBB0_4: .isqrt.2:
cmp rcx, 0 cmp rcx, 0
je .LBB0_5 je .isqrt.5
mov rdx, rax mov rdx, rax
add rdx, rcx add rdx, rcx
cmp rbx, rdx cmp rbx, rdx
jb .LBB0_7 jb .isqrt.3
sub rbx, rdx sub rbx, rdx
shr rax, 1 shr rax, 1
add rax, rcx add rax, rcx
jmp .LBB0_6 jmp .isqrt.4
.LBB0_7: .isqrt.3:
shr rax, 1 shr rax, 1
.LBB0_6: .isqrt.4:
shr rcx, 2 shr rcx, 2
jmp .LBB0_4 jmp .isqrt.2
.LBB0_5: .isqrt.5:
ret ret
nth: nth:
@@ -259,10 +262,8 @@ nth:
self.compile_stmt(env, *body)?; self.compile_stmt(env, *body)?;
if name.lexeme == "main" { // TODO: default exit code only for main
// default exit code
emit!(&mut self.output, " mov rax, 0"); emit!(&mut self.output, " mov rax, 0");
}
emit!(&mut self.output, " mov rsp, rbp"); emit!(&mut self.output, " mov rsp, rbp");
emit!(&mut self.output, " pop rbp"); emit!(&mut self.output, " pop rbp");
@@ -356,6 +357,10 @@ nth:
TokenType::String => { TokenType::String => {
// TODO: actual string parsing in the tokenizer // TODO: actual string parsing in the tokenizer
let value = &token.lexeme[1..token.lexeme.len() - 1].replace("\\n", "\n"); let value = &token.lexeme[1..token.lexeme.len() - 1].replace("\\n", "\n");
if value.is_empty() {
emit!(&mut self.data_section, " S{} db 0", self.data_counter);
} else {
let charcodes = value let charcodes = value
.chars() .chars()
.map(|x| (x as u8).to_string()) .map(|x| (x as u8).to_string())
@@ -367,6 +372,7 @@ nth:
self.data_counter, self.data_counter,
charcodes, charcodes,
); );
}
emit!(&mut self.output, " mov rax, S{}", self.data_counter); emit!(&mut self.output, " mov rax, S{}", self.data_counter);
self.data_counter += 1; self.data_counter += 1;
} }

View File

@@ -10,6 +10,23 @@ use std::{
use tokenizer::ZernError; use tokenizer::ZernError;
fn compile_file_to(
codegen: &mut codegen_x86_64::CodegenX86_64,
filename: &str,
source: String,
) -> Result<(), ZernError> {
let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
let tokens = tokenizer.tokenize()?;
let parser = parser::Parser::new(tokens);
let statements = parser.parse()?;
for stmt in statements {
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?;
}
Ok(())
}
fn compile_file(path: String) -> Result<(), ZernError> { fn compile_file(path: String) -> Result<(), ZernError> {
let source = match fs::read_to_string(path.clone()) { let source = match fs::read_to_string(path.clone()) {
Ok(x) => x, Ok(x) => x,
@@ -21,18 +38,10 @@ fn compile_file(path: String) -> Result<(), ZernError> {
let filename = Path::new(&path).file_name().unwrap().to_str().unwrap(); let filename = Path::new(&path).file_name().unwrap().to_str().unwrap();
let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
let tokens = tokenizer.tokenize()?;
let parser = parser::Parser::new(tokens);
let statements = parser.parse()?;
let mut codegen = codegen_x86_64::CodegenX86_64::new(); let mut codegen = codegen_x86_64::CodegenX86_64::new();
codegen.emit_prologue()?; codegen.emit_prologue()?;
for stmt in statements { compile_file_to(&mut codegen, "std.zr", include_str!("std.zr").into())?;
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?; compile_file_to(&mut codegen, filename, source)?;
}
codegen.emit_epilogue()?; codegen.emit_epilogue()?;
if fs::write("out.s", codegen.get_output()).is_err() { if fs::write("out.s", codegen.get_output()).is_err() {

67
src/std.zr Normal file
View File

@@ -0,0 +1,67 @@
func print[x: String] : I64
printf("%s\n", x)
func print_i64[x: I64] : I64
printf("%ld\n", x)
func concat[a: String, b: String] : String
let c: String = malloc(strlen(a) + strlen(b) + 1)
strcpy(c, a)
strcat(c, b)
return c
func Char.to_i64[c: I64]: I64
return c - 48
func I64.to_string[n: I64] : String
let x: I64 = malloc(21)
sprintf(x, "%ld", n)
return x
func Math.gcd[a: I64, b: I64] : I64
while b != 0
let tmp: I64 = b
b = a % b
a = tmp
return a
func Math.min[a: I64, b: I64] : I64
if a < b
return a
return b
func Math.max[a: I64, b: I64] : I64
if a > b
return a
return b
func Math.abs[n: I64] : I64
if n < 0
return -n
return n
func Math.pow[b: I64, e: I64] : I64
let out: I64 = 1
let i: I64 = 0
while i < e
out = out * b
i = i + 1
return out
func Math.lcm[a: I64, b: I64] : I64
return (a * b) / Math.gcd(a, b)
func Math.is_prime[n: I64]: I64
if n <= 1
return false
if n == 2 || n == 3
return true
if n % 2 == 0 || n % 3 == 0
return false
let i: I64 = 5
while i * i <= n
if n % i == 0 || n % (i + 2) == 0
return false
i = i + 6
return true

View File

@@ -220,7 +220,7 @@ impl Tokenizer {
self.handle_indentation()?; self.handle_indentation()?;
} }
'0'..='9' => self.scan_number(), '0'..='9' => self.scan_number(),
'A'..='Z' | 'a'..='z' | '_' => self.scan_identifier(), 'A'..='Z' | 'a'..='z' | '_' | '.' => self.scan_identifier(),
_ => return error!(self.loc, "unexpected character"), _ => return error!(self.loc, "unexpected character"),
} }
Ok(()) Ok(())
@@ -295,7 +295,11 @@ impl Tokenizer {
} }
fn scan_identifier(&mut self) { fn scan_identifier(&mut self) {
while self.peek().is_alphanumeric() || self.peek() == '_' || self.peek() == '.' { while self.peek().is_alphanumeric()
|| self.peek() == '_'
|| self.peek() == '.'
|| self.peek() == '!'
{
self.advance(); self.advance();
} }

21
test.py Normal file
View File

@@ -0,0 +1,21 @@
import os
import sys
import time
os.system("cargo build --release")
for x in os.listdir("examples/"):
print(
"\033[93mBuilding %s...\033[0m" % x,
end="",
flush=True,
)
t = time.time()
if os.system("./target/release/zern examples/" + x) != 0:
sys.exit(1)
print(" %sms" % round((time.time() - t) * 1000, 2))
t = time.time()
if os.system("./out") != 0:
sys.exit(1)
print("\033[93mRunning %s...\033[0m %sms" % (x, round((time.time() - t) * 1000, 2)))