analyze externs and catch undefined function calls

This commit is contained in:
2025-12-19 15:55:31 +01:00
parent fbf28748c7
commit fdcf7eca37
3 changed files with 24 additions and 23 deletions

View File

@@ -6,7 +6,7 @@ use crate::{
}; };
pub struct Analyzer { pub struct Analyzer {
pub functions: HashMap<String, usize>, pub functions: HashMap<String, i32>,
} }
impl Analyzer { impl Analyzer {
@@ -28,7 +28,8 @@ impl Analyzer {
if self.functions.contains_key(&name.lexeme) { if self.functions.contains_key(&name.lexeme) {
return error!(name.loc, format!("tried to redefine '{}'", name.lexeme)); return error!(name.loc, format!("tried to redefine '{}'", name.lexeme));
} }
self.functions.insert(name.lexeme.clone(), params.len()); self.functions
.insert(name.lexeme.clone(), params.len() as i32);
} }
Ok(()) Ok(())
} }
@@ -89,7 +90,12 @@ impl Analyzer {
} }
Stmt::Break => {} Stmt::Break => {}
Stmt::Continue => {} Stmt::Continue => {}
Stmt::Extern(_) => {} Stmt::Extern(name) => {
if self.functions.contains_key(&name.lexeme) {
return error!(name.loc, format!("tried to redefine '{}'", name.lexeme));
}
self.functions.insert(name.lexeme.clone(), -1);
}
} }
Ok(()) Ok(())
} }
@@ -120,14 +126,14 @@ impl Analyzer {
}; };
if let Some(arity) = self.functions.get(&callee) { if let Some(arity) = self.functions.get(&callee) {
if *arity != args.len() { if *arity >= 0 && *arity != args.len() as i32 {
return error!( return error!(
&paren.loc, &paren.loc,
format!("expected {} arguments, got {}", arity, args.len()) format!("expected {} arguments, got {}", arity, args.len())
); );
} }
} else { } else if !callee.starts_with("_builtin_") {
// TODO: cant error here since we dont analyze externs/builtins YET return error!(&paren.loc, format!("undefined function: {}", callee));
} }
for arg in args { for arg in args {

View File

@@ -100,18 +100,6 @@ impl CodegenX86_64 {
"section .note.GNU-stack "section .note.GNU-stack
db 0 db 0
section .text
"
);
for name in &["malloc", "realloc", "free", "gethostbyname"] {
emit!(&mut self.output, "extern {}", name);
emit!(&mut self.output, "c.{} equ {}", name, name);
}
emit!(
&mut self.output,
"
section .text._builtin_read8 section .text._builtin_read8
_builtin_read8: _builtin_read8:
xor rax, rax xor rax, rax

View File

@@ -1,13 +1,18 @@
extern malloc
extern realloc
extern free
extern gethostbyname
func dbg.panic[msg: String] : Void func dbg.panic[msg: String] : Void
io.print("PANIC: ") io.print("PANIC: ")
io.println(msg) io.println(msg)
os.exit(1) os.exit(1)
func mem.alloc[x: I64] : Ptr func mem.alloc[x: I64] : Ptr
return c.malloc(x) return malloc(x)
func mem.free[x: Ptr] : Void func mem.free[x: Ptr] : Void
c.free(x) free(x)
func mem.zero[x: I64, size: I64] : Void func mem.zero[x: I64, size: I64] : Void
for i in 0..size for i in 0..size
@@ -357,9 +362,11 @@ func array.new[] : Array
return arr return arr
func array.nth[xs: Array, n: I64] : I64 func array.nth[xs: Array, n: I64] : I64
// this probably should be implemented in the codegen
if n < 0 | n >= array.size(xs) if n < 0 | n >= array.size(xs)
dbg.panic("array.nth out of bounds") dbg.panic("array.nth out of bounds")
return array.nth_unchecked(xs, n)
func array.nth_unchecked[xs: Array, n: I64] : I64
let data: Ptr = mem.read64(xs) let data: Ptr = mem.read64(xs)
return mem.read64(data + n * 8) return mem.read64(data + n * 8)
@@ -376,7 +383,7 @@ func array.push[xs: Array, x: I64] : Void
let new_capacity: I64 = 4 let new_capacity: I64 = 4
if capacity != 0 if capacity != 0
new_capacity = capacity * 2 new_capacity = capacity * 2
let new_data: Ptr = c.realloc(data, new_capacity * 8) let new_data: Ptr = realloc(data, new_capacity * 8)
mem.write64(xs, new_data) mem.write64(xs, new_data)
mem.write64(xs + 8, new_capacity) mem.write64(xs + 8, new_capacity)
data = new_data data = new_data
@@ -514,7 +521,7 @@ func net.listen[port: I64] : I64
return s return s
func net.connect[host: String, port: I64] : I64 func net.connect[host: String, port: I64] : I64
let he: Ptr = c.gethostbyname(host) let he: Ptr = gethostbyname(host)
if he == 0 if he == 0
return -1 return -1