attach id to expressions

This commit is contained in:
2026-05-13 13:14:55 +02:00
parent 52443c837b
commit 5f2082ef57
4 changed files with 116 additions and 102 deletions

View File

@@ -1,7 +1,7 @@
use std::{collections::HashMap, fmt::Write}; use std::{collections::HashMap, fmt::Write};
use crate::{ use crate::{
parser::{Expr, Params, Stmt}, parser::{Expr, ExprKind, Params, Stmt},
symbol_table::SymbolTable, symbol_table::SymbolTable,
tokenizer::{Token, TokenType, ZernError, error}, tokenizer::{Token, TokenType, ZernError, error},
}; };
@@ -218,13 +218,9 @@ _builtin_environ:
let var_type: String = match var_type { let var_type: String = match var_type {
Some(t) => t.lexeme.clone(), Some(t) => t.lexeme.clone(),
None => match &initializer { None => match &initializer.kind {
Expr::Literal(token) => { ExprKind::Literal(token) if token.token_type == TokenType::IntLiteral => {
if token.token_type == TokenType::IntLiteral {
"i64".into() "i64".into()
} else {
return error!(&name.loc, "unable to infer variable type");
}
} }
_ => return error!(&name.loc, "unable to infer variable type"), _ => return error!(&name.loc, "unable to infer variable type"),
}, },
@@ -406,8 +402,8 @@ _builtin_environ:
} }
pub fn compile_expr(&mut self, env: &mut Env, expr: &Expr) -> Result<(), ZernError> { pub fn compile_expr(&mut self, env: &mut Env, expr: &Expr) -> Result<(), ZernError> {
match expr { match &expr.kind {
Expr::Binary { left, op, right } => { ExprKind::Binary { left, op, right } => {
self.compile_expr(env, left)?; self.compile_expr(env, left)?;
emit!(&mut self.output, " push rax"); emit!(&mut self.output, " push rax");
self.compile_expr(env, right)?; self.compile_expr(env, right)?;
@@ -483,7 +479,7 @@ _builtin_environ:
_ => unreachable!(), _ => unreachable!(),
} }
} }
Expr::Logical { left, op, right } => { ExprKind::Logical { left, op, right } => {
let end_label = self.label(); let end_label = self.label();
match op.token_type { match op.token_type {
TokenType::LogicalAnd => { TokenType::LogicalAnd => {
@@ -502,8 +498,8 @@ _builtin_environ:
} }
emit!(&mut self.output, "{}:", end_label); emit!(&mut self.output, "{}:", end_label);
} }
Expr::Grouping(expr) => self.compile_expr(env, expr)?, ExprKind::Grouping(expr) => self.compile_expr(env, expr)?,
Expr::Literal(token) => match token.token_type { ExprKind::Literal(token) => match token.token_type {
TokenType::IntLiteral => { TokenType::IntLiteral => {
emit!(&mut self.output, " mov rax, {}", token.lexeme); emit!(&mut self.output, " mov rax, {}", token.lexeme);
} }
@@ -520,18 +516,16 @@ _builtin_environ:
let label = format!("str_{:03}", self.data_counter); let label = format!("str_{:03}", self.data_counter);
if value.is_empty() {
emit!(&mut self.data_section, " {} db 0", label);
} else {
let charcodes = value let charcodes = value
.chars() .chars()
.map(|x| (x as u8).to_string()) .map(|x| (x as u8).to_string())
.collect::<Vec<String>>() .chain(std::iter::once("0".into()))
.collect::<Vec<_>>()
.join(","); .join(",");
emit!(&mut self.data_section, " {} db {},0", label, charcodes); emit!(&mut self.data_section, " {} db {}", label, charcodes);
}
emit!(&mut self.output, " mov rax, {}", label);
self.data_counter += 1; self.data_counter += 1;
emit!(&mut self.output, " mov rax, {}", label);
} }
TokenType::True => { TokenType::True => {
emit!(&mut self.output, " mov rax, 1"); emit!(&mut self.output, " mov rax, 1");
@@ -541,7 +535,7 @@ _builtin_environ:
} }
_ => unreachable!(), _ => unreachable!(),
}, },
Expr::Unary { op, right } => { ExprKind::Unary { op, right } => {
self.compile_expr(env, right)?; self.compile_expr(env, right)?;
match op.token_type { match op.token_type {
TokenType::Minus => { TokenType::Minus => {
@@ -555,7 +549,7 @@ _builtin_environ:
_ => unreachable!(), _ => unreachable!(),
} }
} }
Expr::Variable(name) => { ExprKind::Variable(name) => {
if self.symbol_table.constants.contains_key(&name.lexeme) { if self.symbol_table.constants.contains_key(&name.lexeme) {
emit!( emit!(
&mut self.output, &mut self.output,
@@ -574,11 +568,11 @@ _builtin_environ:
); );
} }
} }
Expr::Assign { left, op, value } => { ExprKind::Assign { left, op, value } => {
self.compile_expr(env, value)?; self.compile_expr(env, value)?;
match left.as_ref() { match &left.kind {
Expr::Variable(name) => { ExprKind::Variable(name) => {
let var = match env.get_var(&name.lexeme) { let var = match env.get_var(&name.lexeme) {
Some(x) => x, Some(x) => x,
None => unreachable!(), None => unreachable!(),
@@ -589,7 +583,7 @@ _builtin_environ:
var.stack_offset, var.stack_offset,
); );
} }
Expr::Index { ExprKind::Index {
expr, expr,
bracket: _, bracket: _,
index, index,
@@ -603,7 +597,7 @@ _builtin_environ:
emit!(&mut self.output, " pop rax"); emit!(&mut self.output, " pop rax");
emit!(&mut self.output, " mov BYTE [rbx], al"); emit!(&mut self.output, " mov BYTE [rbx], al");
} }
Expr::MemberAccess { left, field } => { ExprKind::MemberAccess { left, field } => {
emit!(&mut self.output, " push rax"); emit!(&mut self.output, " push rax");
let offset = self.get_field_offset(env, left, field)?; let offset = self.get_field_offset(env, left, field)?;
@@ -615,12 +609,12 @@ _builtin_environ:
_ => return error!(&op.loc, "invalid assignment target"), _ => return error!(&op.loc, "invalid assignment target"),
}; };
} }
Expr::Call { ExprKind::Call {
callee, callee,
paren: _, paren: _,
args, args,
} => { } => {
if let Expr::Variable(callee_name) = &**callee if let ExprKind::Variable(callee_name) = &callee.kind
&& callee_name.lexeme == "_var_arg" && callee_name.lexeme == "_var_arg"
{ {
return self.emit_var_arg(env, &args[0]); return self.emit_var_arg(env, &args[0]);
@@ -661,7 +655,7 @@ _builtin_environ:
} }
} }
if let Expr::Variable(callee_name) = &**callee { if let ExprKind::Variable(callee_name) = &callee.kind {
if self if self
.symbol_table .symbol_table
.functions .functions
@@ -686,7 +680,7 @@ _builtin_environ:
emit!(&mut self.output, " add rsp, {}", 8 * arg_count); emit!(&mut self.output, " add rsp, {}", 8 * arg_count);
} }
} }
Expr::ArrayLiteral(exprs) => { ExprKind::ArrayLiteral(exprs) => {
emit!(&mut self.output, " call array.new"); emit!(&mut self.output, " call array.new");
emit!(&mut self.output, " push rax"); emit!(&mut self.output, " push rax");
@@ -699,7 +693,7 @@ _builtin_environ:
} }
emit!(&mut self.output, " pop rax"); emit!(&mut self.output, " pop rax");
} }
Expr::Index { ExprKind::Index {
expr, expr,
bracket: _, bracket: _,
index, index,
@@ -711,8 +705,8 @@ _builtin_environ:
emit!(&mut self.output, " add rax, rbx"); emit!(&mut self.output, " add rax, rbx");
emit!(&mut self.output, " movzx rax, BYTE [rax]"); emit!(&mut self.output, " movzx rax, BYTE [rax]");
} }
Expr::AddrOf { op, expr } => match *expr.clone() { ExprKind::AddrOf { op, expr } => match &expr.kind {
Expr::Variable(name) => { ExprKind::Variable(name) => {
if self.symbol_table.functions.contains_key(&name.lexeme) { if self.symbol_table.functions.contains_key(&name.lexeme) {
emit!(&mut self.output, " mov rax, {}", name.lexeme); emit!(&mut self.output, " mov rax, {}", name.lexeme);
} else { } else {
@@ -736,7 +730,7 @@ _builtin_environ:
return error!(&op.loc, "can only take address of variables and functions"); return error!(&op.loc, "can only take address of variables and functions");
} }
}, },
Expr::New(struct_name) => { ExprKind::New(struct_name) => {
let struct_fields = &self.symbol_table.structs[&struct_name.lexeme]; let struct_fields = &self.symbol_table.structs[&struct_name.lexeme];
let memory_size = struct_fields.len() * 8; let memory_size = struct_fields.len() * 8;
@@ -748,12 +742,12 @@ _builtin_environ:
emit!(&mut self.output, " call mem.zero"); emit!(&mut self.output, " call mem.zero");
emit!(&mut self.output, " pop rax"); emit!(&mut self.output, " pop rax");
} }
Expr::MemberAccess { left, field } => { ExprKind::MemberAccess { left, field } => {
let offset = self.get_field_offset(env, left, field)?; let offset = self.get_field_offset(env, left, field)?;
self.compile_expr(env, left)?; self.compile_expr(env, left)?;
emit!(&mut self.output, " mov rax, QWORD [rax+{}]", offset); emit!(&mut self.output, " mov rax, QWORD [rax+{}]", offset);
} }
Expr::Cast { expr, type_name: _ } => { ExprKind::Cast { expr, type_name: _ } => {
self.compile_expr(env, expr)?; self.compile_expr(env, expr)?;
} }
} }
@@ -766,8 +760,8 @@ _builtin_environ:
left: &Expr, left: &Expr,
field: &Token, field: &Token,
) -> Result<usize, ZernError> { ) -> Result<usize, ZernError> {
let struct_name = match left { let struct_name = match &left.kind {
Expr::Variable(name) => match env.get_var(&name.lexeme) { ExprKind::Variable(name) => match env.get_var(&name.lexeme) {
Some(v) => v.var_type.clone(), Some(v) => v.var_type.clone(),
None => { None => {
return error!(name.loc, format!("undefined variable: {}", &name.lexeme)); return error!(name.loc, format!("undefined variable: {}", &name.lexeme));

View File

@@ -121,6 +121,8 @@ struct Args {
impl Args { impl Args {
fn parse(mut args: std::env::Args) -> Args { fn parse(mut args: std::env::Args) -> Args {
_ = args.next(); // skip the program name
let mut out = Args { let mut out = Args {
path: String::new(), path: String::new(),
out: None, out: None,
@@ -187,9 +189,7 @@ impl Args {
} }
fn main() { fn main() {
let mut raw_args = std::env::args(); let args = Args::parse(std::env::args());
_ = raw_args.next();
let args = Args::parse(raw_args);
if let Err(err) = compile_file(args) { if let Err(err) = compile_file(args) {
eprintln!("{}", err); eprintln!("{}", err);

View File

@@ -1,3 +1,5 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use crate::tokenizer::{Token, TokenType, ZernError, error}; use crate::tokenizer::{Token, TokenType, ZernError, error};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -62,8 +64,26 @@ pub enum Stmt {
}, },
} }
pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expr { pub struct Expr {
pub id: usize,
pub kind: ExprKind,
}
impl Expr {
pub fn new(kind: ExprKind) -> Expr {
NEXT_EXPR_ID.fetch_add(1, Ordering::SeqCst);
Expr {
id: NEXT_EXPR_ID.load(Ordering::SeqCst),
kind,
}
}
}
#[derive(Debug, Clone)]
pub enum ExprKind {
Binary { Binary {
left: Box<Expr>, left: Box<Expr>,
op: Token, op: Token,
@@ -357,11 +377,11 @@ impl Parser {
let equals = self.previous().clone(); let equals = self.previous().clone();
let value = self.assignment()?; let value = self.assignment()?;
return Ok(Expr::Assign { return Ok(Expr::new(ExprKind::Assign {
left: Box::new(expr), left: Box::new(expr),
op: equals, op: equals,
value: Box::new(value), value: Box::new(value),
}); }));
} }
Ok(expr) Ok(expr)
@@ -374,19 +394,19 @@ impl Parser {
let pipe = self.previous().clone(); let pipe = self.previous().clone();
let right = self.equality()?; let right = self.equality()?;
match right { match right.kind {
Expr::Call { ExprKind::Call {
callee, callee,
paren, paren,
args, args,
} => { } => {
let mut new_args = args; let mut new_args = args;
new_args.insert(0, expr); new_args.insert(0, expr);
expr = Expr::Call { expr = Expr::new(ExprKind::Call {
callee, callee,
paren, paren,
args: new_args, args: new_args,
} })
} }
_ => { _ => {
return error!(pipe.loc, "tried to pipe into a non-call expression"); return error!(pipe.loc, "tried to pipe into a non-call expression");
@@ -403,11 +423,11 @@ impl Parser {
while self.match_token(&[TokenType::LogicalOr, TokenType::LogicalAnd]) { while self.match_token(&[TokenType::LogicalOr, TokenType::LogicalAnd]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.equality()?; let right = self.equality()?;
expr = Expr::Logical { expr = Expr::new(ExprKind::Logical {
left: Box::new(expr), left: Box::new(expr),
op, op,
right: Box::new(right), right: Box::new(right),
} })
} }
Ok(expr) Ok(expr)
@@ -419,11 +439,11 @@ impl Parser {
while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) { while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.comparison()?; let right = self.comparison()?;
expr = Expr::Binary { expr = Expr::new(ExprKind::Binary {
left: Box::new(expr), left: Box::new(expr),
op, op,
right: Box::new(right), right: Box::new(right),
} })
} }
Ok(expr) Ok(expr)
@@ -440,11 +460,11 @@ impl Parser {
]) { ]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.term()?; let right = self.term()?;
expr = Expr::Binary { expr = Expr::new(ExprKind::Binary {
left: Box::new(expr), left: Box::new(expr),
op, op,
right: Box::new(right), right: Box::new(right),
} })
} }
Ok(expr) Ok(expr)
@@ -462,11 +482,11 @@ impl Parser {
]) { ]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.factor()?; let right = self.factor()?;
expr = Expr::Binary { expr = Expr::new(ExprKind::Binary {
left: Box::new(expr), left: Box::new(expr),
op, op,
right: Box::new(right), right: Box::new(right),
} })
} }
Ok(expr) Ok(expr)
@@ -484,11 +504,11 @@ impl Parser {
]) { ]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.unary()?; let right = self.unary()?;
expr = Expr::Binary { expr = Expr::new(ExprKind::Binary {
left: Box::new(expr), left: Box::new(expr),
op, op,
right: Box::new(right), right: Box::new(right),
} })
} }
Ok(expr) Ok(expr)
@@ -499,10 +519,10 @@ impl Parser {
while self.match_token(&[TokenType::KeywordAs]) { while self.match_token(&[TokenType::KeywordAs]) {
let type_name = self.consume(TokenType::Identifier, "expected type after 'as'")?; let type_name = self.consume(TokenType::Identifier, "expected type after 'as'")?;
expr = Expr::Cast { expr = Expr::new(ExprKind::Cast {
expr: Box::new(expr), expr: Box::new(expr),
type_name, type_name,
}; })
} }
Ok(expr) Ok(expr)
@@ -512,18 +532,18 @@ impl Parser {
if self.match_token(&[TokenType::Xor]) { if self.match_token(&[TokenType::Xor]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.unary()?; let right = self.unary()?;
return Ok(Expr::AddrOf { return Ok(Expr::new(ExprKind::AddrOf {
op, op,
expr: Box::new(right), expr: Box::new(right),
}); }));
} }
if self.match_token(&[TokenType::Bang, TokenType::Minus]) { if self.match_token(&[TokenType::Bang, TokenType::Minus]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.unary()?; let right = self.unary()?;
return Ok(Expr::Unary { return Ok(Expr::new(ExprKind::Unary {
op, op,
right: Box::new(right), right: Box::new(right),
}); }));
} }
self.call() self.call()
@@ -546,26 +566,26 @@ impl Parser {
let paren = self.consume(TokenType::RightParen, "expected ')' after arguments")?; let paren = self.consume(TokenType::RightParen, "expected ')' after arguments")?;
expr = Expr::Call { expr = Expr::new(ExprKind::Call {
callee: Box::new(expr), callee: Box::new(expr),
paren, paren,
args, args,
}; })
} else if self.match_token(&[TokenType::LeftBracket]) { } else if self.match_token(&[TokenType::LeftBracket]) {
let index = self.expression()?; let index = self.expression()?;
let bracket = self.consume(TokenType::RightBracket, "expected ']' after index")?; let bracket = self.consume(TokenType::RightBracket, "expected ']' after index")?;
expr = Expr::Index { expr = Expr::new(ExprKind::Index {
expr: Box::new(expr), expr: Box::new(expr),
bracket, bracket,
index: Box::new(index), index: Box::new(index),
} })
} else if self.match_token(&[TokenType::Arrow]) { } else if self.match_token(&[TokenType::Arrow]) {
let field = let field =
self.consume(TokenType::Identifier, "expected field name after '->'")?; self.consume(TokenType::Identifier, "expected field name after '->'")?;
expr = Expr::MemberAccess { expr = Expr::new(ExprKind::MemberAccess {
left: Box::new(expr), left: Box::new(expr),
field, field,
}; })
} else { } else {
break; break;
} }
@@ -582,11 +602,11 @@ impl Parser {
TokenType::True, TokenType::True,
TokenType::False, TokenType::False,
]) { ]) {
Ok(Expr::Literal(self.previous().clone())) Ok(Expr::new(ExprKind::Literal(self.previous().clone())))
} else if self.match_token(&[TokenType::LeftParen]) { } else if self.match_token(&[TokenType::LeftParen]) {
let expr = self.expression()?; let expr = self.expression()?;
self.consume(TokenType::RightParen, "expected ')' after expression")?; self.consume(TokenType::RightParen, "expected ')' after expression")?;
Ok(Expr::Grouping(Box::new(expr))) Ok(Expr::new(ExprKind::Grouping(Box::new(expr))))
} else if self.match_token(&[TokenType::LeftBracket]) { } else if self.match_token(&[TokenType::LeftBracket]) {
let mut xs = vec![]; let mut xs = vec![];
if !self.check(&TokenType::RightBracket) { if !self.check(&TokenType::RightBracket) {
@@ -599,13 +619,13 @@ impl Parser {
} }
self.consume(TokenType::RightBracket, "expected ']' after values")?; self.consume(TokenType::RightBracket, "expected ']' after values")?;
Ok(Expr::ArrayLiteral(xs)) Ok(Expr::new(ExprKind::ArrayLiteral(xs)))
} else if self.match_token(&[TokenType::KeywordNew]) { } else if self.match_token(&[TokenType::KeywordNew]) {
let struct_name = let struct_name =
self.consume(TokenType::Identifier, "expected struct name after 'new'")?; self.consume(TokenType::Identifier, "expected struct name after 'new'")?;
Ok(Expr::New(struct_name)) Ok(Expr::new(ExprKind::New(struct_name)))
} else if self.match_token(&[TokenType::Identifier]) { } else if self.match_token(&[TokenType::Identifier]) {
Ok(Expr::Variable(self.previous().clone())) Ok(Expr::new(ExprKind::Variable(self.previous().clone())))
} else { } else {
error!( error!(
self.peek().loc, self.peek().loc,

View File

@@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{ use crate::{
parser::{Expr, Params, Stmt}, parser::{Expr, ExprKind, Params, Stmt},
symbol_table::{SymbolTable, Type}, symbol_table::{SymbolTable, Type},
tokenizer::{TokenType, ZernError, error}, tokenizer::{TokenType, ZernError, error},
}; };
@@ -263,8 +263,8 @@ impl<'a> TypeChecker<'a> {
} }
pub fn typecheck_expr(&self, env: &mut Env, expr: &Expr) -> Result<Type, ZernError> { pub fn typecheck_expr(&self, env: &mut Env, expr: &Expr) -> Result<Type, ZernError> {
match expr { match &expr.kind {
Expr::Binary { left, op, right } => { ExprKind::Binary { left, op, right } => {
let left_type = self.typecheck_expr(env, left)?; let left_type = self.typecheck_expr(env, left)?;
match op.token_type { match op.token_type {
@@ -306,7 +306,7 @@ impl<'a> TypeChecker<'a> {
_ => unreachable!(), _ => unreachable!(),
} }
} }
Expr::Logical { left, op, right } => { ExprKind::Logical { left, op, right } => {
expect_types!( expect_types!(
self.typecheck_expr(env, left)?, self.typecheck_expr(env, left)?,
["bool", "i64", "ptr"], ["bool", "i64", "ptr"],
@@ -319,8 +319,8 @@ impl<'a> TypeChecker<'a> {
); );
Ok("bool".into()) Ok("bool".into())
} }
Expr::Grouping(expr) => self.typecheck_expr(env, expr), ExprKind::Grouping(expr) => self.typecheck_expr(env, expr),
Expr::Literal(token) => match token.token_type { ExprKind::Literal(token) => match token.token_type {
TokenType::IntLiteral => Ok("i64".into()), TokenType::IntLiteral => Ok("i64".into()),
TokenType::CharLiteral => Ok("u8".into()), TokenType::CharLiteral => Ok("u8".into()),
TokenType::StringLiteral => Ok("str".into()), TokenType::StringLiteral => Ok("str".into()),
@@ -328,7 +328,7 @@ impl<'a> TypeChecker<'a> {
TokenType::False => Ok("bool".into()), TokenType::False => Ok("bool".into()),
_ => unreachable!(), _ => unreachable!(),
}, },
Expr::Unary { op, right } => { ExprKind::Unary { op, right } => {
let right_type = self.typecheck_expr(env, right)?; let right_type = self.typecheck_expr(env, right)?;
match op.token_type { match op.token_type {
TokenType::Minus => { TokenType::Minus => {
@@ -342,7 +342,7 @@ impl<'a> TypeChecker<'a> {
_ => unreachable!(), _ => unreachable!(),
} }
} }
Expr::Variable(name) => { ExprKind::Variable(name) => {
if self.symbol_table.constants.contains_key(&name.lexeme) { if self.symbol_table.constants.contains_key(&name.lexeme) {
Ok("i64".into()) Ok("i64".into())
} else { } else {
@@ -352,11 +352,11 @@ impl<'a> TypeChecker<'a> {
} }
} }
} }
Expr::Assign { left, op, value } => { ExprKind::Assign { left, op, value } => {
let value_type = self.typecheck_expr(env, value)?; let value_type = self.typecheck_expr(env, value)?;
match left.as_ref() { match &left.kind {
Expr::Variable(name) => { ExprKind::Variable(name) => {
let existing_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 => {
@@ -368,7 +368,7 @@ impl<'a> TypeChecker<'a> {
}; };
expect_type!(value_type.clone(), *existing_var_type, name.loc); expect_type!(value_type.clone(), *existing_var_type, name.loc);
} }
Expr::Index { ExprKind::Index {
expr, expr,
bracket, bracket,
index, index,
@@ -377,7 +377,7 @@ impl<'a> TypeChecker<'a> {
expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc); expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc);
expect_types!(value_type.clone(), ["u8", "i64"], bracket.loc); expect_types!(value_type.clone(), ["u8", "i64"], bracket.loc);
} }
Expr::MemberAccess { left, field } => { ExprKind::MemberAccess { left, field } => {
let left_type = self.typecheck_expr(env, left)?; let left_type = self.typecheck_expr(env, left)?;
let fields = match self.symbol_table.structs.get(&left_type) { let fields = match self.symbol_table.structs.get(&left_type) {
@@ -406,12 +406,12 @@ impl<'a> TypeChecker<'a> {
} }
Ok(value_type) Ok(value_type)
} }
Expr::Call { ExprKind::Call {
callee, callee,
paren, paren,
args, args,
} => { } => {
if let Expr::Variable(callee_name) = &**callee { if let ExprKind::Variable(callee_name) = &callee.kind {
if let Some(fn_type) = self.symbol_table.functions.get(&callee_name.lexeme) { if let Some(fn_type) = self.symbol_table.functions.get(&callee_name.lexeme) {
// its a function (defined/builtin/extern) // its a function (defined/builtin/extern)
if let Some(params) = fn_type.params.clone() { if let Some(params) = fn_type.params.clone() {
@@ -454,13 +454,13 @@ impl<'a> TypeChecker<'a> {
Ok("any".into()) Ok("any".into())
} }
} }
Expr::ArrayLiteral(exprs) => { ExprKind::ArrayLiteral(exprs) => {
for expr in exprs { for expr in exprs {
self.typecheck_expr(env, expr)?; self.typecheck_expr(env, expr)?;
} }
Ok("Array".into()) Ok("Array".into())
} }
Expr::Index { ExprKind::Index {
expr, expr,
bracket, bracket,
index, index,
@@ -469,8 +469,8 @@ impl<'a> TypeChecker<'a> {
expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc); expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc);
Ok("u8".into()) Ok("u8".into())
} }
Expr::AddrOf { op, expr } => match expr.as_ref() { ExprKind::AddrOf { op, expr } => match &expr.kind {
Expr::Variable(name) => { ExprKind::Variable(name) => {
if self.symbol_table.functions.contains_key(&name.lexeme) { if self.symbol_table.functions.contains_key(&name.lexeme) {
Ok("fnptr".into()) Ok("fnptr".into())
} else { } else {
@@ -481,7 +481,7 @@ impl<'a> TypeChecker<'a> {
error!(&op.loc, "can only take address of variables and functions") error!(&op.loc, "can only take address of variables and functions")
} }
}, },
Expr::New(struct_name) => { ExprKind::New(struct_name) => {
if !self.symbol_table.structs.contains_key(&struct_name.lexeme) { if !self.symbol_table.structs.contains_key(&struct_name.lexeme) {
return error!( return error!(
&struct_name.loc, &struct_name.loc,
@@ -490,7 +490,7 @@ impl<'a> TypeChecker<'a> {
} }
Ok(struct_name.lexeme.clone()) Ok(struct_name.lexeme.clone())
} }
Expr::MemberAccess { left, field } => { ExprKind::MemberAccess { left, field } => {
let left_type = self.typecheck_expr(env, left)?; let left_type = self.typecheck_expr(env, left)?;
let fields = match self.symbol_table.structs.get(&left_type) { let fields = match self.symbol_table.structs.get(&left_type) {
@@ -507,7 +507,7 @@ impl<'a> TypeChecker<'a> {
Ok(field.field_type.clone()) Ok(field.field_type.clone())
} }
Expr::Cast { expr, type_name } => { ExprKind::Cast { expr, type_name } => {
self.typecheck_expr(env, expr)?; self.typecheck_expr(env, expr)?;
if !self.is_valid_type_name(&type_name.lexeme) { if !self.is_valid_type_name(&type_name.lexeme) {
return error!( return error!(