typecheck return types
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
func main[] : i64
|
func main[] : i64
|
||||||
let s: net.UDPSocket = must(net.udp_listen?(net.pack_addr(127, 0, 0, 1), 8000))
|
let s: net.UDPSocket = must(net.create_udp_server?(net.pack_addr(127, 0, 0, 1), 8000))
|
||||||
|
|
||||||
io.println("Listening on port 8000...")
|
io.println("Listening on port 8000...")
|
||||||
while true
|
while true
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ impl Analyzer {
|
|||||||
("_builtin_read64".into(), FnType::new("i64", vec!["ptr"])),
|
("_builtin_read64".into(), FnType::new("i64", vec!["ptr"])),
|
||||||
(
|
(
|
||||||
"_builtin_set64".into(),
|
"_builtin_set64".into(),
|
||||||
FnType::new("void", vec!["ptr", "any"]),
|
FnType::new("void", vec!["ptr", "i64"]),
|
||||||
),
|
),
|
||||||
("_builtin_syscall".into(), FnType::new_variadic("any")),
|
("_builtin_syscall".into(), FnType::new_variadic("i64")),
|
||||||
("io.printf".into(), FnType::new_variadic("void")),
|
("io.printf".into(), FnType::new_variadic("void")),
|
||||||
("_builtin_environ".into(), FnType::new("ptr", vec![])),
|
("_builtin_environ".into(), FnType::new("ptr", vec![])),
|
||||||
]),
|
]),
|
||||||
@@ -145,7 +145,7 @@ impl Analyzer {
|
|||||||
|
|
||||||
self.analyze_stmt(body)?;
|
self.analyze_stmt(body)?;
|
||||||
}
|
}
|
||||||
Stmt::Return(expr) => {
|
Stmt::Return { expr, keyword: _ } => {
|
||||||
self.analyze_expr(expr)?;
|
self.analyze_expr(expr)?;
|
||||||
}
|
}
|
||||||
Stmt::For {
|
Stmt::For {
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " ret");
|
emit!(&mut self.output, " ret");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::Return(expr) => {
|
Stmt::Return { expr, keyword: _ } => {
|
||||||
self.compile_expr(env, expr)?;
|
self.compile_expr(env, expr)?;
|
||||||
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");
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ pub enum Stmt {
|
|||||||
body: Box<Stmt>,
|
body: Box<Stmt>,
|
||||||
exported: bool,
|
exported: bool,
|
||||||
},
|
},
|
||||||
Return(Expr),
|
Return {
|
||||||
|
expr: Expr,
|
||||||
|
keyword: Token,
|
||||||
|
},
|
||||||
Break,
|
Break,
|
||||||
Continue,
|
Continue,
|
||||||
Extern(Token),
|
Extern(Token),
|
||||||
@@ -262,7 +265,11 @@ impl Parser {
|
|||||||
} else if self.match_token(&[TokenType::KeywordFor]) {
|
} else if self.match_token(&[TokenType::KeywordFor]) {
|
||||||
self.for_statement()
|
self.for_statement()
|
||||||
} else if self.match_token(&[TokenType::KeywordReturn]) {
|
} else if self.match_token(&[TokenType::KeywordReturn]) {
|
||||||
Ok(Stmt::Return(self.expression()?))
|
let keyword = self.previous().clone();
|
||||||
|
Ok(Stmt::Return {
|
||||||
|
expr: self.expression()?,
|
||||||
|
keyword,
|
||||||
|
})
|
||||||
} else if self.match_token(&[TokenType::KeywordBreak]) {
|
} else if self.match_token(&[TokenType::KeywordBreak]) {
|
||||||
Ok(Stmt::Break)
|
Ok(Stmt::Break)
|
||||||
} else if self.match_token(&[TokenType::KeywordContinue]) {
|
} else if self.match_token(&[TokenType::KeywordContinue]) {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func net.close[s: i64] : void
|
|||||||
_builtin_syscall(SYS_close, s)
|
_builtin_syscall(SYS_close, s)
|
||||||
|
|
||||||
func net.pack_addr[a: u8, b: u8, c: u8, d: u8] : i64
|
func net.pack_addr[a: u8, b: u8, c: u8, d: u8] : i64
|
||||||
return (a << 24) | (b << 16) | (c << 8) | d
|
return (a as i64 << 24) | (b << 16) | (c << 8) | d
|
||||||
|
|
||||||
struct net.UDPSocket
|
struct net.UDPSocket
|
||||||
fd: i64
|
fd: i64
|
||||||
@@ -101,7 +101,7 @@ func net.create_udp_client?[packed_host: i64, port: i64] : net.UDPSocket
|
|||||||
if s->fd < 0
|
if s->fd < 0
|
||||||
mem.free(s)
|
mem.free(s)
|
||||||
err.set(ERR_SYSCALL_FAILED, "net.create_udp_client?: failed to create a socket")
|
err.set(ERR_SYSCALL_FAILED, "net.create_udp_client?: failed to create a socket")
|
||||||
return 0
|
return 0 as net.UDPSocket
|
||||||
|
|
||||||
s->addr = mem.alloc(16)
|
s->addr = mem.alloc(16)
|
||||||
mem.zero(s->addr, 16)
|
mem.zero(s->addr, 16)
|
||||||
@@ -115,16 +115,16 @@ func net.create_udp_client?[packed_host: i64, port: i64] : net.UDPSocket
|
|||||||
s->addr[7] = packed_host & 255
|
s->addr[7] = packed_host & 255
|
||||||
return s
|
return s
|
||||||
|
|
||||||
func net.udp_listen?[packed_host: i64, port: i64] : net.UDPSocket
|
func net.create_udp_server?[packed_host: i64, port: i64] : net.UDPSocket
|
||||||
err.clear()
|
err.clear()
|
||||||
let s: net.UDPSocket = net.create_udp_client?(packed_host, port)
|
let s: net.UDPSocket = net.create_udp_client?(packed_host, port)
|
||||||
if err.check()
|
if err.check()
|
||||||
return 0
|
return 0 as net.UDPSocket
|
||||||
|
|
||||||
if _builtin_syscall(SYS_bind, s->fd, s->addr, 16) < 0
|
if _builtin_syscall(SYS_bind, s->fd, s->addr, 16) < 0
|
||||||
net.UDPSocket.close_and_free(s)
|
net.UDPSocket.close_and_free(s)
|
||||||
err.set(ERR_SYSCALL_FAILED, "net.udp_listen?: failed to bind")
|
err.set(ERR_SYSCALL_FAILED, "net.create_udp_server?: failed to bind")
|
||||||
return 0
|
return 0 as net.UDPSocket
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ func err.code[] : i64
|
|||||||
return mem.read64(_builtin_err_code())
|
return mem.read64(_builtin_err_code())
|
||||||
|
|
||||||
func err.msg[] : str
|
func err.msg[] : str
|
||||||
return mem.read64(_builtin_err_msg())
|
return mem.read64(_builtin_err_msg()) as str
|
||||||
|
|
||||||
func err.check[] : bool
|
func err.check[] : bool
|
||||||
return err.code() != 0
|
return err.code() != 0
|
||||||
@@ -73,7 +73,7 @@ func mem._request_space?[size: i64] : mem.Block
|
|||||||
let blk_ptr: ptr = _builtin_syscall(SYS_mmap, 0, alloc_size, 3, 34, -1, 0) as ptr
|
let blk_ptr: ptr = _builtin_syscall(SYS_mmap, 0, alloc_size, 3, 34, -1, 0) as ptr
|
||||||
if blk_ptr == -1
|
if blk_ptr == -1
|
||||||
err.set(ERR_ALLOC_FAILED, "mem._request_space: mmap failed")
|
err.set(ERR_ALLOC_FAILED, "mem._request_space: mmap failed")
|
||||||
return 0
|
return 0 as mem.Block
|
||||||
|
|
||||||
let blk: mem.Block = blk_ptr as mem.Block
|
let blk: mem.Block = blk_ptr as mem.Block
|
||||||
|
|
||||||
@@ -173,11 +173,11 @@ func mem.realloc?[x: ptr, new_size: i64] : ptr
|
|||||||
|
|
||||||
if new_size < 0
|
if new_size < 0
|
||||||
err.set(ERR_ALLOC_FAILED, "mem.realloc? called with negative size")
|
err.set(ERR_ALLOC_FAILED, "mem.realloc? called with negative size")
|
||||||
return 0
|
return 0 as ptr
|
||||||
|
|
||||||
if new_size == 0
|
if new_size == 0
|
||||||
mem.free(x)
|
mem.free(x)
|
||||||
return 0
|
return 0 as ptr
|
||||||
|
|
||||||
new_size = mem._align(new_size)
|
new_size = mem._align(new_size)
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ func mem.realloc?[x: ptr, new_size: i64] : ptr
|
|||||||
|
|
||||||
let new_ptr: ptr = mem.alloc?(new_size)
|
let new_ptr: ptr = mem.alloc?(new_size)
|
||||||
if err.check()
|
if err.check()
|
||||||
return 0
|
return 0 as ptr
|
||||||
|
|
||||||
mem.copy(x, new_ptr, math.min(blk->size, new_size))
|
mem.copy(x, new_ptr, math.min(blk->size, new_size))
|
||||||
mem.free(x)
|
mem.free(x)
|
||||||
@@ -232,16 +232,16 @@ func mem.read8[x: ptr] : u8
|
|||||||
return x[0]
|
return x[0]
|
||||||
|
|
||||||
func mem.read16[x: ptr] : i64
|
func mem.read16[x: ptr] : i64
|
||||||
return x[0] | (x[1] << 8)
|
return x[0] as i64 | (x[1] << 8)
|
||||||
|
|
||||||
func mem.read16be[x: ptr] : i64
|
func mem.read16be[x: ptr] : i64
|
||||||
return (x[0] << 8) | x[1]
|
return (x[0] << 8) as i64 | x[1]
|
||||||
|
|
||||||
func mem.read32[x: ptr] : i64
|
func mem.read32[x: ptr] : i64
|
||||||
return x[0] | (x[1] << 8) | (x[2] << 16) | (x[3] << 24)
|
return x[0] as i64 | (x[1] << 8) | (x[2] << 16) | (x[3] << 24)
|
||||||
|
|
||||||
func mem.read32be[x: ptr] : i64
|
func mem.read32be[x: ptr] : i64
|
||||||
return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]
|
return (x[0] as i64 << 24) | (x[1] << 16) | (x[2] << 8) | x[3]
|
||||||
|
|
||||||
func mem.read64[x: ptr] : i64
|
func mem.read64[x: ptr] : i64
|
||||||
return _builtin_read64(x)
|
return _builtin_read64(x)
|
||||||
@@ -349,7 +349,7 @@ func io.Buffer.alloc?[size: i64] : io.Buffer
|
|||||||
buffer->data = mem.alloc?(size)
|
buffer->data = mem.alloc?(size)
|
||||||
if err.check()
|
if err.check()
|
||||||
mem.free(buffer)
|
mem.free(buffer)
|
||||||
return 0
|
return 0 as io.Buffer
|
||||||
return buffer
|
return buffer
|
||||||
|
|
||||||
func io.Buffer.free[buf: io.Buffer] : void
|
func io.Buffer.free[buf: io.Buffer] : void
|
||||||
@@ -364,7 +364,7 @@ func io.read_text_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
|
||||||
err.set(ERR_OPEN_FAILED, "io.read_text_file?: failed to open file")
|
err.set(ERR_OPEN_FAILED, "io.read_text_file?: failed to open file")
|
||||||
return 0
|
return 0 as str
|
||||||
|
|
||||||
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)
|
||||||
@@ -372,7 +372,7 @@ func io.read_text_file?[path: str] : str
|
|||||||
let buffer: str = mem.alloc?(size + 1) as str
|
let buffer: str = mem.alloc?(size + 1) as str
|
||||||
if err.check()
|
if err.check()
|
||||||
_builtin_syscall(SYS_close, fd)
|
_builtin_syscall(SYS_close, fd)
|
||||||
return 0
|
return 0 as str
|
||||||
|
|
||||||
let n: i64 = _builtin_syscall(SYS_read, fd, buffer, size)
|
let n: i64 = _builtin_syscall(SYS_read, fd, buffer, size)
|
||||||
_builtin_syscall(SYS_close, fd)
|
_builtin_syscall(SYS_close, fd)
|
||||||
@@ -380,7 +380,7 @@ func io.read_text_file?[path: str] : str
|
|||||||
if n != size
|
if n != size
|
||||||
mem.free(buffer)
|
mem.free(buffer)
|
||||||
err.set(ERR_READ_FAILED, "io.read_text_file?: failed to read file")
|
err.set(ERR_READ_FAILED, "io.read_text_file?: failed to read file")
|
||||||
return 0
|
return 0 as str
|
||||||
|
|
||||||
buffer[n] = 0
|
buffer[n] = 0
|
||||||
return buffer
|
return buffer
|
||||||
@@ -390,7 +390,7 @@ 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
|
||||||
err.set(ERR_OPEN_FAILED, "io.read_binary_file?: failed to open file")
|
err.set(ERR_OPEN_FAILED, "io.read_binary_file?: failed to open file")
|
||||||
return 0
|
return 0 as io.Buffer
|
||||||
|
|
||||||
let buf: io.Buffer = new io.Buffer
|
let buf: io.Buffer = new io.Buffer
|
||||||
buf->size = _builtin_syscall(SYS_lseek, fd, 0, 2)
|
buf->size = _builtin_syscall(SYS_lseek, fd, 0, 2)
|
||||||
@@ -400,7 +400,7 @@ func io.read_binary_file?[path: str] : io.Buffer
|
|||||||
if err.check()
|
if err.check()
|
||||||
io.Buffer.free(buf)
|
io.Buffer.free(buf)
|
||||||
_builtin_syscall(SYS_close, fd)
|
_builtin_syscall(SYS_close, fd)
|
||||||
return 0
|
return 0 as io.Buffer
|
||||||
|
|
||||||
let n: i64 = _builtin_syscall(SYS_read, fd, buf->data, buf->size)
|
let n: i64 = _builtin_syscall(SYS_read, fd, buf->data, buf->size)
|
||||||
_builtin_syscall(SYS_close, fd)
|
_builtin_syscall(SYS_close, fd)
|
||||||
@@ -408,7 +408,7 @@ func io.read_binary_file?[path: str] : io.Buffer
|
|||||||
if n != buf->size
|
if n != buf->size
|
||||||
io.Buffer.free(buf)
|
io.Buffer.free(buf)
|
||||||
err.set(ERR_READ_FAILED, "io.read_binary_file?: failed to read file")
|
err.set(ERR_READ_FAILED, "io.read_binary_file?: failed to read file")
|
||||||
return 0
|
return 0 as io.Buffer
|
||||||
|
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
@@ -664,7 +664,7 @@ func str.hex_encode[s: str, s_len: i64] : str
|
|||||||
out[j] = 0
|
out[j] = 0
|
||||||
return out
|
return out
|
||||||
|
|
||||||
func str._hex_digit_to_int[d: u8] : i64
|
func str._hex_digit_to_int[d: u8] : u8
|
||||||
if d >= 'a' && d <= 'f'
|
if d >= 'a' && d <= 'f'
|
||||||
return d - 'a' + 10
|
return d - 'a' + 10
|
||||||
if d >= 'A' && d <= 'F'
|
if d >= 'A' && d <= 'F'
|
||||||
@@ -902,13 +902,13 @@ func os.urandom?[n: i64]: ptr
|
|||||||
err.clear()
|
err.clear()
|
||||||
let buffer: ptr = mem.alloc(n)
|
let buffer: ptr = mem.alloc(n)
|
||||||
if err.check()
|
if err.check()
|
||||||
return 0
|
return 0 as ptr
|
||||||
|
|
||||||
let fd: i64 = _builtin_syscall(SYS_openat, -100, "/dev/urandom", 0, 0)
|
let fd: i64 = _builtin_syscall(SYS_openat, -100, "/dev/urandom", 0, 0)
|
||||||
if fd < 0
|
if fd < 0
|
||||||
mem.free(buffer)
|
mem.free(buffer)
|
||||||
err.set(ERR_READ_FAILED, "os.urandom?: failed to open /dev/urandom")
|
err.set(ERR_READ_FAILED, "os.urandom?: failed to open /dev/urandom")
|
||||||
return 0
|
return 0 as ptr
|
||||||
|
|
||||||
let bytes_read: i64 = _builtin_syscall(SYS_read, fd, buffer, n)
|
let bytes_read: i64 = _builtin_syscall(SYS_read, fd, buffer, n)
|
||||||
_builtin_syscall(SYS_close, fd)
|
_builtin_syscall(SYS_close, fd)
|
||||||
@@ -916,7 +916,7 @@ func os.urandom?[n: i64]: ptr
|
|||||||
if n != bytes_read
|
if n != bytes_read
|
||||||
mem.free(buffer)
|
mem.free(buffer)
|
||||||
err.set(ERR_READ_FAILED, "os.urandom?: failed to read /dev/urandom")
|
err.set(ERR_READ_FAILED, "os.urandom?: failed to read /dev/urandom")
|
||||||
return 0
|
return 0 as ptr
|
||||||
|
|
||||||
return buffer
|
return buffer
|
||||||
|
|
||||||
@@ -968,7 +968,7 @@ func os.list_directory?[path: str] : Array
|
|||||||
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
|
||||||
err.set(ERR_OPEN_FAILED, "os.list_directory?: failed to open dir")
|
err.set(ERR_OPEN_FAILED, "os.list_directory?: failed to open dir")
|
||||||
return 0
|
return 0 as Array
|
||||||
|
|
||||||
let files: Array = []
|
let files: Array = []
|
||||||
let buf: ptr = mem.alloc(1024)
|
let buf: ptr = mem.alloc(1024)
|
||||||
@@ -983,7 +983,7 @@ func os.list_directory?[path: str] : Array
|
|||||||
|
|
||||||
_builtin_syscall(SYS_close, fd)
|
_builtin_syscall(SYS_close, fd)
|
||||||
err.set(ERR_SYSCALL_FAILED, "os.list_directory?: getdents64() failed")
|
err.set(ERR_SYSCALL_FAILED, "os.list_directory?: getdents64() failed")
|
||||||
return 0
|
return 0 as Array
|
||||||
else if n == 0
|
else if n == 0
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
#![allow(unused_variables)]
|
|
||||||
|
|
||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -72,11 +69,15 @@ impl Env {
|
|||||||
|
|
||||||
pub struct TypeChecker {
|
pub struct TypeChecker {
|
||||||
analyzer: Rc<RefCell<Analyzer>>,
|
analyzer: Rc<RefCell<Analyzer>>,
|
||||||
|
current_function_return_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeChecker {
|
impl TypeChecker {
|
||||||
pub fn new(analyzer: Rc<RefCell<Analyzer>>) -> TypeChecker {
|
pub fn new(analyzer: Rc<RefCell<Analyzer>>) -> TypeChecker {
|
||||||
TypeChecker { analyzer }
|
TypeChecker {
|
||||||
|
analyzer,
|
||||||
|
current_function_return_type: String::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn typecheck_stmt(&mut self, env: &mut Env, stmt: &Stmt) -> Result<(), ZernError> {
|
pub fn typecheck_stmt(&mut self, env: &mut Env, stmt: &Stmt) -> Result<(), ZernError> {
|
||||||
@@ -106,11 +107,15 @@ impl TypeChecker {
|
|||||||
|
|
||||||
env.define_var(name.lexeme.clone(), actual_type);
|
env.define_var(name.lexeme.clone(), actual_type);
|
||||||
}
|
}
|
||||||
Stmt::Const { name, value } => {}
|
Stmt::Const { name: _, value: _ } => {
|
||||||
|
// handled in the analyzer
|
||||||
|
}
|
||||||
Stmt::Block(stmts) => {
|
Stmt::Block(stmts) => {
|
||||||
|
env.push_scope();
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
self.typecheck_stmt(env, stmt)?;
|
self.typecheck_stmt(env, stmt)?;
|
||||||
}
|
}
|
||||||
|
env.pop_scope();
|
||||||
}
|
}
|
||||||
Stmt::If {
|
Stmt::If {
|
||||||
condition,
|
condition,
|
||||||
@@ -140,14 +145,12 @@ impl TypeChecker {
|
|||||||
env.pop_scope();
|
env.pop_scope();
|
||||||
}
|
}
|
||||||
Stmt::Function {
|
Stmt::Function {
|
||||||
name,
|
name: _,
|
||||||
params,
|
params,
|
||||||
return_type,
|
return_type,
|
||||||
body,
|
body,
|
||||||
exported,
|
exported: _,
|
||||||
} => {
|
} => {
|
||||||
env.push_scope();
|
|
||||||
|
|
||||||
if !self.is_valid_type_name(&return_type.lexeme) {
|
if !self.is_valid_type_name(&return_type.lexeme) {
|
||||||
return error!(
|
return error!(
|
||||||
&return_type.loc,
|
&return_type.loc,
|
||||||
@@ -155,7 +158,11 @@ impl TypeChecker {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, param) in params.iter().enumerate() {
|
self.current_function_return_type = return_type.lexeme.clone();
|
||||||
|
|
||||||
|
env.push_scope();
|
||||||
|
|
||||||
|
for param in params {
|
||||||
if !self.is_valid_type_name(¶m.var_type.lexeme) {
|
if !self.is_valid_type_name(¶m.var_type.lexeme) {
|
||||||
return error!(
|
return error!(
|
||||||
¶m.var_name.loc,
|
¶m.var_name.loc,
|
||||||
@@ -170,15 +177,22 @@ impl TypeChecker {
|
|||||||
|
|
||||||
env.pop_scope();
|
env.pop_scope();
|
||||||
}
|
}
|
||||||
Stmt::Return(expr) => {
|
Stmt::Return { expr, keyword } => {
|
||||||
// TODO
|
let expected = if self.current_function_return_type == "void" {
|
||||||
|
"i64".into()
|
||||||
|
} else {
|
||||||
|
self.current_function_return_type.clone()
|
||||||
|
};
|
||||||
|
expect_type!(self.typecheck_expr(env, expr)?, expected, keyword.loc);
|
||||||
}
|
}
|
||||||
Stmt::Break => {}
|
Stmt::Break => {}
|
||||||
Stmt::Continue => {}
|
Stmt::Continue => {}
|
||||||
Stmt::Extern(_) => {
|
Stmt::Extern(_) => {
|
||||||
// handled in the analyzer
|
// handled in the analyzer
|
||||||
}
|
}
|
||||||
Stmt::Struct { name, fields } => {}
|
Stmt::Struct { name: _, fields: _ } => {
|
||||||
|
// TODO: validate types
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -265,7 +279,7 @@ impl TypeChecker {
|
|||||||
|
|
||||||
match left.as_ref() {
|
match left.as_ref() {
|
||||||
Expr::Variable(name) => {
|
Expr::Variable(name) => {
|
||||||
let var_type = match env.get_var_type(&name.lexeme) {
|
let existing_var_type = match env.get_var_type(&name.lexeme) {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => {
|
None => {
|
||||||
return error!(
|
return error!(
|
||||||
@@ -274,7 +288,7 @@ impl TypeChecker {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
expect_type!(*var_type, value_type, name.loc);
|
expect_type!(value_type, *existing_var_type, name.loc);
|
||||||
}
|
}
|
||||||
Expr::Index {
|
Expr::Index {
|
||||||
expr,
|
expr,
|
||||||
@@ -403,6 +417,7 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
Expr::Cast { expr, type_name } => {
|
Expr::Cast { expr, type_name } => {
|
||||||
self.typecheck_expr(env, expr)?;
|
self.typecheck_expr(env, expr)?;
|
||||||
|
// TODO: validate target type
|
||||||
Ok(type_name.lexeme.clone())
|
Ok(type_name.lexeme.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user