include "statement"
This commit is contained in:
@@ -8,7 +8,7 @@ A very cool language
|
|||||||
* No libc required!
|
* No libc required!
|
||||||
* Produces tiny static executables (11KB for `hello.zr`)
|
* 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.
|
* 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
|
## Syntax
|
||||||
```rust
|
```rust
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
include "std/net.zr"
|
||||||
|
|
||||||
func main[argc: i64, argv: ptr] : i64
|
func main[argc: i64, argv: ptr] : i64
|
||||||
if argc < 2
|
if argc < 2
|
||||||
io.println("ERROR: url is missing")
|
io.println("ERROR: url is missing")
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
include "std/net.zr"
|
||||||
|
|
||||||
func main[] : i64
|
func main[] : i64
|
||||||
~s, ok := net.listen("127.0.0.1", 8000)
|
~s, ok := net.listen("127.0.0.1", 8000)
|
||||||
if !ok
|
if !ok
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
include "std/net.zr"
|
||||||
|
|
||||||
func main[] : i64
|
func main[] : i64
|
||||||
~s, ok := net.create_udp_server("127.0.0.1", 8000)
|
~s, ok := net.create_udp_server("127.0.0.1", 8000)
|
||||||
if !ok
|
if !ok
|
||||||
|
|||||||
30
src/main.rs
30
src/main.rs
@@ -12,15 +12,6 @@ use std::{
|
|||||||
|
|
||||||
use tokenizer::ZernError;
|
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> {
|
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,
|
||||||
@@ -32,17 +23,10 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
|
|||||||
|
|
||||||
let filename = Path::new(&args.path).file_name().unwrap().to_str().unwrap();
|
let filename = Path::new(&args.path).file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
let mut statements = Vec::new();
|
let mut tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source);
|
||||||
|
tokenizer.include_file("std/std.zr".into())?;
|
||||||
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 parser = parser::Parser::new(tokenizer.tokenize()?);
|
let parser = parser::Parser::new(tokenizer.tokenize()?);
|
||||||
statements.extend(parser.parse()?);
|
let statements = parser.parse()?;
|
||||||
|
|
||||||
let mut symbol_table = symbol_table::SymbolTable::new();
|
let mut symbol_table = symbol_table::SymbolTable::new();
|
||||||
for stmt in &statements {
|
for stmt in &statements {
|
||||||
@@ -114,7 +98,6 @@ struct Args {
|
|||||||
out: Option<String>,
|
out: Option<String>,
|
||||||
emit_only: bool,
|
emit_only: bool,
|
||||||
emit_debug: bool,
|
emit_debug: bool,
|
||||||
include_stdlib: bool,
|
|
||||||
run_exe: bool,
|
run_exe: bool,
|
||||||
use_crt: bool,
|
use_crt: bool,
|
||||||
cflags: String,
|
cflags: String,
|
||||||
@@ -129,7 +112,6 @@ impl Args {
|
|||||||
out: None,
|
out: None,
|
||||||
emit_only: false,
|
emit_only: false,
|
||||||
emit_debug: false,
|
emit_debug: false,
|
||||||
include_stdlib: true,
|
|
||||||
run_exe: false,
|
run_exe: false,
|
||||||
use_crt: false,
|
use_crt: false,
|
||||||
cflags: String::new(),
|
cflags: String::new(),
|
||||||
@@ -146,8 +128,6 @@ impl Args {
|
|||||||
}
|
}
|
||||||
} else if arg == "--emit-only" {
|
} else if arg == "--emit-only" {
|
||||||
out.emit_only = true;
|
out.emit_only = true;
|
||||||
} else if arg == "--no-stdlib" {
|
|
||||||
out.include_stdlib = false;
|
|
||||||
} else if arg == "-r" {
|
} else if arg == "-r" {
|
||||||
out.run_exe = true;
|
out.run_exe = true;
|
||||||
} else if arg == "-m" {
|
} else if arg == "-m" {
|
||||||
@@ -163,9 +143,7 @@ impl Args {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if arg == "-h" || arg == "--help" {
|
} else if arg == "-h" || arg == "--help" {
|
||||||
println!(
|
println!("Usage: zern [-o path] [-r] [-m] [-g] [-C cflags] [--emit-only] path");
|
||||||
"Usage: zern [-o path] [-r] [-m] [-g] [-C cflags] [--emit-only] [--no-stdlib] path"
|
|
||||||
);
|
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
} else if arg.starts_with('-') {
|
} else if arg.starts_with('-') {
|
||||||
eprintln!("\x1b[91mERROR\x1b[0m: unrecognized option: {arg}");
|
eprintln!("\x1b[91mERROR\x1b[0m: unrecognized option: {arg}");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::{cmp::Ordering, fmt};
|
use std::{cmp::Ordering, fmt, fs, path::Path};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
@@ -378,6 +378,11 @@ impl Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let lexeme: String = self.source[self.start..self.current].iter().collect();
|
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() {
|
self.add_token(match lexeme.as_str() {
|
||||||
"const" => TokenType::KeywordConst,
|
"const" => TokenType::KeywordConst,
|
||||||
"if" => TokenType::KeywordIf,
|
"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 {
|
fn match_char(&mut self, expected: char) -> bool {
|
||||||
if self.eof() || self.peek() != expected {
|
if self.eof() || self.peek() != expected {
|
||||||
false
|
false
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
include "std/linux_constants.zr"
|
||||||
|
|
||||||
func panic[msg: str] : void
|
func panic[msg: str] : void
|
||||||
io.print("PANIC: ")
|
io.print("PANIC: ")
|
||||||
io.println(msg)
|
io.println(msg)
|
||||||
Reference in New Issue
Block a user