attach id to expressions
This commit is contained in:
@@ -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));
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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!(
|
||||||
|
|||||||
Reference in New Issue
Block a user