include "statement"

This commit is contained in:
2026-06-26 14:38:39 +02:00
parent 3f3f161151
commit 5a09699845
9 changed files with 62 additions and 28 deletions

View File

@@ -8,7 +8,7 @@ A very cool language
* No libc required!
* Produces tiny static executables (11KB for `hello.zr`)
* Has type inference, [UFCS](https://en.wikipedia.org/wiki/Uniform_function_call_syntax), variadics, dynamic arrays, hashmaps, DNS resolver, etc.
* Growing [standard library](https://git.ton1.dev/toni/zern/src/branch/main/src/std)
* Growing [standard library](https://git.ton1.dev/toni/zern/src/branch/main/std)
## Syntax
```rust

View File

@@ -1,3 +1,5 @@
include "std/net.zr"
func main[argc: i64, argv: ptr] : i64
if argc < 2
io.println("ERROR: url is missing")

View File

@@ -1,3 +1,5 @@
include "std/net.zr"
func main[] : i64
~s, ok := net.listen("127.0.0.1", 8000)
if !ok

View File

@@ -1,3 +1,5 @@
include "std/net.zr"
func main[] : i64
~s, ok := net.create_udp_server("127.0.0.1", 8000)
if !ok

View File

@@ -12,15 +12,6 @@ use std::{
use tokenizer::ZernError;
macro_rules! parse_std_file {
($statements:expr, $filename:expr) => {
let source: String = include_str!($filename).into();
let tokenizer = tokenizer::Tokenizer::new($filename.to_owned(), source);
let parser = parser::Parser::new(tokenizer.tokenize()?);
$statements.extend(parser.parse()?);
};
}
fn compile_file(args: Args) -> Result<(), ZernError> {
let source = match fs::read_to_string(&args.path) {
Ok(x) => x,
@@ -32,17 +23,10 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
let filename = Path::new(&args.path).file_name().unwrap().to_str().unwrap();
let mut statements = Vec::new();
if args.include_stdlib {
parse_std_file!(statements, "std/std.zr");
parse_std_file!(statements, "std/net.zr");
parse_std_file!(statements, "std/linux_constants.zr");
}
let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
let mut tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
tokenizer.include_file("std/std.zr".into())?;
let parser = parser::Parser::new(tokenizer.tokenize()?);
statements.extend(parser.parse()?);
let statements = parser.parse()?;
let mut symbol_table = symbol_table::SymbolTable::new();
for stmt in &statements {
@@ -114,7 +98,6 @@ struct Args {
out: Option<String>,
emit_only: bool,
emit_debug: bool,
include_stdlib: bool,
run_exe: bool,
use_crt: bool,
cflags: String,
@@ -129,7 +112,6 @@ impl Args {
out: None,
emit_only: false,
emit_debug: false,
include_stdlib: true,
run_exe: false,
use_crt: false,
cflags: String::new(),
@@ -146,8 +128,6 @@ impl Args {
}
} else if arg == "--emit-only" {
out.emit_only = true;
} else if arg == "--no-stdlib" {
out.include_stdlib = false;
} else if arg == "-r" {
out.run_exe = true;
} else if arg == "-m" {
@@ -163,9 +143,7 @@ impl Args {
}
}
} else if arg == "-h" || arg == "--help" {
println!(
"Usage: zern [-o path] [-r] [-m] [-g] [-C cflags] [--emit-only] [--no-stdlib] path"
);
println!("Usage: zern [-o path] [-r] [-m] [-g] [-C cflags] [--emit-only] path");
process::exit(0);
} else if arg.starts_with('-') {
eprintln!("\x1b[91mERROR\x1b[0m: unrecognized option: {arg}");

View File

@@ -1,4 +1,4 @@
use std::{cmp::Ordering, fmt};
use std::{cmp::Ordering, fmt, fs, path::Path};
#[derive(Debug, Clone, PartialEq)]
pub enum TokenType {
@@ -378,6 +378,11 @@ impl Tokenizer {
}
let lexeme: String = self.source[self.start..self.current].iter().collect();
if lexeme == "include" {
return self.scan_include();
}
self.add_token(match lexeme.as_str() {
"const" => TokenType::KeywordConst,
"if" => TokenType::KeywordIf,
@@ -401,6 +406,49 @@ impl Tokenizer {
})
}
fn scan_include(&mut self) -> Result<(), ZernError> {
if !self.match_char(' ') {
return error!(self.loc, "expected a space after 'include'");
}
if self.peek() != '"' {
return error!(self.loc, "expected '#' after 'include '");
}
self.advance();
let path_start = self.current;
while !self.eof() && self.peek() != '"' {
self.advance();
}
if self.eof() {
return error!(self.loc, "unterminated string after 'include'");
}
let path: String = self.source[path_start..self.current].iter().collect();
self.advance(); // consume closing quote
self.include_file(path)
}
// TODO: circular includes lead to "fatal runtime error: stack overflow, aborting"
pub fn include_file(&mut self, path: String) -> Result<(), ZernError> {
let source = match fs::read_to_string(&path) {
Ok(x) => x,
Err(_) => {
return error!(self.loc, format!("failed to include {}", path));
}
};
let filename = Path::new(&path).file_name().unwrap().to_str().unwrap();
let tokenizer = Tokenizer::new(filename.to_owned(), source);
self.tokens.extend(tokenizer.tokenize()?);
self.tokens.pop(); // remove inner Eof
Ok(())
}
fn match_char(&mut self, expected: char) -> bool {
if self.eof() || self.peek() != expected {
false

View File

@@ -1,3 +1,5 @@
include "std/linux_constants.zr"
func panic[msg: str] : void
io.print("PANIC: ")
io.println(msg)