diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 25679ef..63a25d9 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, fmt::Write}; use crate::{ - parser::{Expr, Params, Stmt}, + parser::{Expr, ExprKind, Params, Stmt}, symbol_table::SymbolTable, tokenizer::{Token, TokenType, ZernError, error}, }; @@ -218,13 +218,9 @@ _builtin_environ: let var_type: String = match var_type { Some(t) => t.lexeme.clone(), - None => match &initializer { - Expr::Literal(token) => { - if token.token_type == TokenType::IntLiteral { - "i64".into() - } else { - return error!(&name.loc, "unable to infer variable type"); - } + None => match &initializer.kind { + ExprKind::Literal(token) if token.token_type == TokenType::IntLiteral => { + "i64".into() } _ => 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> { - match expr { - Expr::Binary { left, op, right } => { + match &expr.kind { + ExprKind::Binary { left, op, right } => { self.compile_expr(env, left)?; emit!(&mut self.output, " push rax"); self.compile_expr(env, right)?; @@ -483,7 +479,7 @@ _builtin_environ: _ => unreachable!(), } } - Expr::Logical { left, op, right } => { + ExprKind::Logical { left, op, right } => { let end_label = self.label(); match op.token_type { TokenType::LogicalAnd => { @@ -502,8 +498,8 @@ _builtin_environ: } emit!(&mut self.output, "{}:", end_label); } - Expr::Grouping(expr) => self.compile_expr(env, expr)?, - Expr::Literal(token) => match token.token_type { + ExprKind::Grouping(expr) => self.compile_expr(env, expr)?, + ExprKind::Literal(token) => match token.token_type { TokenType::IntLiteral => { emit!(&mut self.output, " mov rax, {}", token.lexeme); } @@ -520,18 +516,16 @@ _builtin_environ: let label = format!("str_{:03}", self.data_counter); - if value.is_empty() { - emit!(&mut self.data_section, " {} db 0", label); - } else { - let charcodes = value - .chars() - .map(|x| (x as u8).to_string()) - .collect::>() - .join(","); - emit!(&mut self.data_section, " {} db {},0", label, charcodes); - } - emit!(&mut self.output, " mov rax, {}", label); + let charcodes = value + .chars() + .map(|x| (x as u8).to_string()) + .chain(std::iter::once("0".into())) + .collect::>() + .join(","); + emit!(&mut self.data_section, " {} db {}", label, charcodes); self.data_counter += 1; + + emit!(&mut self.output, " mov rax, {}", label); } TokenType::True => { emit!(&mut self.output, " mov rax, 1"); @@ -541,7 +535,7 @@ _builtin_environ: } _ => unreachable!(), }, - Expr::Unary { op, right } => { + ExprKind::Unary { op, right } => { self.compile_expr(env, right)?; match op.token_type { TokenType::Minus => { @@ -555,7 +549,7 @@ _builtin_environ: _ => unreachable!(), } } - Expr::Variable(name) => { + ExprKind::Variable(name) => { if self.symbol_table.constants.contains_key(&name.lexeme) { emit!( &mut self.output, @@ -574,11 +568,11 @@ _builtin_environ: ); } } - Expr::Assign { left, op, value } => { + ExprKind::Assign { left, op, value } => { self.compile_expr(env, value)?; - match left.as_ref() { - Expr::Variable(name) => { + match &left.kind { + ExprKind::Variable(name) => { let var = match env.get_var(&name.lexeme) { Some(x) => x, None => unreachable!(), @@ -589,7 +583,7 @@ _builtin_environ: var.stack_offset, ); } - Expr::Index { + ExprKind::Index { expr, bracket: _, index, @@ -603,7 +597,7 @@ _builtin_environ: emit!(&mut self.output, " pop rax"); emit!(&mut self.output, " mov BYTE [rbx], al"); } - Expr::MemberAccess { left, field } => { + ExprKind::MemberAccess { left, field } => { emit!(&mut self.output, " push rax"); let offset = self.get_field_offset(env, left, field)?; @@ -615,12 +609,12 @@ _builtin_environ: _ => return error!(&op.loc, "invalid assignment target"), }; } - Expr::Call { + ExprKind::Call { callee, paren: _, args, } => { - if let Expr::Variable(callee_name) = &**callee + if let ExprKind::Variable(callee_name) = &callee.kind && callee_name.lexeme == "_var_arg" { 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 .symbol_table .functions @@ -686,7 +680,7 @@ _builtin_environ: 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, " push rax"); @@ -699,7 +693,7 @@ _builtin_environ: } emit!(&mut self.output, " pop rax"); } - Expr::Index { + ExprKind::Index { expr, bracket: _, index, @@ -711,8 +705,8 @@ _builtin_environ: emit!(&mut self.output, " add rax, rbx"); emit!(&mut self.output, " movzx rax, BYTE [rax]"); } - Expr::AddrOf { op, expr } => match *expr.clone() { - Expr::Variable(name) => { + ExprKind::AddrOf { op, expr } => match &expr.kind { + ExprKind::Variable(name) => { if self.symbol_table.functions.contains_key(&name.lexeme) { emit!(&mut self.output, " mov rax, {}", name.lexeme); } else { @@ -736,7 +730,7 @@ _builtin_environ: 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 memory_size = struct_fields.len() * 8; @@ -748,12 +742,12 @@ _builtin_environ: emit!(&mut self.output, " call mem.zero"); emit!(&mut self.output, " pop rax"); } - Expr::MemberAccess { left, field } => { + ExprKind::MemberAccess { left, field } => { let offset = self.get_field_offset(env, left, field)?; self.compile_expr(env, left)?; emit!(&mut self.output, " mov rax, QWORD [rax+{}]", offset); } - Expr::Cast { expr, type_name: _ } => { + ExprKind::Cast { expr, type_name: _ } => { self.compile_expr(env, expr)?; } } @@ -766,8 +760,8 @@ _builtin_environ: left: &Expr, field: &Token, ) -> Result { - let struct_name = match left { - Expr::Variable(name) => match env.get_var(&name.lexeme) { + let struct_name = match &left.kind { + ExprKind::Variable(name) => match env.get_var(&name.lexeme) { Some(v) => v.var_type.clone(), None => { return error!(name.loc, format!("undefined variable: {}", &name.lexeme)); diff --git a/src/main.rs b/src/main.rs index ecbc00e..5c2d18b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -121,6 +121,8 @@ struct Args { impl Args { fn parse(mut args: std::env::Args) -> Args { + _ = args.next(); // skip the program name + let mut out = Args { path: String::new(), out: None, @@ -187,9 +189,7 @@ impl Args { } fn main() { - let mut raw_args = std::env::args(); - _ = raw_args.next(); - let args = Args::parse(raw_args); + let args = Args::parse(std::env::args()); if let Err(err) = compile_file(args) { eprintln!("{}", err); diff --git a/src/parser.rs b/src/parser.rs index 7f8a375..8f694d6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,3 +1,5 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + use crate::tokenizer::{Token, TokenType, ZernError, error}; #[derive(Debug, Clone)] @@ -62,8 +64,26 @@ pub enum Stmt { }, } +pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0); + #[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 { left: Box, op: Token, @@ -357,11 +377,11 @@ impl Parser { let equals = self.previous().clone(); let value = self.assignment()?; - return Ok(Expr::Assign { + return Ok(Expr::new(ExprKind::Assign { left: Box::new(expr), op: equals, value: Box::new(value), - }); + })); } Ok(expr) @@ -374,19 +394,19 @@ impl Parser { let pipe = self.previous().clone(); let right = self.equality()?; - match right { - Expr::Call { + match right.kind { + ExprKind::Call { callee, paren, args, } => { let mut new_args = args; new_args.insert(0, expr); - expr = Expr::Call { + expr = Expr::new(ExprKind::Call { callee, paren, args: new_args, - } + }) } _ => { 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]) { let op = self.previous().clone(); let right = self.equality()?; - expr = Expr::Logical { + expr = Expr::new(ExprKind::Logical { left: Box::new(expr), op, right: Box::new(right), - } + }) } Ok(expr) @@ -419,11 +439,11 @@ impl Parser { while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) { let op = self.previous().clone(); let right = self.comparison()?; - expr = Expr::Binary { + expr = Expr::new(ExprKind::Binary { left: Box::new(expr), op, right: Box::new(right), - } + }) } Ok(expr) @@ -440,11 +460,11 @@ impl Parser { ]) { let op = self.previous().clone(); let right = self.term()?; - expr = Expr::Binary { + expr = Expr::new(ExprKind::Binary { left: Box::new(expr), op, right: Box::new(right), - } + }) } Ok(expr) @@ -462,11 +482,11 @@ impl Parser { ]) { let op = self.previous().clone(); let right = self.factor()?; - expr = Expr::Binary { + expr = Expr::new(ExprKind::Binary { left: Box::new(expr), op, right: Box::new(right), - } + }) } Ok(expr) @@ -484,11 +504,11 @@ impl Parser { ]) { let op = self.previous().clone(); let right = self.unary()?; - expr = Expr::Binary { + expr = Expr::new(ExprKind::Binary { left: Box::new(expr), op, right: Box::new(right), - } + }) } Ok(expr) @@ -499,10 +519,10 @@ impl Parser { while self.match_token(&[TokenType::KeywordAs]) { let type_name = self.consume(TokenType::Identifier, "expected type after 'as'")?; - expr = Expr::Cast { + expr = Expr::new(ExprKind::Cast { expr: Box::new(expr), type_name, - }; + }) } Ok(expr) @@ -512,18 +532,18 @@ impl Parser { if self.match_token(&[TokenType::Xor]) { let op = self.previous().clone(); let right = self.unary()?; - return Ok(Expr::AddrOf { + return Ok(Expr::new(ExprKind::AddrOf { op, expr: Box::new(right), - }); + })); } if self.match_token(&[TokenType::Bang, TokenType::Minus]) { let op = self.previous().clone(); let right = self.unary()?; - return Ok(Expr::Unary { + return Ok(Expr::new(ExprKind::Unary { op, right: Box::new(right), - }); + })); } self.call() @@ -546,26 +566,26 @@ impl Parser { let paren = self.consume(TokenType::RightParen, "expected ')' after arguments")?; - expr = Expr::Call { + expr = Expr::new(ExprKind::Call { callee: Box::new(expr), paren, args, - }; + }) } else if self.match_token(&[TokenType::LeftBracket]) { let index = self.expression()?; let bracket = self.consume(TokenType::RightBracket, "expected ']' after index")?; - expr = Expr::Index { + expr = Expr::new(ExprKind::Index { expr: Box::new(expr), bracket, index: Box::new(index), - } + }) } else if self.match_token(&[TokenType::Arrow]) { let field = self.consume(TokenType::Identifier, "expected field name after '->'")?; - expr = Expr::MemberAccess { + expr = Expr::new(ExprKind::MemberAccess { left: Box::new(expr), field, - }; + }) } else { break; } @@ -582,11 +602,11 @@ impl Parser { TokenType::True, TokenType::False, ]) { - Ok(Expr::Literal(self.previous().clone())) + Ok(Expr::new(ExprKind::Literal(self.previous().clone()))) } else if self.match_token(&[TokenType::LeftParen]) { let expr = self.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]) { let mut xs = vec![]; if !self.check(&TokenType::RightBracket) { @@ -599,13 +619,13 @@ impl Parser { } self.consume(TokenType::RightBracket, "expected ']' after values")?; - Ok(Expr::ArrayLiteral(xs)) + Ok(Expr::new(ExprKind::ArrayLiteral(xs))) } else if self.match_token(&[TokenType::KeywordNew]) { let struct_name = 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]) { - Ok(Expr::Variable(self.previous().clone())) + Ok(Expr::new(ExprKind::Variable(self.previous().clone()))) } else { error!( self.peek().loc, diff --git a/src/typechecker.rs b/src/typechecker.rs index f07c634..084189a 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::{ - parser::{Expr, Params, Stmt}, + parser::{Expr, ExprKind, Params, Stmt}, symbol_table::{SymbolTable, Type}, tokenizer::{TokenType, ZernError, error}, }; @@ -263,8 +263,8 @@ impl<'a> TypeChecker<'a> { } pub fn typecheck_expr(&self, env: &mut Env, expr: &Expr) -> Result { - match expr { - Expr::Binary { left, op, right } => { + match &expr.kind { + ExprKind::Binary { left, op, right } => { let left_type = self.typecheck_expr(env, left)?; match op.token_type { @@ -306,7 +306,7 @@ impl<'a> TypeChecker<'a> { _ => unreachable!(), } } - Expr::Logical { left, op, right } => { + ExprKind::Logical { left, op, right } => { expect_types!( self.typecheck_expr(env, left)?, ["bool", "i64", "ptr"], @@ -319,8 +319,8 @@ impl<'a> TypeChecker<'a> { ); Ok("bool".into()) } - Expr::Grouping(expr) => self.typecheck_expr(env, expr), - Expr::Literal(token) => match token.token_type { + ExprKind::Grouping(expr) => self.typecheck_expr(env, expr), + ExprKind::Literal(token) => match token.token_type { TokenType::IntLiteral => Ok("i64".into()), TokenType::CharLiteral => Ok("u8".into()), TokenType::StringLiteral => Ok("str".into()), @@ -328,7 +328,7 @@ impl<'a> TypeChecker<'a> { TokenType::False => Ok("bool".into()), _ => unreachable!(), }, - Expr::Unary { op, right } => { + ExprKind::Unary { op, right } => { let right_type = self.typecheck_expr(env, right)?; match op.token_type { TokenType::Minus => { @@ -342,7 +342,7 @@ impl<'a> TypeChecker<'a> { _ => unreachable!(), } } - Expr::Variable(name) => { + ExprKind::Variable(name) => { if self.symbol_table.constants.contains_key(&name.lexeme) { Ok("i64".into()) } 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)?; - match left.as_ref() { - Expr::Variable(name) => { + match &left.kind { + ExprKind::Variable(name) => { let existing_var_type = match env.get_var_type(&name.lexeme) { Some(x) => x, None => { @@ -368,7 +368,7 @@ impl<'a> TypeChecker<'a> { }; expect_type!(value_type.clone(), *existing_var_type, name.loc); } - Expr::Index { + ExprKind::Index { expr, bracket, index, @@ -377,7 +377,7 @@ impl<'a> TypeChecker<'a> { expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], 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 fields = match self.symbol_table.structs.get(&left_type) { @@ -406,12 +406,12 @@ impl<'a> TypeChecker<'a> { } Ok(value_type) } - Expr::Call { + ExprKind::Call { callee, paren, 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) { // its a function (defined/builtin/extern) if let Some(params) = fn_type.params.clone() { @@ -454,13 +454,13 @@ impl<'a> TypeChecker<'a> { Ok("any".into()) } } - Expr::ArrayLiteral(exprs) => { + ExprKind::ArrayLiteral(exprs) => { for expr in exprs { self.typecheck_expr(env, expr)?; } Ok("Array".into()) } - Expr::Index { + ExprKind::Index { expr, bracket, index, @@ -469,8 +469,8 @@ impl<'a> TypeChecker<'a> { expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc); Ok("u8".into()) } - Expr::AddrOf { op, expr } => match expr.as_ref() { - Expr::Variable(name) => { + ExprKind::AddrOf { op, expr } => match &expr.kind { + ExprKind::Variable(name) => { if self.symbol_table.functions.contains_key(&name.lexeme) { Ok("fnptr".into()) } else { @@ -481,7 +481,7 @@ impl<'a> TypeChecker<'a> { 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) { return error!( &struct_name.loc, @@ -490,7 +490,7 @@ impl<'a> TypeChecker<'a> { } Ok(struct_name.lexeme.clone()) } - Expr::MemberAccess { left, field } => { + ExprKind::MemberAccess { left, field } => { let left_type = self.typecheck_expr(env, left)?; let fields = match self.symbol_table.structs.get(&left_type) { @@ -507,7 +507,7 @@ impl<'a> TypeChecker<'a> { Ok(field.field_type.clone()) } - Expr::Cast { expr, type_name } => { + ExprKind::Cast { expr, type_name } => { self.typecheck_expr(env, expr)?; if !self.is_valid_type_name(&type_name.lexeme) { return error!(