From f30b7827b8fa787ac3e8821a7d7926f8b82b918c Mon Sep 17 00:00:00 2001 From: Janis Date: Thu, 6 Mar 2025 02:28:02 +0100 Subject: [PATCH] pulled out modules into separate files --- src/ast2/ir.rs | 842 ++++++++++ src/ast2/mod.rs | 3579 +------------------------------------------ src/ast2/parser.rs | 1915 +++++++++++++++++++++++ src/ast2/visitor.rs | 628 ++++++++ src/bin/main.rs | 2 +- 5 files changed, 3389 insertions(+), 3577 deletions(-) create mode 100644 src/ast2/ir.rs create mode 100644 src/ast2/parser.rs create mode 100644 src/ast2/visitor.rs diff --git a/src/ast2/ir.rs b/src/ast2/ir.rs new file mode 100644 index 0000000..6bf74ba --- /dev/null +++ b/src/ast2/ir.rs @@ -0,0 +1,842 @@ +use std::collections::HashMap; + +use crate::{ + ast2::{ + intern::{self, AMD64_POINTER_TYPE_INFO}, + Index, + }, + triples::{self, Inst, IR}, +}; + +#[derive(Debug, thiserror::Error)] +enum Error { + #[error("This visitor does not implement visiting this tag.")] + Unimplemented, +} + +use super::{ + intern::InternPoolWrapper as InternPool, + visitor::{AstExt, AstVisitorTrait}, + TypeCache, +}; + +struct IrBuilder { + functions: Vec, +} + +struct Function { + ir: IR, +} + +struct IrFunctionBuilder<'a> { + ir: &'a mut IR, + type_cache: &'a mut TypeCache, + ref_lookup: &'a mut HashMap, + ip: &'a InternPool, + function: Function, +} + +impl<'a> AstVisitorTrait for IrFunctionBuilder<'a> { + type Error = Error; + type Value = Option; + const UNIMPL: Self::Error = Error::Unimplemented; + + fn visit_block( + &mut self, + ast: &mut super::Ast, + idx: super::Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Block); + let (a, b) = data.as_extra_range(); + + ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| self.visit_any(ast, i)) + .try_fold((), |_, e| e.map(crate::unit))?; + + Ok(None) + } + + fn visit_place_to_value_conversion( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::PlaceToValueConversion); + let expr = data.as_index(); + + // idx's (this) type is the pointee type + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + let expr = self.visit_any(ast, expr)?.unwrap(); + + let ir = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr))); + Ok(Some(ir)) + } + + fn visit_value_to_place_conversion( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ValueToPlaceConversion); + let expr = data.as_index(); + + // expr's type is the pointee type + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + + let expr = self.visit_any(ast, expr)?.unwrap(); + + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + + let alloca = self.ir.push( + Inst::Alloca, + Some(triples::Data::new(info.size(), info.align())), + ); + + _ = self + .ir + .push(Inst::Store(ty), Some(triples::Data::new(expr, alloca))); + + Ok(Some(alloca)) + } + + fn visit_decl_ref( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::DeclRef); + let decl = data.as_index(); + + let alloca = self.ref_lookup.get(&decl).cloned().expect("declref"); + + Ok(Some(alloca)) + } + + fn visit_var_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_var_decl_common(ast, idx) + } + + fn visit_mut_var_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_var_decl_common(ast, idx) + } + + fn visit_var_assign_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_var_decl_common(ast, idx) + } + + fn visit_mut_var_assign_decl( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_var_decl_common(ast, idx) + } + + fn visit_return( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + + let ir = self.ir.push(Inst::Return, None); + Ok(Some(ir)) + } + fn visit_return_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ReturnExprStmt); + let expr = data.as_index(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + + let expr = self.visit_any(ast, expr)?.unwrap(); + + let ir = self + .ir + .push(Inst::ReturnValue(ty), Some(triples::Data::lhs(expr))); + Ok(Some(ir)) + } + + fn visit_constant( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Constant); + let (ty, value) = data.as_index_intern(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let ir = self.ir.push(Inst::Constant, Some((ty, value).into())); + + Ok(Some(ir)) + } + + fn visit_subscript_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::SubscriptExpr); + let (lhs, index) = data.as_two_indices(); + + // pointer type + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + let lhs = self.visit_any(ast, lhs)?.unwrap(); + let index = self.visit_any(ast, index)?.unwrap(); + + // TODO: make getelementptr take a variable instead of a constant index. + let ir = self.ir.push( + Inst::GetElementPtr(ty), + Some(triples::Data::new(lhs, index)), + ); + + Ok(Some(ir)) + } + + fn visit_call_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::CallExpr); + let (func, arguments) = data.as_two_indices(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + let len = self.visit_parameter_list(ast, arguments)?.unwrap(); + _ = self.ir.push(Inst::InlineType(ty), None); + let end = self.ir.nodes.len() as u32; + + let func = self.visit_any(ast, func)?.unwrap(); + + let result = self + .ir + .push(Inst::Call(func), Some(triples::Data::new(end - len, end))); + + Ok(Some(result)) + } + + fn visit_argument( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Argument); + let expr = data.as_index(); + + let arg = self.visit_any(ast, expr)?.unwrap(); + + // let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + // self.ir.push(Inst::Argument(ty), Some(triples::Data::lhs(arg))); + + Ok(Some(arg)) + } + + // fn visit_named_argument( + // &mut self, + // ast: &mut super::Ast, + // idx: Index, + // ) -> Result { + // todo!() + // } + + fn visit_argument_list( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ArgumentList); + let (a, b) = data.as_extra_range(); + + let args = ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| { + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, i); + let arg = self.visit_any_argument(ast, i)?.unwrap(); + Ok((ty, arg)) + }) + .collect::, _>>()?; + let count = args.len(); + for (ty, arg) in args { + _ = self + .ir + .push(Inst::Argument(ty), Some(triples::Data::lhs(arg))); + } + // .try_fold((), |_, e| e.map(crate::unit))?; + + Ok(Some(count as u32)) + } + + fn visit_block_trailing_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::BlockTrailingExpr); + + let (a, b) = data.as_extra_range(); + + let expr = ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| self.visit_any(ast, i)) + // the last node is the trailing + .try_fold(None, |_, e| e)?; + + Ok(expr) + } + + fn visit_function_proto( + &mut self, + ast: &mut super::Ast, + idx: super::Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionProto); + + let (_, extra) = data.as_intern_and_extra_offset(); + let (_return_type, parameter_list) = ( + Index::from_u32(ast.extra[extra]).unwrap(), + Index::from_u32(ast.extra[extra + 1]).unwrap(), + ); + + self.visit_parameter_list(ast, parameter_list)?; + // push parameters to ir + Ok(None) + } + + fn visit_parameter_list( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ParameterList); + let (a, b) = data.as_extra_range(); + + ast.extra[a..b] + .to_vec() + .into_iter() + .map(|i| Index::from_u32(i).unwrap()) + .map(|i| self.visit_parameter(ast, i)) + .try_fold((), |_, e| e.map(crate::unit))?; + + Ok(None) + } + + fn visit_parameter( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Parameter); + let (ty, _name) = data.as_index_intern(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + let ir = self.ir.push( + Inst::Parameter(ty), + Some(triples::Data::new(info.size(), info.align())), + ); + self.ref_lookup.insert(idx, ir); + + Ok(None) + } + + fn visit_address_of_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::AddressOf); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + let expr = self.visit_any(ast, expr)?.unwrap(); + let r = self + .ir + .push(Inst::GetElementPtr(ty), Some(triples::Data::new(expr, 0))); + + Ok(Some(r)) + } + + fn visit_assign( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Assign); + let (dst, src) = data.as_two_indices(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + let dst = self.visit_any(ast, dst)?.unwrap(); + let src = self.visit_any(ast, src)?.unwrap(); + + let ir = self + .ir + .push(Inst::Store(ty.into()), Some(triples::Data::new(src, dst))); + + Ok(Some(ir)) + } + + fn visit_explicit_cast_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::ExplicitCast); + let (lhs, ty) = data.as_two_indices(); + + let lty = ast.get_type_of_node(&self.ip, &mut self.type_cache, lhs); + let rty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); + + let lhs = self.visit_any(ast, lhs)?.unwrap(); + + // TODO: if bitwidth is the same, then this is a noop? + let cast = self + .ir + .push(Inst::ExplicitCast(lty, rty), Some(triples::Data::lhs(lhs))); + + Ok(Some(cast)) + } + + fn visit_if_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::IfExpr); + let (cond, body) = data.as_two_indices(); + + let cond = self.visit_any(ast, cond)?.unwrap(); + let br = self.ir.push(Inst::Branch(cond), None); + + let lbody = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + _ = self.visit_any(ast, body); + let jmp = self.ir.push(Inst::Jump, None); + let skip = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + self.ir.data[br as usize] = Some(triples::Data::new(lbody, skip)); + self.ir.data[jmp as usize] = Some(triples::Data::lhs(skip)); + + Ok(Some(br)) + } + + fn visit_if_else_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::IfElseExpr); + let (cond, extra) = data.as_index_and_extra_offset(); + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + let [a, b] = ast.extra[extra..][..2] else { + unreachable!() + }; + + let cond = self.visit_any(ast, cond)?.unwrap(); + let br = self.ir.push(Inst::Branch(cond), None); + + let la = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + let a = self.visit_any(ast, Index::from_u32(a).unwrap())?.unwrap(); + let jmpa = self.ir.push(Inst::Jump, None); + + let lb = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + let b = self.visit_any(ast, Index::from_u32(b).unwrap())?.unwrap(); + let jmpb = self.ir.push(Inst::Jump, None); + + let lphi = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + let phi = if ty == intern::Index::VOID { + br + } else { + self.ir.push(Inst::Phi2(ty), Some(triples::Data::new(a, b))) + }; + + self.ir.data[br as usize] = Some(triples::Data::new(la, lb)); + self.ir.data[jmpa as usize] = Some(triples::Data::lhs(lphi)); + self.ir.data[jmpb as usize] = Some(triples::Data::lhs(lphi)); + + Ok(Some(phi)) + } + + fn visit_deref_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Not); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + let expr = self.visit_any(ast, expr)?.unwrap(); + let not = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr))); + + Ok(Some(not)) + } + + fn visit_not_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Not); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + let expr = self.visit_any(ast, expr)?.unwrap(); + let not = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(expr))); + + Ok(Some(not)) + } + + fn visit_negate_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Negate); + let expr = data.as_index(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); + let expr = self.visit_any(ast, expr)?.unwrap(); + let not = self + .ir + .push(Inst::Negate(ty), Some(triples::Data::lhs(expr))); + + Ok(Some(not)) + } + + fn visit_or_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Or); + let (a, b) = data.as_two_indices(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + // TODO: make this an error instead of a panic + let a = self.visit_any(ast, a)?.unwrap(); + let not_a = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(a))); + + // branch taken if a + let br = self.ir.push(Inst::Branch(not_a), None); + let lb = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + let b = self.visit_any(ast, b)?.unwrap(); + let jmp = self.ir.push(Inst::Jump, None); + + let la = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + self.ir.data[br as usize] = Some(triples::Data::new(lb, la)); + self.ir.data[jmp as usize] = Some(triples::Data::lhs(la)); + + let or = self.ir.push( + Inst::Phi2(intern::Index::BOOL), + Some(triples::Data::new(a, b)), + ); + + Ok(Some(or)) + } + + fn visit_and_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + let data = ast.expect_node_data_for_tag(idx, super::Tag::Or); + let (a, b) = data.as_two_indices(); + + // TODO: make this an error instead of a panic + let a = self.visit_any(ast, a)?.unwrap(); + + // branch taken if a + let br = self.ir.push(Inst::Branch(a), None); + + let lb = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + let b = self.visit_any(ast, b)?.unwrap(); + + let skip = self + .ir + .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); + + self.ir.data[br as usize] = Some(triples::Data::new(lb, skip)); + let and = self.ir.push( + Inst::Phi2(intern::Index::BOOL), + Some(triples::Data::new(a, b)), + ); + + Ok(Some(and)) + } + + fn visit_add_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_sub_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_div_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_rem_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_mul_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_bitand_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_bitor_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_bitxor_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_eq_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_neq_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_lt_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_gt_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_le_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_ge_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_shl_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } + fn visit_shr_expr( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result { + self.visit_binop_expr(ast, idx) + } +} + +impl IrFunctionBuilder<'_> { + fn visit_var_decl_common( + &mut self, + ast: &mut super::Ast, + idx: Index, + ) -> Result, Error> { + let (tag, data) = ast.get_node_tag_and_data(idx); + let (a, b) = data.as_extra_range(); + + let range = &ast.extra[a..b]; + let _name = range.get(0).unwrap(); + + let (expr, typed_index) = match tag { + super::Tag::VarDecl | super::Tag::MutVarDecl => { + let typed_index = range + .get(1) + .cloned() + .map(Index::from_u32) + .flatten() + .unwrap(); + (None, typed_index) + } + super::Tag::VarDeclAssignment | super::Tag::MutVarDeclAssignment => { + let expr = range + .get(1) + .cloned() + .map(Index::from_u32) + .flatten() + .unwrap(); + let typed_index = range + .get(2) + .cloned() + .map(Index::from_u32) + .flatten() + .unwrap_or(expr); + (Some(expr), typed_index) + } + _ => unreachable!(), + }; + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, typed_index); + let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); + + let alloca = self.ir.push( + Inst::Alloca, + Some(triples::Data::new(info.size(), info.align())), + ); + + if let Some(idx) = expr { + let expr = self.visit_any(ast, idx)?.unwrap(); + _ = self + .ir + .push(Inst::Store(ty), Some(triples::Data::new(expr, alloca))); + } + + self.ref_lookup.insert(idx, alloca); + + Ok(Some(alloca)) + } + + /// handles all binary operations that don't short circuit and visit + /// both lhs and rhs. + fn visit_binop_expr(&mut self, ast: &mut super::Ast, idx: Index) -> Result, Error> { + use triples::Data; + let (tag, data) = ast.get_node_tag_and_data(idx); + let (lhs, rhs) = data.as_two_indices(); + + let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); + + // TODO: make this an error instead of a panic + let lhs = self.visit_any(ast, lhs)?.unwrap(); + let rhs = self.visit_any(ast, rhs)?.unwrap(); + + let (inst, data) = match tag { + super::Tag::BitOr => (Inst::BitOr(ty), Data::new(lhs, rhs)), + super::Tag::BitXOr => (Inst::BitOr(ty), Data::new(lhs, rhs)), + super::Tag::BitAnd => (Inst::BitOr(ty), Data::new(lhs, rhs)), + + super::Tag::Eq => (Inst::Eq(ty), Data::new(lhs, rhs)), + super::Tag::NEq => (Inst::Neq(ty), Data::new(lhs, rhs)), + super::Tag::Lt => (Inst::Lt(ty), Data::new(lhs, rhs)), + super::Tag::Gt => (Inst::Gt(ty), Data::new(lhs, rhs)), + super::Tag::Le => (Inst::Le(ty), Data::new(lhs, rhs)), + super::Tag::Ge => (Inst::Ge(ty), Data::new(lhs, rhs)), + + super::Tag::Shl => (Inst::ShiftLeft(ty), Data::new(lhs, rhs)), + super::Tag::Shr => (Inst::ShiftRight(ty), Data::new(lhs, rhs)), + super::Tag::Add => (Inst::Add(ty), Data::new(lhs, rhs)), + super::Tag::Sub => (Inst::Sub(ty), Data::new(lhs, rhs)), + super::Tag::Div => (Inst::Div(ty), Data::new(lhs, rhs)), + super::Tag::Rem => (Inst::Rem(ty), Data::new(lhs, rhs)), + super::Tag::Mul => (Inst::Mul(ty), Data::new(lhs, rhs)), + _ => panic!("not a binop"), + }; + + Ok(Some(self.ir.push(inst, Some(data)))) + } +} + +impl AstVisitorTrait for IrBuilder { + type Value = (); + type Error = Error; + const UNIMPL: Self::Error = Error::Unimplemented; + + fn visit_function_decl( + &mut self, + ast: &mut super::Ast, + idx: super::Index, + ) -> Result<(), Self::Error> { + let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionDecl); + let (proto, block) = data.as_two_indices(); + + // visit proto + + // visit block + + todo!() + } +} diff --git a/src/ast2/mod.rs b/src/ast2/mod.rs index b086b39..a723530 100644 --- a/src/ast2/mod.rs +++ b/src/ast2/mod.rs @@ -14,6 +14,9 @@ use crate::{ }; pub mod intern; +pub mod ir; +pub mod parser; +pub mod visitor; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Tag { @@ -2190,248 +2193,6 @@ where } } -use visitor::AstVisitor; - -impl Ast { - pub fn visitor_mut(&mut self) -> AstVisitor<&mut Self> { - AstVisitor { - scopes: vec![], - nodes: self - .get_root_file_indices() - .map(|i| visitor::A::PushChildren(i)) - .collect(), - ast: self, - rev: false, - } - } - pub fn visitor_rev_mut(&mut self) -> AstVisitor<&mut Self> { - AstVisitor { - scopes: vec![], - nodes: self - .get_root_file_indices() - .map(|i| visitor::A::PushChildren(i)) - .collect(), - ast: self, - rev: true, - } - } - - pub fn visitor(&self) -> AstVisitor<&Self> { - AstVisitor { - scopes: vec![], - nodes: self - .get_root_file_indices() - .map(|i| visitor::A::PushChildren(i)) - .collect(), - ast: self, - rev: false, - } - } -} - -pub mod visitor { - use super::*; - pub trait AstExt { - fn get_node_children(&self, node: Index) -> Vec; - fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data); - } - - impl AstExt for &Ast { - fn get_node_children(&self, node: Index) -> Vec { - Ast::get_node_children(self, node) - } - - fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) { - (self.tags[node], self.datas[node]) - } - } - impl AstExt for &mut Ast { - fn get_node_children(&self, node: Index) -> Vec { - Ast::get_node_children(self, node) - } - - fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) { - (self.tags[node], self.datas[node]) - } - } - - pub struct AstVisitor { - pub(super) ast: AstT, - pub(super) scopes: Vec, - pub(super) nodes: Vec, - pub(super) rev: bool, - } - - impl AstVisitor - where - AstT: AstExt, - { - pub fn visit< - F: FnMut(&mut AstT, &[Index], Index, Tag, Data), - G: FnMut(&mut AstT, &[Index], Index, Tag, Data), - >( - &mut self, - mut pre: F, - mut post: G, - ) { - while let Some(node) = self.nodes.pop() { - match node { - A::PushChildren(i) => { - self.nodes.push(A::PopSelf(i)); - let children_iter = self - .ast - .get_node_children(i) - .into_iter() - .map(|i| A::PushChildren(i)); - // inverse because we are popping from the end - if !self.rev { - self.nodes.extend(children_iter.rev()) - } else { - self.nodes.extend(children_iter) - }; - - let (tag, data) = self.ast.get_node_tag_and_data(i); - - let _ = pre(&mut self.ast, &self.scopes, i, tag, data); - - match tag { - Tag::File - | Tag::FunctionDecl - | Tag::GlobalDecl - | Tag::Block - | Tag::BlockTrailingExpr => { - self.scopes.push(i); - } - _ => {} - } - } - A::PopSelf(i) => { - // already popped. - let (tag, data) = self.ast.get_node_tag_and_data(i); - - let _ = post(&mut self.ast, &self.scopes, i, tag, data); - - match tag { - Tag::File - | Tag::FunctionDecl - | Tag::GlobalDecl - | Tag::Block - | Tag::BlockTrailingExpr => { - self.scopes.pop(); - } - _ => {} - } - } - } - } - } - pub fn visit_pre(&mut self, mut cb: F) { - while let Some(node) = self.nodes.pop() { - match node { - A::PushChildren(i) => { - self.nodes.push(A::PopSelf(i)); - let children_iter = self - .ast - .get_node_children(i) - .into_iter() - .map(|i| A::PushChildren(i)); - // inverse because we are popping from the end - if !self.rev { - self.nodes.extend(children_iter.rev()) - } else { - self.nodes.extend(children_iter) - }; - - let (tag, data) = self.ast.get_node_tag_and_data(i); - - let _ = cb(&mut self.ast, &self.scopes, i, tag, data); - - match tag { - Tag::File - | Tag::FunctionDecl - | Tag::GlobalDecl - | Tag::Block - | Tag::BlockTrailingExpr => { - self.scopes.push(i); - } - _ => {} - } - } - A::PopSelf(i) => { - // already popped. - let (tag, _data) = self.ast.get_node_tag_and_data(i); - - match tag { - Tag::File - | Tag::FunctionDecl - | Tag::GlobalDecl - | Tag::Block - | Tag::BlockTrailingExpr => { - self.scopes.pop(); - } - _ => {} - } - } - } - } - } - pub fn visit_post(&mut self, mut cb: F) { - while let Some(node) = self.nodes.pop() { - match node { - A::PushChildren(i) => { - self.nodes.push(A::PopSelf(i)); - let children_iter = self - .ast - .get_node_children(i) - .into_iter() - .map(|i| A::PushChildren(i)); - if self.rev { - self.nodes.extend(children_iter.rev()) - } else { - self.nodes.extend(children_iter) - }; - - let (tag, _data) = self.ast.get_node_tag_and_data(i); - - match tag { - Tag::File - | Tag::FunctionDecl - | Tag::GlobalDecl - | Tag::Block - | Tag::BlockTrailingExpr => { - self.scopes.push(i); - } - _ => {} - } - } - A::PopSelf(i) => { - // already popped. - let (tag, data) = self.ast.get_node_tag_and_data(i); - - let _ = cb(&mut self.ast, &self.scopes, i, tag, data); - - match tag { - Tag::File - | Tag::FunctionDecl - | Tag::GlobalDecl - | Tag::Block - | Tag::BlockTrailingExpr => { - self.scopes.pop(); - } - _ => {} - } - } - } - } - } - } - - pub enum A { - PushChildren(Index), - PopSelf(Index), - } -} - pub struct AstRenderer<'a> { ast: &'a Ast, #[allow(dead_code)] @@ -2503,3337 +2264,3 @@ impl<'a> AstRenderer<'a> { Ok(()) } } - -pub mod ast_gen { - - use intern::{PointerFlags, SimpleType}; - use itertools::Itertools; - use num_bigint::{BigInt, BigUint}; - - use crate::{ - common::from_lo_hi_dwords, - comptime, - lexer::{Radix, TokenItem, TokenIterator}, - symbol_table::syms2::SymbolKind, - tokens::PRECEDENCE_MAP, - variant, - }; - - use super::*; - - #[derive(Debug)] - pub struct ErrorInfo { - error: ParseError, - loc: SourceLocation, - } - - #[derive(Debug)] - pub struct Parser { - pub ast: Ast, - pub intern: InternPool, - pub syms: crate::symbol_table::syms2::Symbols, - scopes: Vec, - pub errors: Vec, - } - - type ParseResult = core::result::Result; - - impl Display for Parser { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.display().render(f) - } - } - - impl Parser { - pub fn new() -> Parser { - Self { - ast: Ast::new(), - intern: InternPool::new(), - syms: crate::symbol_table::syms2::Symbols::new(), - scopes: Vec::new(), - errors: Vec::new(), - } - } - - pub fn display(&self) -> AstRenderer<'_> { - AstRenderer::new(&self.ast, &self.intern, &self.syms) - } - - pub fn node_display(&self, node: Index) -> NodeDisplay<'_> { - NodeDisplay { - node, - ast: &self.ast, - ip: &self.intern, - } - } - - pub fn create_comptime_folding_graph(&mut self, pointer_bits: u16) { - let mut type_cache = TypeCache::new(); - let mut cache = ComptimeCache::default(); - let mut nodes = self.ast.get_root_file_indices().collect::>(); - while let Some(node) = nodes.pop() { - if !self.ast.is_node_comptime_evaluable(&mut cache, node) { - nodes.extend(self.ast.get_node_children(node)); - } - } - - let mut node_map = Vec::::new(); - let edges = cache - .inner - .iter() - .filter(|(_, b)| **b) - .map(|(e, _)| self.ast.get_node_children(*e).into_iter().map(|d| (*e, d))) - .flatten() - // .map(|(a, b)| (a.into_u32(), b.into_u32())) - .map(|(a, b)| { - ( - node_map.iter().position(|&i| i == a).unwrap_or_else(|| { - node_map.push(a); - node_map.len() - 1 - }) as u32, - node_map.iter().position(|&i| i == b).unwrap_or_else(|| { - node_map.push(b); - node_map.len() - 1 - }) as u32, - ) - }) - .collect::>(); - - let extra_nodes = cache - .inner - .iter() - .filter(|(_, b)| **b) - .filter_map(|(i, _)| (!node_map.contains(i)).then(|| node_map.push(*i))) - .count(); - - eprintln!("cache: {cache:?}"); - eprintln!("node_map: {node_map:?}"); - eprintln!("edges: {edges:?}"); - - let mut graph = petgraph::stable_graph::StableDiGraph::<(), ()>::from_edges(edges); - for _ in 0..extra_nodes { - graph.add_node(()); - } - std::fs::write( - "comptime_graph.dot", - &format!( - "{:?}", - petgraph::dot::Dot::with_attr_getters( - &graph, - &[], - &|_graph, _edgeref| { "".to_string() }, - &|_graph, noderef| { - format!("label = \"{}\"", node_map[noderef.0.index()]) - } - ) - ), - ) - .expect("writing comptime graph repr"); - - while let Some(external) = graph.externals(petgraph::Direction::Outgoing).next() { - let node = node_map[external.index()]; - if !(self.ast.tags[node] == Tag::Constant || self.ast.tags[node].is_type()) - && self.ast.tags[node].is_expr() - { - eprintln!("folding {node}:\n{}", self.node_display(node)); - let value = self - .ast - .comptime_value_of_node(&self.intern, pointer_bits, &mut type_cache, node) - .expect(&format!("{node} has value of None?")); - let (value, ty) = comptime_number_to_interned_type_and_value( - &mut self.intern, - pointer_bits, - value, - ); - let ty = self.ast.push_interend_type(ty, self.ast.get_loc(node)); - self.ast.set_tag_data_source_loc( - node, - Tag::Constant, - Data::index_and_intern(ty, value), - self.ast.get_loc(node), - ); - } else { - eprintln!("rejecting {node}:\n{}", self.node_display(node)); - } - // comptime fold node - graph.remove_node(external); - } - } - - /// folds more AST-patterns into structures that are easier to build the IR with - pub fn fold_more_patterns(&mut self) { - use visitor::AstExt; - self.ast.visitor_mut().visit_post(|ast, _, _i, tag, data| { - match tag { - // normalise functions with block-with-trailing-expr into block - Tag::FunctionDecl => { - let (_, block) = data.as_two_indices(); - - let (block_tag, block_data) = ast.get_node_tag_and_data(block); - if block_tag == Tag::BlockTrailingExpr { - let (_, end) = block_data.as_extra_range(); - let end = end - 1; - let expr = Index::from_u32(ast.extra[end]).unwrap(); - let loc = ast.get_loc(expr); - let ret = ast.push_ret(Some(expr), loc); - // modify last element in place to be a return instruction - ast.extra[end] = ret.as_u32(); - ast.tags[block] = Tag::Block; - eprintln!("folding ({block}): {block_tag:?} into Tag::Block"); - eprintln!("expr: {expr:?}"); - } - } - _ => {} - } - }); - } - - pub fn intern_types(&mut self) { - self.ast.visitor_mut().visit_post(|ast, _, i, tag, data| { - match tag { - Tag::ArrayType => { - let (length, pointee) = data.as_two_indices(); - let pointee = - ast.datas[pointee].as_intern(); - variant!( self.intern.get_key(pointee) => intern::Key::PointerType { pointee, flags }); - - // get interened value from constant node - let length = { - let value = ast.datas[length] - .as_index_intern() - .1; - - match self.intern.get_key(value) { - intern::Key::SIntSmall { bits } => { - bits as u32 - } - intern::Key::UIntSmall { bits } => { - bits as u32 - } - intern::Key::SInt64 { bits } => { - bits as u32 - } - intern::Key::UInt64 { bits } => { - bits as u32 - } - intern::Key::NegativeInt { bigint } - | intern::Key::PositiveInt { bigint } => { - bigint - .iter_u32_digits() - .next() - .unwrap_or(0) - } - _ => 0, - } - }; - - let ty = self.intern.get_array_type( - pointee, - Some(flags), - length, - ); - ast.tags[i] = Tag::InternedType; - ast.datas[i] = Data::intern(ty); - } - Tag::PointerType => { - let (pointee, flags) = - data.as_index_and_extra_offset(); - let pointee = - ast.datas[pointee].as_intern(); - let ty = self.intern.get_pointer_type( - pointee, - Some(PointerFlags::unpack(flags as u8)), - ); - ast.tags[i] = Tag::InternedType; - ast.datas[i] = Data::intern(ty); - } - Tag::TypeDeclRef => { - let decl = data.as_index(); - let (name, _) = ast.datas[decl] - .as_intern_and_extra_offset(); - - let ty = - self.intern.get_struct_type(name, decl); - ast.tags[i] = Tag::InternedType; - ast.datas[i] = Data::intern(ty); - } - Tag::FunctionProto => { - let (_, i) = data.as_intern_and_extra_offset(); - let (return_type, parameter_list) = ( - Index::from_u32(ast.extra[i]).unwrap(), - Index::from_u32(ast.extra[i + 1]).unwrap(), - ); - let return_type = ast.get_type_of_node( - &self.intern, - &mut TypeCache::new(), - return_type - ); - let parameters = { - let (a, b) = ast.datas - [parameter_list] - .as_extra_range(); - ast.extra[a..b].iter() - .map(|&i| Index::from_u32(i).unwrap()) - .map(|i| { - // i is index to a parameter, a parameter is (index, intern) - let ty = ast.datas[i] - .as_index_intern() - .0; - ast.datas[ty].as_intern() - }) - }; - - self.intern - .get_function_type(return_type, parameters); - } - // Tag::VarDeclAssignment|Tag::MutVarDeclAssignment| - // Tag::VarDecl | Tag::MutVarDecl => { - // let (a,b) = - // data.as_extra_range(); - // let extra = &self.ast.extra[a..b]; - // let typed = Index::from_u32( - // extra.last().unwrap()).unwrap(); - // self.ast.get_type_of_node(&self.intern, cache, index) - // } - Tag::StructDecl => { - let (name, offset) = - data.as_intern_and_extra_offset(); - let flags = - StructFlags::unpack(ast.extra[offset]); - - let types = (offset + 1) - ..(offset + 1 + flags.num_fields as usize); - let names = - (offset + 1 + flags.num_fields as usize) - ..(offset - + 1 - + flags.num_fields as usize * 2); - - let types = ast.extra[types] - .iter() - .map(|&i| Index::from_u32(i).unwrap()) - .map(|i| { - ast.datas[i].as_intern() - }); - let names = ast.extra[names] - .iter() - .map(|&i| intern::Index::from_u32(i)); - - self.intern.insert_or_replace_struct_type( - name, - i, - flags.packed, - flags.c_like, - names.zip(types), - ); - } - _ => {} - } - }); - } - - pub fn resolve_decl_refs(&mut self) { - self.ast - .visitor_rev_mut() - .visit_post(|ast, _, node, tag, _| { - match tag { - Tag::TypeDeclRefUnresolved => { - let (scope, name) = ast.datas[node].as_index_intern(); - // look in my_scope - if let Some((_, decl)) = - self.syms - .find_type_symbol(scope, name, ast.source_locs[node]) - { - ast.resolve_type_ref(node, decl) - }; - } - Tag::DeclRefUnresolved => { - let (scope, name) = ast.datas[node].as_index_intern(); - - // look in my_scope - if let Some((key, decl)) = - self.syms.find_symbol(scope, name, ast.source_locs[node]) - { - ast.resolve_decl_ref( - node, - decl, - Option::::from(key.kind().unwrap()).unwrap(), - ) - }; - } - _ => {} - } - }); - } - - fn current_scope(&self) -> Index { - self.scopes.last().cloned().unwrap() - } - - fn parse_ident(&mut self, tokens: &mut TokenIterator) -> Result { - let ident = tokens.expect_token(Token::Ident).map_err(|_| ErrorInfo { - error: ParseError::ExpectedIdent, - loc: tokens.current_source_location(), - })?; - - let name = self.intern.get_or_insert(intern::Key::String { - str: ident.lexeme(), - }); - - Ok(name) - } - - fn parse_pointer(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - tokens.eat_token(Token::Star).ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Star), - loc: tokens.current_source_location(), - })?; - - let &[cnst, vol, noalias] = - &tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3] - else { - unreachable!() - }; - let pointee = self.parse_type(tokens)?; - - Ok(self - .ast - .push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc)) - } - - /// [LENGTH]const? volatile? noalias? TYPE - fn parse_array_type(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - let length_expr = self.parse_bracketed(tokens, |this, tokens| { - this.parse_value_expr(tokens) - // let next = tokens.peek_token().ok_or(ErrorInfo { - // error: ParseError::UnexpectedEndOfTokens, - // loc: tokens.current_source_location(), - // })?; - // match next.token() { - // Token::IntegerBinConstant - // | Token::IntegerHexConstant - // | Token::IntegerOctConstant - // | Token::IntegerConstant => { - // _ = tokens.next(); - // Ok(this.parse_integral_constant(&next, next.source_location())) - // } - // _ => Err(ErrorInfo { - // error: ParseError::ExpectedConstantLiteral, - // loc: tokens.current_source_location(), - // }), - // } - })?; - - let &[cnst, vol, noalias] = - &tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3] - else { - unreachable!() - }; - - let pointee = self.parse_type(tokens)?; - let pointer = - self.ast - .push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc); - - Ok(self.ast.push_array_type(length_expr, pointer, loc)) - } - - fn parse_simple_type(&mut self, token: Token) -> Option { - match token { - Token::Void => Some(self.intern.get_assume_present(&intern::Key::SimpleType { - ty: SimpleType::Void, - })), - Token::Bool => Some(self.intern.get_assume_present(&intern::Key::SimpleType { - ty: SimpleType::Bool, - })), - Token::F32 => Some(self.intern.get_assume_present(&intern::Key::SimpleType { - ty: SimpleType::F32, - })), - Token::F64 => Some(self.intern.get_assume_present(&intern::Key::SimpleType { - ty: SimpleType::F64, - })), - Token::USize => Some(self.intern.get_assume_present(&intern::Key::SimpleType { - ty: SimpleType::USize, - })), - Token::ISize => Some(self.intern.get_assume_present(&intern::Key::SimpleType { - ty: SimpleType::ISize, - })), - _ => None, - } - } - - fn try_parse_integral_type( - &mut self, - typename: &str, - ) -> Result, ParseError> { - let mut iter = typename.chars().peekable(); - let signed = match iter.next() { - Some('u') => false, - Some('i') => true, - _ => { - return Ok(None); - } - }; - - // need 1 digit for an integral type - if iter.peek().map(|&c| crate::common::is_digit(c)) != Some(true) { - return Ok(None); - } - - // need no nondigits after digits - if iter - .clone() - .skip_while(|&c| crate::common::is_digit(c)) - .next() - .is_some() - { - return Ok(None); - } - - let mut bits = 0u16; - loop { - let Some(digit) = iter.next().map(|c| c as u8 - b'0') else { - break; - }; - - match bits - .checked_mul(10) - .and_then(|bits| bits.checked_add(digit as u16)) - { - Some(val) => { - bits = val; - } - None => { - // this IS an integral type, but it is bigger than u/i65535 - return Err(ParseError::IntegralTypeTooWide); - } - } - } - - Ok(Some(self.intern.get_int_type(signed, bits))) - } - - fn parse_integral_constant_inner( - &mut self, - item: &TokenItem, - ) -> (intern::Index, intern::Index) { - let radix = Radix::from_token(item.token()).unwrap(); - - let mut chars = item.lexeme().char_indices(); - match radix { - Radix::Dec => {} - _ => { - _ = chars.advance_by(2); - } - } - - let digits = chars - .take_while_ref(|&(_, c)| radix.is_digit()(c) || c == '_') - .filter(|&(_, c)| c != '_') - .map(|(_, c)| c) - .collect::>(); - - let value = comptime::bigint::parse_bigint(digits.into_iter(), radix); - - let ty = match chars.clone().next() { - Some((i, 'u')) | Some((i, 'i')) => self - .try_parse_integral_type(&item.lexeme()[i..]) - .expect("invalid integral type??"), - _ => None, - }; - - let interned = match value.len() { - ..1 => { - let bits = value.get(0).cloned().unwrap_or(0); - self.intern.get_or_insert(intern::Key::UIntSmall { bits }) - } - ..2 => { - let lo = value.get(0).cloned().unwrap_or(0); - let hi = value.get(1).cloned().unwrap_or(0); - let bits = from_lo_hi_dwords(lo, hi); - self.intern.get_or_insert(intern::Key::UInt64 { bits }) - } - _ => { - let bigint = BigInt::from_biguint(num_bigint::Sign::Plus, BigUint::new(value)); - self.intern - .get_or_insert(intern::Key::PositiveInt { bigint }) - } - }; - - let ty = ty.unwrap_or(self.intern.get_comptime_int_type()); - (interned, ty) - } - - fn parse_integral_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index { - let (interned, ty) = self.parse_integral_constant_inner(item); - let ty = self.ast.push_interend_type(ty, loc); - return self.ast.push_constant(interned, ty, loc); - } - - fn parse_floating_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index { - let lexeme = item.lexeme(); - let lexeme = lexeme - .strip_suffix("f32") - .map(|l| (l, self.intern.get_f32_type())) - .unwrap_or( - lexeme - .strip_suffix("f64") - .map(|l| (l, self.intern.get_f64_type())) - .unwrap_or((lexeme, self.intern.get_f64_type())), - ); - - let bits = if lexeme.1 == self.intern.get_f32_type() { - self.intern.get_or_insert(intern::Key::F32 { - bits: lexeme.0.parse::().unwrap(), - }) - } else { - self.intern.get_or_insert(intern::Key::F64 { - bits: lexeme.0.parse::().unwrap(), - }) - }; - - let ty = self.ast.push_interend_type(lexeme.1, loc); - return self.ast.push_constant(bits, ty, loc); - } - - /// TYPE <- - /// * TYPE - /// IDENTIFIER - /// SIMPLE_TYPE - /// [ TYPE ; CONSTANT_EXPR ] - /// INTEGRAL_TYPE // u[0..65535] | i[0..65535] - fn parse_type(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - match tokens - .peek_token() - .ok_or(ErrorInfo { - error: ParseError::ExpectedTypeName, - loc: tokens.current_source_location(), - })? - .token() - { - Token::Star => self.parse_pointer(tokens), - Token::OpenSquareBracket => self.parse_array_type(tokens), - Token::Ident => { - let token = tokens.next().unwrap(); - match self - .try_parse_integral_type(token.lexeme()) - .map_err(|error| ErrorInfo { - error, - loc: token.source_location(), - })? { - Some(int) => Ok(self.ast.push_interend_type(int, loc)), - None => { - let name = self.intern.get_or_insert(intern::Key::String { - str: token.lexeme(), - }); - // TODO: this will cause issues with redefinitions of types with the same name - // and actually, make type into a proper node of the ast - Ok(self - .ast - .push_type_ref_unresolved(self.current_scope(), name, loc)) - } - } - } - token => { - let ty = self.parse_simple_type(token).ok_or(ErrorInfo { - error: ParseError::ExpectedTypeName, - loc: tokens.current_source_location(), - })?; - _ = tokens.next(); - - Ok(self.ast.push_interend_type(ty, loc)) - } - } - } - - /// GLOBAL_DECL <- - /// const IDENTIFIER: TYPENAME = EXPR; - fn parse_const_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let err = 'blk: { - let loc = tokens.current_source_location(); - let Some(_) = tokens.eat_token(Token::Const) else { - break 'blk ErrorInfo { - error: ParseError::ExpectedToken(Token::Const), - loc, - }; - }; - - let ident = match self.parse_ident(tokens) { - Ok(i) => i, - Err(err) => { - break 'blk err; - } - }; - - let Some(_) = tokens.eat_token(Token::Colon) else { - return Err(ErrorInfo { - error: ParseError::ExpectedToken(Token::Colon), - loc, - }); - }; - - let typename = match self.parse_type(tokens) { - Ok(i) => i, - Err(err) => { - break 'blk err; - } - }; - - let Some(_) = tokens.eat_token(Token::Equal) else { - break 'blk ErrorInfo { - error: ParseError::ExpectedToken(Token::Equal), - loc: tokens.current_source_location(), - }; - }; - - let expr = match self.parse_value_expr(tokens) { - Ok(i) => i, - Err(err) => { - break 'blk err; - } - }; - - let Some(_) = tokens.eat_token(Token::Semi) else { - break 'blk ErrorInfo { - error: ParseError::ExpectedToken(Token::Semi), - loc: tokens.current_source_location(), - }; - }; - - let decl = self.ast.push_global_decl(ident, typename, expr, loc); - self.syms - .insert_symbol(self.current_scope(), ident, SymbolKind::Const, decl); - - return Ok(decl); - }; - - tokens.advance_past_semi().ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Semi), - loc: tokens.current_source_location(), - })?; - - Ok(self.ast.push_error(err.error, err.loc)) - } - - /// FUNCTION_PROTO <- - /// fn IDENTIFIER () - /// fn IDENTIFIER () -> TYPENAME - /// fn IDENTIFIER ( PARAMETER_LIST ,? ) - /// fn IDENTIFIER ( PARAMETER_LIST ,? ) -> TYPENAME - fn parse_fn_proto( - &mut self, - tokens: &mut TokenIterator, - ) -> ParseResult<(Index, intern::Index)> { - let loc = tokens.current_source_location(); - let _ = tokens.eat_token(Token::Fn).ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Fn), - loc, - })?; - - let ident = self.parse_ident(tokens)?; - - let parameters = self.parse_parenthesised(tokens, |this, tokens| { - if tokens.is_next_token(Token::CloseParens) { - Ok(this.ast.push_parameter_list([], loc)) - } else { - this.parse_parameter_list(tokens) - } - })?; - - let return_type = if let Some(_) = tokens.eat_token(Token::MinusGreater) { - self.parse_type(tokens)? - } else { - self.ast.push_interend_type( - self.intern.get_void_type(), - tokens.current_source_location(), - ) - }; - - let decl = self.ast.push_fn_proto(ident, return_type, parameters, loc); - - Ok((decl, ident)) - } - - fn parse_fn_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - let func = self.ast.reserve_node(Kind::Function); - - self.push_scope(func, intern::Index::invalid()); - - let (proto, ident) = self.parse_fn_proto(tokens).map_err(|e| { - self.pop_scope(); - e - })?; - let body = self - .parse_block(tokens) - .map(|pv| self.convert_to_value_expr(pv)) - .map_err(|e| { - self.pop_scope(); - e - })?; - - self.pop_scope(); - - self.ast.set_fn_decl(func, proto, body, loc); - - self.syms - .insert_symbol(self.current_scope(), ident, SymbolKind::Function, func); - - Ok(func) - } - - /// FUNCTION_DECL <- - /// FUNCTION_PROTO BLOCK - fn parse_fn_decl(&mut self, tokens: &mut TokenIterator) -> Index { - match self.parse_fn_inner(tokens) { - Ok(i) => i, - Err(err) => { - self.find_next_fn_or_const(tokens); - self.push_error(err.error, err.loc) - } - } - } - - /// RETURN_STATEMENT <- - /// return EXPRESSION? ; - fn parse_return_stmt(&mut self, tokens: &mut TokenIterator) -> ParseResult { - // SAFETY: function invariance - let ret = tokens.next().unwrap(); - let loc = ret.source_location(); - - let expr = if tokens.eat_token(Token::Semi).is_some() { - self.ast.push_ret(None, loc) - } else { - match self.parse_value_expr(tokens) { - Ok(i) => { - tokens.eat_token(Token::Semi).ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Semi), - loc: tokens.current_source_location(), - })?; - self.ast.push_ret(Some(i), loc) - } - Err(err) => { - tokens.advance_past_semi().ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Semi), - loc: tokens.current_source_location(), - })?; - self.push_error(err.error, err.loc) - } - } - }; - - Ok(expr) - } - - /// VAR_DECL <- - /// (let | var) IDENTIFIER (: TYPENAME)? ; - /// (let | var) IDENTIFIER (: TYPENAME)? = EXPRESSION ; - fn parse_var_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult { - self.parse_with_trailing_semi(tokens, Self::parse_var_decl_inner) - } - - fn parse_var_decl_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult { - // SAFETY: function invariance - let let_or_var = tokens.next().unwrap(); - let loc = let_or_var.source_location(); - - let is_let = let_or_var.token() == Token::Let; - - let name = self.parse_ident(tokens)?; - - let ty = if tokens.eat_token(Token::Colon).is_some() { - Some(self.parse_type(tokens)?) - } else { - None - }; - - let assignment = if tokens.eat_token(Token::Equal).is_some() { - Some(self.parse_value_expr(tokens)?) - } else { - None - }; - - let decl = self.ast.push_var_decl(is_let, name, ty, assignment, loc); - self.syms.insert_symbol( - self.current_scope(), - name, - SymbolKind::Local(tokens.current_source_location()), - decl, - ); - - Ok(decl) - } - - fn parse_block_inner( - &mut self, - block: Index, - tokens: &mut TokenIterator, - ) -> ParseResult { - let loc = tokens.current_source_location(); - let mut statements = Vec::new(); - - let trailing = loop { - if tokens.is_next_token(Token::CloseBrace) { - break None; - } - let next = tokens.peek_token().ok_or(ErrorInfo { - error: ParseError::UnexpectedEndOfTokens, - loc: tokens.current_source_location(), - })?; - - if let Some(decl) = self.parse_constant_decls(tokens)? { - statements.push(decl); - } else { - match next.token() { - Token::Return => { - statements.push(self.parse_return_stmt(tokens)?); - } - Token::Var | Token::Let => { - statements.push(self.parse_var_decl(tokens)?); - } - _ => { - if self.is_statement(tokens) { - // expr -> statements - let expr = self - .parse_with_trailing_semi(tokens, |this, tokens| { - Ok(this.parse_expr(tokens)?.into_index()) - })?; - - statements.push(expr); - } else { - // expr -> trailing - let expr = self.parse_expr(tokens)?; - if !tokens.is_next_token(Token::CloseBrace) { - statements.push(self.push_error( - ParseError::ExpectedEndOfBlock, - tokens.current_source_location(), - )); - } else { - break Some(expr); - } - } - } - } - } - }; - - self.ast.set_block( - block, - statements, - trailing.map(PlaceOrValue::into_index), - loc, - ); - - let block = trailing - .map(|pv| pv.with_index(block)) - .unwrap_or(PlaceOrValue::Value(block)); - Ok(block) - } - - /// BLOCK <- - /// { STATEMENT* EXPRESSION? } - fn parse_block(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let block = self.parse_braced(tokens, |this, tokens| { - let block = this.ast.reserve_node_other(); - this.push_scope(block, intern::Index::invalid()); - let block_result = this.parse_block_inner(block, tokens); - this.pop_scope(); - - block_result - })?; - - Ok(block) - } - - /// PARAMETER_LIST <- - /// PARAMETER - /// PARAMETER_LIST , ARGUMENT - fn parse_parameter_list(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - - let mut params = Vec::new(); - loop { - params.push(self.parse_parameter(tokens)?); - - if !tokens.is_next_token(Token::Comma) { - break; - } - if tokens.is_next_token2(Token::CloseParens) { - break; - } - // skip comma - _ = tokens.next(); - } - - return Ok(self.ast.push_parameter_list(params, loc)); - } - - /// PARAMETER <- - /// IDENT : TYPENAME - fn parse_parameter(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - let name = self.parse_ident(tokens)?; - let Some(_) = tokens.eat_token(Token::Colon) else { - return Err(ErrorInfo { - error: ParseError::ExpectedToken(Token::Colon), - loc, - }); - }; - let ty = self.parse_type(tokens)?; - - let param = self.ast.push_parameter(name, ty, loc); - self.syms.insert_symbol( - self.current_scope(), - name, - SymbolKind::Parameter(loc), - param, - ); - - return Ok(param); - } - - /// ARGUMENT <- - /// IDENT : EXPR - /// EXPR - fn parse_argument(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - let name = if tokens.is_next_token2(Token::Colon) && tokens.is_next_token(Token::Ident) - { - let name = self.parse_ident(tokens)?; - // we checked `is_next_token2` - _ = tokens.eat_token(Token::Colon).unwrap(); - Some(name) - } else { - None - }; - let expr = self.parse_value_expr(tokens)?; - - let i = match name { - Some(name) => self.ast.push_named_argument(name, expr, loc), - None => self.ast.push_argument(expr, loc), - }; - - Ok(i) - } - - /// ARGUMENT_LIST <- - /// ARGUMENT - /// ARGUMENT_LIST , ARGUMENT - fn parse_argument_list(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - let mut args = Vec::new(); - loop { - args.push(self.parse_argument(tokens)?); - - if !tokens.is_next_token(Token::Comma) { - break; - } - if tokens.is_next_token2(Token::CloseParens) { - break; - } - // skip comma - _ = tokens.next(); - } - return Ok(self.ast.push_argument_list(args, loc)); - } - - /// PRIMARY_EXPR <- - /// IDENTIFIER - /// INTEGER_CONSTANT - /// FLOATING_CONSTANT - /// ( EXPRESSION ) - /// BLOCK - fn parse_primary_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - - let Some(next) = tokens.peek_token() else { - return Err(ErrorInfo { - error: ParseError::ExpectedPrimaryExpression, - loc, - }); - }; - - match next.token() { - Token::IntegerBinConstant - | Token::IntegerHexConstant - | Token::IntegerOctConstant - | Token::IntegerConstant => { - _ = tokens.next(); - return Ok(PlaceOrValue::Value( - self.parse_integral_constant(&next, next.source_location()), - )); - } - Token::FloatingConstant - | Token::FloatingExpConstant - | Token::DotFloatingConstant - | Token::DotFloatingExpConstant => { - _ = tokens.next(); - return Ok(PlaceOrValue::Value( - self.parse_floating_constant(&next, next.source_location()), - )); - } - - Token::OpenParens => { - let expr = - self.parse_parenthesised(tokens, |this, tokens| this.parse_expr(tokens))?; - - return Ok(expr); - } - Token::OpenBrace => { - return Ok(self.parse_block(tokens)?); - } - Token::Ident => { - _ = tokens.next(); - let ident = next.lexeme(); - let ident = self - .intern - .get_or_insert(intern::Key::String { str: ident }); - - return Ok(PlaceOrValue::Place(self.ast.push_decl_ref_unresolved( - self.current_scope(), - ident, - loc, - ))); - } - // TODO: eventually handle paths - _ => { - return Err(ErrorInfo { - error: ParseError::ExpectedPrimaryExpression, - loc, - }); - } - } - } - - /// POSTFIX_EXPR <- - /// PRIMARY_EXPR - /// PRIMARY_EXPR ( ) - /// PRIMARY_EXPR ( ARGUMENT_LIST ) - /// PRIMARY_EXPR [ EXPR ] - /// POSTFIX_EXPR . IDENTIFIER - fn parse_postfix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let mut lhs = self.parse_primary_expr(tokens)?; - while let Some(postfix) = self.try_parse_postfix_expr_inner(tokens, lhs)? { - lhs = postfix; - } - - Ok(lhs) - } - - fn try_parse_postfix_expr_inner( - &mut self, - tokens: &mut TokenIterator, - lhs: PlaceOrValue, - ) -> ParseResult> { - let lhs = if let Some(next) = tokens.peek_token() { - let loc = next.source_location(); - match next.token() { - Token::OpenParens => { - let arguments = self.parse_parenthesised(tokens, |this, tokens| { - if tokens.is_next_token(Token::CloseParens) { - Ok(this.ast.push_argument_list([], loc)) - } else { - this.parse_argument_list(tokens) - } - })?; - let lhs = self.convert_to_value_expr(lhs); - - Some(PlaceOrValue::Value( - self.ast.push_call_expr(lhs, arguments, loc), - )) - } - Token::OpenSquareBracket => { - let subscript = self.parse_bracketed(tokens, |this, tokens| { - this.parse_value_expr(tokens) - })?; - - let lhs = self.convert_to_value_expr(lhs); - - Some(PlaceOrValue::Place(self.ast.push_binary( - Tag::SubscriptExpr, - lhs, - subscript, - loc, - ))) - } - Token::Dot if tokens.is_next_token2(Token::Ident) => { - _ = tokens.next(); - let loc = tokens.current_source_location(); - let lhs = self.convert_to_place_expr(lhs); - let name = self.parse_ident(tokens)?; - - Some(self.ast.push_field_access(lhs, name, loc)) - } - _ => None, - } - } else { - None - }; - - Ok(lhs) - } - - fn push_error(&mut self, error: ParseError, loc: SourceLocation) -> Index { - self.errors.push(ErrorInfo { error, loc }); - self.ast.push_error(error, loc) - } - - /// converts the expression to a value expression, if it isn't one already. - fn convert_to_value_expr(&mut self, lrvalue: PlaceOrValue) -> Index { - match lrvalue { - PlaceOrValue::Value(index) => index, - PlaceOrValue::Place(index) => self.ast.push_place_to_value_conversion(index), - } - } - - /// converts the expression to a place expression, if it isn't one already. - fn convert_to_place_expr(&mut self, lrvalue: PlaceOrValue) -> Index { - match lrvalue { - PlaceOrValue::Place(index) => index, - PlaceOrValue::Value(index) => self.ast.push_value_to_place_conversion(index), - } - } - - /// PREFIX_EXPR <- - /// POSTFIX_EXPR - /// ! POSTFIX_EXPR - /// - POSTFIX_EXPR - /// & POSTFIX_EXPR - /// * POSTFIX_EXPR - fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let next = tokens.peek_token().ok_or(ErrorInfo { - error: ParseError::ExpectedPrefixExpression, - loc: tokens.current_source_location(), - })?; - - let loc = next.source_location(); - - let expr = match next.token() { - Token::Bang => { - _ = tokens.next(); - let lhs = self.parse_prefix_expr(tokens)?; - let lhs = self.convert_to_value_expr(lhs); - self.ast.push_unary(Tag::Not, lhs, loc) - } - Token::Minus => { - _ = tokens.next(); - let lhs = self.parse_prefix_expr(tokens)?; - let lhs = self.convert_to_value_expr(lhs); - self.ast.push_unary(Tag::Negate, lhs, loc) - } - Token::Ampersand => { - _ = tokens.next(); - // the address-of operator requires lhs to be a place - // expression. not all expressions that might be the lhs - // are automatically place expressions: the construct `let a - // = &3;` has `3`, which is a value expression, as the lhs - // of the address-of operator. - let lhs = self.parse_prefix_expr(tokens)?; - let lhs = self.convert_to_place_expr(lhs); - self.ast.push_unary(Tag::AddressOf, lhs, loc) - } - Token::Star => { - _ = tokens.next(); - let lhs = self.parse_prefix_expr(tokens)?; - self.ast.push_unary(Tag::Deref, lhs.into_index(), loc) - } - _ => self.parse_postfix_expr(tokens)?, - }; - - Ok(expr) - } - - /// AS_EXPR <- - /// PREFIX_EXPR - /// PREFIX_EXPR as TYPENAME - fn parse_as_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - let expr = self.parse_prefix_expr(tokens)?; - - if tokens.eat_token(Token::As).is_some() { - let typename = self.parse_type(tokens)?; - let expr = self.convert_to_value_expr(expr); - - return Ok(PlaceOrValue::Value(self.ast.push_cast(expr, typename, loc))); - } else { - return Ok(expr); - } - } - - /// BINARY_EXPR <- - /// AS_EXPR - /// AS_EXPR * EXPRESSION - /// AS_EXPR / EXPRESSION - /// AS_EXPR % EXPRESSION - /// AS_EXPR + EXPRESSION - /// AS_EXPR - EXPRESSION - /// AS_EXPR << EXPRESSION - /// AS_EXPR >> EXPRESSION - /// AS_EXPR < EXPRESSION - /// AS_EXPR > EXPRESSION - /// AS_EXPR <= EXPRESSION - /// AS_EXPR >= EXPRESSION - /// AS_EXPR == EXPRESSION - /// AS_EXPR != EXPRESSION - /// AS_EXPR & EXPRESSION - /// AS_EXPR ^ EXPRESSION - /// AS_EXPR | EXPRESSION - /// AS_EXPR && EXPRESSION - /// AS_EXPR || EXPRESSION - fn parse_binary_expr( - &mut self, - tokens: &mut TokenIterator, - precedence: u32, - ) -> ParseResult { - let mut node = self.parse_as_expr(tokens)?; - - loop { - let Some(tok) = tokens.peek_token() else { - break; - }; - let loc = tok.source_location(); - let Some(prec) = PRECEDENCE_MAP.get(&tok.token()).cloned() else { - break; - }; - - if prec < precedence { - break; - } - - // SAFETY: we peeked `tok` - let tok = tokens.next().unwrap(); - - let lhs = self.convert_to_value_expr(node); - let rhs = self.parse_binary_expr(tokens, prec + 1)?; - let rhs = self.convert_to_value_expr(rhs); - - let tag = match tok.token() { - Token::PipePipe => Tag::Or, - Token::AmpersandAmpersand => Tag::And, - Token::Pipe => Tag::BitOr, - Token::Caret => Tag::BitXOr, - Token::Ampersand => Tag::BitAnd, - Token::BangEqual => Tag::NEq, - Token::EqualEqual => Tag::Eq, - Token::LessEqual => Tag::Le, - Token::GreaterEqual => Tag::Ge, - Token::Less => Tag::Lt, - Token::Greater => Tag::Gt, - Token::GreaterGreater => Tag::Shr, - Token::LessLess => Tag::Shl, - Token::Plus => Tag::Add, - Token::Minus => Tag::Sub, - Token::Percent => Tag::Rem, - Token::Star => Tag::Mul, - Token::Slash => Tag::Div, - _ => unreachable!(), - }; - - node = PlaceOrValue::Value(self.ast.push_binary(tag, lhs, rhs, loc)); - } - - Ok(node) - } - - /// ASSIGNMENT_EXPR <- - /// BINARY_EXPRESSION - /// BINARY_EXPRESSION ASSIGNMENT_OP EXPRESSION - /// ASSIGNMENT_OP <- - /// = += -= *= /= %= ... - fn parse_assignment_expr( - &mut self, - tokens: &mut TokenIterator, - ) -> ParseResult { - let lhs = self.parse_binary_expr(tokens, 0)?; - - if tokens - .peek_token() - .map(|itm| itm.token().is_assignment_op()) - == Some(true) - { - // SAFETY: we peeked - let op = tokens.next().unwrap(); - let loc = op.source_location(); - // rhs (src) must be a value - let rhs = self.parse_value_expr(tokens)?; - - let rhs = if op.token() == Token::Equal { - rhs - } else { - let tag = match op.token() { - Token::PlusEqual => Tag::Add, - Token::MinusEqual => Tag::Sub, - Token::StarEqual => Tag::Mul, - Token::SlashEqual => Tag::Sub, - Token::PercentEqual => Tag::Rem, - Token::PipeEqual => Tag::BitOr, - Token::CaretEqual => Tag::BitXOr, - Token::AmpersandEqual => Tag::BitAnd, - Token::LessLessEqual => Tag::Shl, - Token::GreaterGreaterEqual => Tag::Shr, - _ => { - unreachable!() - } - }; - - // convert lhs (dest) to value - let lhs = self.convert_to_value_expr(lhs); - self.ast.push_binary(tag, lhs, rhs, loc) - }; - - // for the assignment, lhs (dest) must be a place - // I think this is the only case where the AST is a dag. - let lhs = self.convert_to_place_expr(lhs); - // the assignment is a value - Ok(PlaceOrValue::Value(self.ast.push_assign(lhs, rhs, loc))) - } else { - // but if we don't have an assignment, this might be a place - Ok(lhs) - } - } - - /// ELSE_EXPR <- - /// 'else' (IF_EXPR | EXPR_OR_STATEMENT_OR_BLOCK) - fn parse_else_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - // SAFETY: function invariance - let _else_ = tokens.eat_token(Token::Else).unwrap(); - - if tokens.is_next_token(Token::If) { - self.parse_if_expr(tokens) - } else { - self.parse_expr_or_block_as_block(tokens) - } - } - - /// IF_EXPR <- - /// 'if' ( EXPR ) EXPR_OR_STATEMENT_OR_BLOCK ELSE_EXPR? - fn parse_if_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - // SAFETY: function invariance - let iff = tokens.eat_token(Token::If).unwrap(); - let loc = iff.source_location(); - - let cond = - self.parse_parenthesised(tokens, |this, tokens| this.parse_value_expr(tokens))?; - - let body = self.parse_expr_or_block_as_block(tokens)?; - - if tokens.is_next_token(Token::Else) { - let else_expr = self.parse_else_expr(tokens)?; - Ok(body.with_index(self.ast.push_if_else( - cond, - body.into_index(), - else_expr.into_index(), - loc, - ))) - } else { - Ok(body.with_index(self.ast.push_if(cond, body.into_index(), loc))) - } - } - - fn parse_expr_or_block_as_block( - &mut self, - tokens: &mut TokenIterator, - ) -> ParseResult { - let Some(next) = tokens.peek_token() else { - return Err(ErrorInfo { - error: ParseError::ExpectedExpression, - loc: tokens.current_source_location(), - }); - }; - - match next.token() { - Token::OpenBrace => self.parse_block(tokens), - _ => { - let loc = tokens.current_source_location(); - let expr = self.parse_expr(tokens)?; - Ok(expr.with_index(self.ast.push_block([], Some(expr.into_index()), loc))) - } - } - } - - fn parse_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - let loc = tokens.current_source_location(); - let Some(next) = tokens.peek_token() else { - return Err(ErrorInfo { - error: ParseError::ExpectedExpression, - loc, - }); - }; - - let expr = match next.token() { - Token::If => self.parse_if_expr(tokens)?, - _ => self.parse_assignment_expr(tokens)?, - }; - - Ok(expr) - } - - fn parse_place_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - // TODO: panic if not place expr - let expr = self.parse_expr(tokens)?; - let expr = self.convert_to_place_expr(expr); - - Ok(expr) - } - fn parse_value_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { - // TODO: convert from place to value (lvalue-to-rvalue) - let expr = self.parse_expr(tokens)?; - let expr = self.convert_to_value_expr(expr); - - Ok(expr) - } - - /// TYPE_DECL <- - /// type IDENTIFIER = TYPE_UNION ; - /// type IDENTIFIER = '(' (TYPE,)* ')' ; - /// type IDENTIFIER = extern? union { (IDENTIFIER: TYPE,)* } - /// type IDENTIFIER = extern? packed? enum { (IDENTIFIER (= EXPRESSION),)* } - /// type IDENTIFIER = extern? packed? struct { (IDENTIFIER: TYPE,)* } - fn parse_type_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult { - _ = tokens.eat_token(Token::Type).ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Type), - loc: tokens.current_source_location(), - }); - - let name = self.parse_ident(tokens)?; - let loc = tokens.current_source_location(); - - _ = tokens.eat_token(Token::Equal).ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Equal), - loc: tokens.current_source_location(), - }); - - let (has_attributes, c_like, packed) = { - let vec = tokens.eat_all_zero_or_once(&[Token::Extern, Token::Packed]); - (vec[0] || vec[1], vec[0], vec[1]) - }; - - let Some(next) = tokens.peek_token() else { - return Err(ErrorInfo { - error: ParseError::ExpectedTypeDeclaration, - loc: tokens.current_source_location(), - }); - }; - - let decl = match next.token() { - Token::Struct => self.parse_struct_decl(tokens, name, c_like, packed, loc), - Token::Union => { - unimplemented!() - } - Token::Enum => { - unimplemented!() - } - _ => { - if has_attributes { - return Err(ErrorInfo { - error: ParseError::UnexpectedTypeAttributes, - loc: tokens.current_source_location(), - }); - } - match next.token() { - Token::OpenParens => { - // tuple - unimplemented!() - } - Token::Ident => { - // sumtype - unimplemented!() - } - _ => { - return Err(ErrorInfo { - error: ParseError::ExpectedTypeDeclaration, - loc: tokens.current_source_location(), - }); - } - } - } - }?; - - self.syms - .insert_symbol(self.current_scope(), name, SymbolKind::Type, decl); - - Ok(decl) - } - - /// SUMTYPE_DECL <- - /// type IDENTIFIER = TYPE_UNION - /// TYPE_UNION <- - /// TYPE (| TYPE_UNION)? - /// IDENTIFIER: TYPE (| TYPE_UNION)? - fn parse_sumtype_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { - todo!() - } - - /// TUPLE_DECL <- - /// type IDENTIFIER = (TYPE,* ) - fn parse_tuple_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { - todo!() - } - - /// UNION_DECL <- - /// type IDENTIFIER = union { IDENTIFIER: TYPE,* } - fn parse_union_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { - todo!() - } - - /// ENUM_DECL <- - /// type IDENTIFIER = packed? enum { IDENTIFIER (= EXPRESSION),* } - fn parse_enum_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { - todo!() - } - - /// STRUCT_DECL <- - /// type IDENTIFIER = extern? packed? struct { STRUCT_FIELD,* } - fn parse_struct_decl( - &mut self, - tokens: &mut TokenIterator, - name: intern::Index, - c_like: bool, - packed: bool, - loc: SourceLocation, - ) -> ParseResult { - // SAFETY: function invariance - - _ = tokens.eat_token(Token::Struct).ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Struct), - loc: tokens.current_source_location(), - })?; - - let decl = self.ast.reserve_node(Kind::GlobalDecl); - let decl = self.parse_braced(tokens, |this, tokens| { - this.parse_struct_fields(tokens).map(|fields| { - _ = tokens.eat_token(Token::Comma); - let flags = StructFlags::new(packed, c_like, fields.len() as u32); - - this.intern.insert_or_replace_struct_type( - name, - decl, - flags.packed, - flags.c_like, - vec![], - ); - - this.ast.set_struct_decl(decl, name, flags, fields, loc) - }) - })?; - - Ok(decl) - } - - fn parse_with_trailing_semi( - &mut self, - tokens: &mut TokenIterator, - parse: F, - ) -> ParseResult - where - F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, - Index: Into, - { - match parse(self, tokens) { - Ok(i) => { - _ = tokens.eat_token(Token::Semi).ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Semi), - loc: tokens.current_source_location(), - })?; - - Ok(i) - } - Err(err) => { - tokens.advance_past_semi().ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Semi), - loc: tokens.current_source_location(), - })?; - Ok(self.push_error(err.error, err.loc).into()) - } - } - } - - fn parse_inner( - &mut self, - tokens: &mut TokenIterator, - open: Token, - close: Token, - parse: F, - on_err: E, - ) -> ParseResult - where - F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, - E: FnOnce(&mut Self, &mut TokenIterator, ErrorInfo, TokenItem) -> ParseResult, - { - let Some(start) = tokens.eat_token(open) else { - return Err(ErrorInfo { - error: ParseError::ExpectedToken(open), - loc: tokens.current_source_location(), - }); - }; - - match parse(self, tokens) { - Ok(i) => { - _ = tokens.eat_token(close).ok_or(ErrorInfo { - error: match open { - Token::OpenBrace => ParseError::UnmatchedBrace(start.token_pos().start), - Token::OpenParens => { - ParseError::UnmatchedParens(start.token_pos().start) - } - Token::OpenSquareBracket => { - ParseError::UnmatchedSquareBracket(start.token_pos().start) - } - _ => ParseError::UnmatchedDelimiter(start.token_pos().start), - }, - loc: tokens.current_source_location(), - })?; - - Ok(i) - } - Err(e) => on_err(self, tokens, e, start), - } - } - - fn parse_inner2( - &mut self, - tokens: &mut TokenIterator, - open: Token, - close: Token, - parse: F, - ) -> ParseResult - where - F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, - Index: Into, - // I: From, - { - self.parse_inner(tokens, open, close, parse, |this, tokens, err, start| { - match close { - Token::CloseBrace => { - tokens.advance_past_end_of_braced().ok_or(ErrorInfo { - error: ParseError::UnmatchedBrace(start.token_pos().start), - loc: tokens.current_source_location(), - })?; - } - Token::CloseParens => { - tokens.advance_past_end_of_parens().ok_or(ErrorInfo { - error: ParseError::UnmatchedParens(start.token_pos().start), - loc: tokens.current_source_location(), - })?; - } - Token::CloseSquareBracket => { - tokens.advance_past_end_of_bracketed().ok_or(ErrorInfo { - error: ParseError::UnmatchedSquareBracket(start.token_pos().start), - loc: tokens.current_source_location(), - })?; - } - Token::Semi => { - tokens.advance_past_semi().ok_or(ErrorInfo { - error: ParseError::ExpectedToken(Token::Semi), - loc: tokens.current_source_location(), - })?; - } - _ => unimplemented!(), - } - Ok(this.push_error(err.error, err.loc).into()) - }) - } - - fn parse_bracketed(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult - where - F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, - Index: Into, - { - self.parse_inner2( - tokens, - Token::OpenSquareBracket, - Token::CloseSquareBracket, - parse, - ) - } - - fn parse_braced(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult - where - F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, - Index: Into, - { - self.parse_inner2(tokens, Token::OpenBrace, Token::CloseBrace, parse) - } - - fn parse_parenthesised( - &mut self, - tokens: &mut TokenIterator, - parse: F, - ) -> ParseResult - where - F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, - Index: Into, - { - self.parse_inner2(tokens, Token::OpenParens, Token::CloseParens, parse) - } - - fn parse_struct_fields( - &mut self, - tokens: &mut TokenIterator, - ) -> ParseResult> { - let mut fields = Vec::new(); - loop { - fields.push(self.parse_struct_field(tokens)?); - - if !tokens.is_next_token(Token::Comma) { - break; - } - if tokens.is_next_token2(Token::CloseBrace) { - break; - } - // skip comma - _ = tokens.next(); - } - - Ok(fields) - } - - /// STRUCT_FIELD <- - /// IDENTIFIER: TYPE - fn parse_struct_field( - &mut self, - tokens: &mut TokenIterator, - ) -> ParseResult<(intern::Index, Index)> { - let name = self.parse_ident(tokens)?; - let Some(_) = tokens.eat_token(Token::Colon) else { - return Err(ErrorInfo { - error: ParseError::ExpectedToken(Token::Colon), - loc: tokens.current_source_location(), - }); - }; - let ty = self.parse_type(tokens)?; - - return Ok((name, ty)); - } - - /// CONSTANT_DECL <- - /// FUNCTION_DECL - /// GLOBAL_DECL - /// STRUCT_DECL - fn parse_constant_decls( - &mut self, - tokens: &mut TokenIterator, - ) -> ParseResult> { - let next = tokens.peek_token().ok_or(ErrorInfo { - error: ParseError::UnexpectedEndOfTokens, - loc: tokens.current_source_location(), - })?; - - match next.token() { - Token::Fn => Ok(Some(self.parse_fn_decl(tokens))), - Token::Const => self.parse_const_decl(tokens).map(|i| Some(i)), - Token::Type => self.parse_type_decl(tokens).map(|i| Some(i)), - _ => Ok(None), - } - } - - /// FILE <- - /// (FUNCTION_DECL | GLOBAL_DECL)* - fn parse_file(&mut self, tokens: &mut TokenIterator) -> Index { - let start = tokens.current_source_location(); - let mut decls = Vec::new(); - let file = self.ast.reserve_node(Kind::File); - self.push_scope(file, intern::Index::invalid()); - - while let Some(next) = tokens.peek_token() { - let loc = next.source_location(); - let decl = match self.parse_constant_decls(tokens).and_then(|i| match i { - Some(i) => Ok(i), - None => { - let error = ParseError::UnexpectedTokenAtFileScope; - let node = self.push_error(error, loc); - - self.find_next_fn_or_const(tokens); - - Ok(node) - } - }) { - Ok(i) => i, - Err(err) => self.push_error(err.error, err.loc), - }; - decls.push(decl); - } - self.pop_scope(); - - self.ast.set_file(file, decls, start); - file - } - - /// FILE <- - /// (FUNCTION_DECL | GLOBAL_DECL)* - pub fn parse(&mut self, mut tokens: TokenIterator) { - let file = self.parse_file(&mut tokens); - self.ast.set_root([file]); - eprintln!("resolving decls:"); - self.resolve_decl_refs(); - self.create_comptime_folding_graph(intern::AMD64_POINTER_BITS); - eprintln!("interning types:"); - self.intern_types(); - self.fold_more_patterns(); - } - - fn push_scope(&mut self, ast: Index, name: intern::Index) { - let parent = self.scopes.last().cloned(); - self.scopes.push(ast); - - if let Some(parent) = parent { - self.syms.insert_symbol( - ast, - intern::Index::invalid(), - SymbolKind::ParentScope, - parent, - ); - } - self.syms.insert_scope(name, ast); - } - - fn pop_scope(&mut self) { - self.scopes.pop(); - } - - fn is_statement(&self, tokens: &mut TokenIterator) -> bool { - let mut tokens = tokens.clone(); - let mut braces = 0; - let mut parens = 0; - let mut brackets = 0; - while let Some(itm) = tokens.next() { - match itm.token() { - Token::OpenBrace => { - braces += 1; - } - Token::CloseBrace => { - braces -= 1; - } - Token::OpenParens => { - parens += 1; - } - Token::CloseParens => { - parens -= 1; - } - Token::OpenSquareBracket => { - brackets += 1; - } - Token::CloseSquareBracket => { - brackets -= 1; - } - Token::Semi => { - if braces == 0 && parens == 0 && brackets == 0 { - return true; - } - } - _ => {} - } - if braces < 0 || parens < 0 || brackets < 0 { - break; - } - } - false - } - - fn find_next_fn_or_const(&mut self, tokens: &mut TokenIterator) -> Option<()> { - tokens - .advance_until_before_one_of(&[Token::Const, Token::Fn, Token::Type]) - .map(|_| ()) - } - } -} - -impl Ast { - fn visit_all_functions_mut(&mut self, visitor: &mut impl AstVisitorTrait) { - for i in - (0..self.tags.functions.len()).map(|i| Index::new(Kind::Function, i as u32).unwrap()) - { - visitor.visit_function_decl(self, i); - } - } - - fn visit_function_mut(&mut self) {} -} - -pub trait AstVisitorTrait { - type Error; - type Value; - const UNIMPL: Self::Error; - - fn visit_function_decl( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_parameter(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_parameter_list( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_block(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_block_trailing_expr( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_block_maybe_trailing( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - use visitor::AstExt; - match ast.get_node_tag_and_data(idx).0 { - Tag::BlockTrailingExpr => self.visit_block(ast, idx), - Tag::Block => self.visit_block_trailing_expr(ast, idx), - _ => unreachable!(), - } - } - fn visit_function_proto( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_call_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_add_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_sub_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_mul_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_div_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_rem_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_eq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_neq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_lt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_gt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_le_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_ge_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_shl_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_shr_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_bitor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_bitxor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_bitand_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_or_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_and_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_not_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_negate_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_deref_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_address_of_expr( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_explicit_cast_expr( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_assign(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_subscript_expr( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_if_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_if_else_expr( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_argument(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - - fn visit_any_argument( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - use visitor::AstExt; - match ast.get_node_tag_and_data(idx).0 { - Tag::Argument => self.visit_argument(ast, idx), - Tag::NamedArgument => self.visit_named_argument(ast, idx), - _ => unreachable!(), - } - } - - fn visit_named_argument( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - - fn visit_argument_list( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - - fn visit_constant(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - - fn visit_return(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_return_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_global_decl(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_var_decl(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_mut_var_decl( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_var_assign_decl( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_mut_var_assign_decl( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_decl_ref(&mut self, ast: &mut Ast, idx: Index) -> Result { - _ = (ast, idx); - Err(Self::UNIMPL) - } - fn visit_value_to_place_conversion( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - let idx = ast - .get_node_data_for_tag(idx, Tag::ValueToPlaceConversion) - .unwrap() - .as_index(); - self.visit_any(ast, idx) - } - fn visit_place_to_value_conversion( - &mut self, - ast: &mut Ast, - idx: Index, - ) -> Result { - let idx = ast - .get_node_data_for_tag(idx, Tag::PlaceToValueConversion) - .unwrap() - .as_index(); - self.visit_any(ast, idx) - } - - fn visit_any(&mut self, ast: &mut Ast, idx: Index) -> Result { - use visitor::AstExt; - match ast.get_node_tag_and_data(idx).0 { - Tag::FunctionProto => self.visit_function_proto(ast, idx), - Tag::FunctionDecl => self.visit_function_decl(ast, idx), - Tag::ParameterList => self.visit_parameter_list(ast, idx), - Tag::Parameter => self.visit_parameter(ast, idx), - Tag::Block => self.visit_block(ast, idx), - Tag::BlockTrailingExpr => self.visit_block_trailing_expr(ast, idx), - Tag::Constant => self.visit_constant(ast, idx), - Tag::ExprStmt => todo!(), - Tag::ReturnStmt => self.visit_return(ast, idx), - Tag::ReturnExprStmt => self.visit_return_expr(ast, idx), - Tag::VarDecl => self.visit_var_decl(ast, idx), - Tag::MutVarDecl => self.visit_mut_var_decl(ast, idx), - Tag::VarDeclAssignment => self.visit_var_assign_decl(ast, idx), - Tag::MutVarDeclAssignment => self.visit_mut_var_assign_decl(ast, idx), - Tag::GlobalDecl => self.visit_global_decl(ast, idx), - Tag::StructDecl => todo!(), - Tag::FieldDecl => todo!(), - Tag::DeclRef => self.visit_decl_ref(ast, idx), - Tag::DeclRefUnresolved => todo!(), - Tag::InternedType => todo!(), - Tag::TypeDeclRef => todo!(), - Tag::TypeDeclRefUnresolved => todo!(), - Tag::PointerType => todo!(), - Tag::ArrayType => todo!(), - Tag::CallExpr => self.visit_call_expr(ast, idx), - Tag::FieldAccess => todo!(), - Tag::ArgumentList => self.visit_argument_list(ast, idx), - Tag::Argument => self.visit_argument(ast, idx), - Tag::NamedArgument => self.visit_named_argument(ast, idx), - Tag::ExplicitCast => self.visit_explicit_cast_expr(ast, idx), - Tag::Deref => self.visit_deref_expr(ast, idx), - Tag::AddressOf => self.visit_add_expr(ast, idx), - Tag::Not => self.visit_not_expr(ast, idx), - Tag::Negate => self.visit_negate_expr(ast, idx), - Tag::Or => self.visit_or_expr(ast, idx), - Tag::And => self.visit_and_expr(ast, idx), - Tag::BitOr => self.visit_bitor_expr(ast, idx), - Tag::BitXOr => self.visit_bitxor_expr(ast, idx), - Tag::BitAnd => self.visit_bitand_expr(ast, idx), - Tag::Eq => self.visit_eq_expr(ast, idx), - Tag::NEq => self.visit_neq_expr(ast, idx), - Tag::Lt => self.visit_lt_expr(ast, idx), - Tag::Gt => self.visit_gt_expr(ast, idx), - Tag::Le => self.visit_le_expr(ast, idx), - Tag::Ge => self.visit_ge_expr(ast, idx), - Tag::Shl => self.visit_shl_expr(ast, idx), - Tag::Shr => self.visit_shr_expr(ast, idx), - Tag::Add => self.visit_add_expr(ast, idx), - Tag::Sub => self.visit_sub_expr(ast, idx), - Tag::Mul => self.visit_mul_expr(ast, idx), - Tag::Div => self.visit_div_expr(ast, idx), - Tag::Rem => self.visit_rem_expr(ast, idx), - Tag::Assign => self.visit_assign(ast, idx), - Tag::SubscriptExpr => self.visit_subscript_expr(ast, idx), - Tag::IfExpr => self.visit_if_expr(ast, idx), - Tag::IfElseExpr => self.visit_if_else_expr(ast, idx), - Tag::PlaceToValueConversion => self.visit_place_to_value_conversion(ast, idx), - Tag::ValueToPlaceConversion => self.visit_value_to_place_conversion(ast, idx), - Tag::Error => todo!(), - Tag::Undefined => todo!(), - Tag::Root => todo!(), - Tag::File => todo!(), - } - } -} - -impl Ast { - fn get_node_data_for_tag(&self, idx: Index, tag: Tag) -> Option { - use visitor::AstExt; - let (t, data) = self.get_node_tag_and_data(idx); - if t == tag { - Some(data) - } else { - None - } - } - - fn expect_node_data_for_tag(&self, idx: Index, tag: Tag) -> Data { - self.get_node_data_for_tag(idx, tag) - .expect(&format!("node {idx} is not a {tag:?}")) - } -} - -pub mod ir { - use std::collections::HashMap; - - use crate::{ - ast2::{ - intern::{self, AMD64_POINTER_TYPE_INFO}, - Index, - }, - triples::{self, Inst, IR}, - }; - - #[derive(Debug, thiserror::Error)] - enum Error { - #[error("This visitor does not implement visiting this tag.")] - Unimplemented, - } - - use super::{ - intern::InternPoolWrapper as InternPool, visitor::AstExt, AstVisitorTrait, TypeCache, - }; - - struct IrBuilder { - functions: Vec, - } - - struct Function { - ir: IR, - } - - struct IrFunctionBuilder<'a> { - ir: &'a mut IR, - type_cache: &'a mut TypeCache, - ref_lookup: &'a mut HashMap, - ip: &'a InternPool, - function: Function, - } - - impl<'a> AstVisitorTrait for IrFunctionBuilder<'a> { - type Error = Error; - type Value = Option; - const UNIMPL: Self::Error = Error::Unimplemented; - - fn visit_block( - &mut self, - ast: &mut super::Ast, - idx: super::Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Block); - let (a, b) = data.as_extra_range(); - - ast.extra[a..b] - .to_vec() - .into_iter() - .map(|i| Index::from_u32(i).unwrap()) - .map(|i| self.visit_any(ast, i)) - .try_fold((), |_, e| e.map(crate::unit))?; - - Ok(None) - } - - fn visit_place_to_value_conversion( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::PlaceToValueConversion); - let expr = data.as_index(); - - // idx's (this) type is the pointee type - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - - let expr = self.visit_any(ast, expr)?.unwrap(); - - let ir = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr))); - Ok(Some(ir)) - } - - fn visit_value_to_place_conversion( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::ValueToPlaceConversion); - let expr = data.as_index(); - - // expr's type is the pointee type - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); - - let expr = self.visit_any(ast, expr)?.unwrap(); - - let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); - - let alloca = self.ir.push( - Inst::Alloca, - Some(triples::Data::new(info.size(), info.align())), - ); - - _ = self - .ir - .push(Inst::Store(ty), Some(triples::Data::new(expr, alloca))); - - Ok(Some(alloca)) - } - - fn visit_decl_ref( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::DeclRef); - let decl = data.as_index(); - - let alloca = self.ref_lookup.get(&decl).cloned().expect("declref"); - - Ok(Some(alloca)) - } - - fn visit_var_decl( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_var_decl_common(ast, idx) - } - - fn visit_mut_var_decl( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_var_decl_common(ast, idx) - } - - fn visit_var_assign_decl( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_var_decl_common(ast, idx) - } - - fn visit_mut_var_assign_decl( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_var_decl_common(ast, idx) - } - - fn visit_return( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - _ = (ast, idx); - - let ir = self.ir.push(Inst::Return, None); - Ok(Some(ir)) - } - fn visit_return_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::ReturnExprStmt); - let expr = data.as_index(); - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); - - let expr = self.visit_any(ast, expr)?.unwrap(); - - let ir = self - .ir - .push(Inst::ReturnValue(ty), Some(triples::Data::lhs(expr))); - Ok(Some(ir)) - } - - fn visit_constant( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Constant); - let (ty, value) = data.as_index_intern(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); - let ir = self.ir.push(Inst::Constant, Some((ty, value).into())); - - Ok(Some(ir)) - } - - fn visit_subscript_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::SubscriptExpr); - let (lhs, index) = data.as_two_indices(); - - // pointer type - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - - let lhs = self.visit_any(ast, lhs)?.unwrap(); - let index = self.visit_any(ast, index)?.unwrap(); - - // TODO: make getelementptr take a variable instead of a constant index. - let ir = self.ir.push( - Inst::GetElementPtr(ty), - Some(triples::Data::new(lhs, index)), - ); - - Ok(Some(ir)) - } - - fn visit_call_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::CallExpr); - let (func, arguments) = data.as_two_indices(); - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - - let len = self.visit_parameter_list(ast, arguments)?.unwrap(); - _ = self.ir.push(Inst::InlineType(ty), None); - let end = self.ir.nodes.len() as u32; - - let func = self.visit_any(ast, func)?.unwrap(); - - let result = self - .ir - .push(Inst::Call(func), Some(triples::Data::new(end - len, end))); - - Ok(Some(result)) - } - - fn visit_argument( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Argument); - let expr = data.as_index(); - - let arg = self.visit_any(ast, expr)?.unwrap(); - - // let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); - // self.ir.push(Inst::Argument(ty), Some(triples::Data::lhs(arg))); - - Ok(Some(arg)) - } - - // fn visit_named_argument( - // &mut self, - // ast: &mut super::Ast, - // idx: Index, - // ) -> Result { - // todo!() - // } - - fn visit_argument_list( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::ArgumentList); - let (a, b) = data.as_extra_range(); - - let args = ast.extra[a..b] - .to_vec() - .into_iter() - .map(|i| Index::from_u32(i).unwrap()) - .map(|i| { - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, i); - let arg = self.visit_any_argument(ast, i)?.unwrap(); - Ok((ty, arg)) - }) - .collect::, _>>()?; - let count = args.len(); - for (ty, arg) in args { - _ = self - .ir - .push(Inst::Argument(ty), Some(triples::Data::lhs(arg))); - } - // .try_fold((), |_, e| e.map(crate::unit))?; - - Ok(Some(count as u32)) - } - - fn visit_block_trailing_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::BlockTrailingExpr); - - let (a, b) = data.as_extra_range(); - - let expr = ast.extra[a..b] - .to_vec() - .into_iter() - .map(|i| Index::from_u32(i).unwrap()) - .map(|i| self.visit_any(ast, i)) - // the last node is the trailing - .try_fold(None, |_, e| e)?; - - Ok(expr) - } - - fn visit_function_proto( - &mut self, - ast: &mut super::Ast, - idx: super::Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionProto); - - let (_, extra) = data.as_intern_and_extra_offset(); - let (_return_type, parameter_list) = ( - Index::from_u32(ast.extra[extra]).unwrap(), - Index::from_u32(ast.extra[extra + 1]).unwrap(), - ); - - self.visit_parameter_list(ast, parameter_list)?; - // push parameters to ir - Ok(None) - } - - fn visit_parameter_list( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::ParameterList); - let (a, b) = data.as_extra_range(); - - ast.extra[a..b] - .to_vec() - .into_iter() - .map(|i| Index::from_u32(i).unwrap()) - .map(|i| self.visit_parameter(ast, i)) - .try_fold((), |_, e| e.map(crate::unit))?; - - Ok(None) - } - - fn visit_parameter( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Parameter); - let (ty, _name) = data.as_index_intern(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); - let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); - let ir = self.ir.push( - Inst::Parameter(ty), - Some(triples::Data::new(info.size(), info.align())), - ); - self.ref_lookup.insert(idx, ir); - - Ok(None) - } - - fn visit_address_of_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::AddressOf); - let expr = data.as_index(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); - let expr = self.visit_any(ast, expr)?.unwrap(); - let r = self - .ir - .push(Inst::GetElementPtr(ty), Some(triples::Data::new(expr, 0))); - - Ok(Some(r)) - } - - fn visit_assign( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Assign); - let (dst, src) = data.as_two_indices(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - let dst = self.visit_any(ast, dst)?.unwrap(); - let src = self.visit_any(ast, src)?.unwrap(); - - let ir = self - .ir - .push(Inst::Store(ty.into()), Some(triples::Data::new(src, dst))); - - Ok(Some(ir)) - } - - fn visit_explicit_cast_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::ExplicitCast); - let (lhs, ty) = data.as_two_indices(); - - let lty = ast.get_type_of_node(&self.ip, &mut self.type_cache, lhs); - let rty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty); - - let lhs = self.visit_any(ast, lhs)?.unwrap(); - - // TODO: if bitwidth is the same, then this is a noop? - let cast = self - .ir - .push(Inst::ExplicitCast(lty, rty), Some(triples::Data::lhs(lhs))); - - Ok(Some(cast)) - } - - fn visit_if_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::IfExpr); - let (cond, body) = data.as_two_indices(); - - let cond = self.visit_any(ast, cond)?.unwrap(); - let br = self.ir.push(Inst::Branch(cond), None); - - let lbody = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - _ = self.visit_any(ast, body); - let jmp = self.ir.push(Inst::Jump, None); - let skip = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - - self.ir.data[br as usize] = Some(triples::Data::new(lbody, skip)); - self.ir.data[jmp as usize] = Some(triples::Data::lhs(skip)); - - Ok(Some(br)) - } - - fn visit_if_else_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::IfElseExpr); - let (cond, extra) = data.as_index_and_extra_offset(); - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - - let [a, b] = ast.extra[extra..][..2] else { - unreachable!() - }; - - let cond = self.visit_any(ast, cond)?.unwrap(); - let br = self.ir.push(Inst::Branch(cond), None); - - let la = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - let a = self.visit_any(ast, Index::from_u32(a).unwrap())?.unwrap(); - let jmpa = self.ir.push(Inst::Jump, None); - - let lb = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - let b = self.visit_any(ast, Index::from_u32(b).unwrap())?.unwrap(); - let jmpb = self.ir.push(Inst::Jump, None); - - let lphi = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - - let phi = if ty == intern::Index::VOID { - br - } else { - self.ir.push(Inst::Phi2(ty), Some(triples::Data::new(a, b))) - }; - - self.ir.data[br as usize] = Some(triples::Data::new(la, lb)); - self.ir.data[jmpa as usize] = Some(triples::Data::lhs(lphi)); - self.ir.data[jmpb as usize] = Some(triples::Data::lhs(lphi)); - - Ok(Some(phi)) - } - - fn visit_deref_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Not); - let expr = data.as_index(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - let expr = self.visit_any(ast, expr)?.unwrap(); - let not = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr))); - - Ok(Some(not)) - } - - fn visit_not_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Not); - let expr = data.as_index(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); - let expr = self.visit_any(ast, expr)?.unwrap(); - let not = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(expr))); - - Ok(Some(not)) - } - - fn visit_negate_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Negate); - let expr = data.as_index(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr); - let expr = self.visit_any(ast, expr)?.unwrap(); - let not = self - .ir - .push(Inst::Negate(ty), Some(triples::Data::lhs(expr))); - - Ok(Some(not)) - } - - fn visit_or_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Or); - let (a, b) = data.as_two_indices(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - - // TODO: make this an error instead of a panic - let a = self.visit_any(ast, a)?.unwrap(); - let not_a = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(a))); - - // branch taken if a - let br = self.ir.push(Inst::Branch(not_a), None); - let lb = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - - let b = self.visit_any(ast, b)?.unwrap(); - let jmp = self.ir.push(Inst::Jump, None); - - let la = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - - self.ir.data[br as usize] = Some(triples::Data::new(lb, la)); - self.ir.data[jmp as usize] = Some(triples::Data::lhs(la)); - - let or = self.ir.push( - Inst::Phi2(intern::Index::BOOL), - Some(triples::Data::new(a, b)), - ); - - Ok(Some(or)) - } - - fn visit_and_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - let data = ast.expect_node_data_for_tag(idx, super::Tag::Or); - let (a, b) = data.as_two_indices(); - - // TODO: make this an error instead of a panic - let a = self.visit_any(ast, a)?.unwrap(); - - // branch taken if a - let br = self.ir.push(Inst::Branch(a), None); - - let lb = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - let b = self.visit_any(ast, b)?.unwrap(); - - let skip = self - .ir - .push(Inst::Label, Some(intern::Index::EMPTY_STRING.into())); - - self.ir.data[br as usize] = Some(triples::Data::new(lb, skip)); - let and = self.ir.push( - Inst::Phi2(intern::Index::BOOL), - Some(triples::Data::new(a, b)), - ); - - Ok(Some(and)) - } - - fn visit_add_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_sub_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_div_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_rem_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_mul_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_bitand_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_bitor_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_bitxor_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_eq_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_neq_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_lt_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_gt_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_le_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_ge_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_shl_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - fn visit_shr_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result { - self.visit_binop_expr(ast, idx) - } - } - - impl IrFunctionBuilder<'_> { - fn visit_var_decl_common( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result, Error> { - let (tag, data) = ast.get_node_tag_and_data(idx); - let (a, b) = data.as_extra_range(); - - let range = &ast.extra[a..b]; - let _name = range.get(0).unwrap(); - - let (expr, typed_index) = match tag { - super::Tag::VarDecl | super::Tag::MutVarDecl => { - let typed_index = range - .get(1) - .cloned() - .map(Index::from_u32) - .flatten() - .unwrap(); - (None, typed_index) - } - super::Tag::VarDeclAssignment | super::Tag::MutVarDeclAssignment => { - let expr = range - .get(1) - .cloned() - .map(Index::from_u32) - .flatten() - .unwrap(); - let typed_index = range - .get(2) - .cloned() - .map(Index::from_u32) - .flatten() - .unwrap_or(expr); - (Some(expr), typed_index) - } - _ => unreachable!(), - }; - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, typed_index); - let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO); - - let alloca = self.ir.push( - Inst::Alloca, - Some(triples::Data::new(info.size(), info.align())), - ); - - if let Some(idx) = expr { - let expr = self.visit_any(ast, idx)?.unwrap(); - _ = self - .ir - .push(Inst::Store(ty), Some(triples::Data::new(expr, alloca))); - } - - self.ref_lookup.insert(idx, alloca); - - Ok(Some(alloca)) - } - - /// handles all binary operations that don't short circuit and visit - /// both lhs and rhs. - fn visit_binop_expr( - &mut self, - ast: &mut super::Ast, - idx: Index, - ) -> Result, Error> { - use triples::Data; - let (tag, data) = ast.get_node_tag_and_data(idx); - let (lhs, rhs) = data.as_two_indices(); - - let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx); - - // TODO: make this an error instead of a panic - let lhs = self.visit_any(ast, lhs)?.unwrap(); - let rhs = self.visit_any(ast, rhs)?.unwrap(); - - let (inst, data) = match tag { - super::Tag::BitOr => (Inst::BitOr(ty), Data::new(lhs, rhs)), - super::Tag::BitXOr => (Inst::BitOr(ty), Data::new(lhs, rhs)), - super::Tag::BitAnd => (Inst::BitOr(ty), Data::new(lhs, rhs)), - - super::Tag::Eq => (Inst::Eq(ty), Data::new(lhs, rhs)), - super::Tag::NEq => (Inst::Neq(ty), Data::new(lhs, rhs)), - super::Tag::Lt => (Inst::Lt(ty), Data::new(lhs, rhs)), - super::Tag::Gt => (Inst::Gt(ty), Data::new(lhs, rhs)), - super::Tag::Le => (Inst::Le(ty), Data::new(lhs, rhs)), - super::Tag::Ge => (Inst::Ge(ty), Data::new(lhs, rhs)), - - super::Tag::Shl => (Inst::ShiftLeft(ty), Data::new(lhs, rhs)), - super::Tag::Shr => (Inst::ShiftRight(ty), Data::new(lhs, rhs)), - super::Tag::Add => (Inst::Add(ty), Data::new(lhs, rhs)), - super::Tag::Sub => (Inst::Sub(ty), Data::new(lhs, rhs)), - super::Tag::Div => (Inst::Div(ty), Data::new(lhs, rhs)), - super::Tag::Rem => (Inst::Rem(ty), Data::new(lhs, rhs)), - super::Tag::Mul => (Inst::Mul(ty), Data::new(lhs, rhs)), - _ => panic!("not a binop"), - }; - - Ok(Some(self.ir.push(inst, Some(data)))) - } - } - - impl AstVisitorTrait for IrBuilder { - type Value = (); - type Error = Error; - const UNIMPL: Self::Error = Error::Unimplemented; - - fn visit_function_decl( - &mut self, - ast: &mut super::Ast, - idx: super::Index, - ) -> Result<(), Self::Error> { - let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionDecl); - let (proto, block) = data.as_two_indices(); - - // visit proto - - // visit block - - todo!() - } - } -} - -pub mod irgen { - - use super::*; - use crate::{symbol_table::syms2::Symbols, triples::*}; - use std::collections::HashMap; - - struct IRGen { - ast: Ast, - syms: Symbols, - ir: IR, - ip: InternPool, - } - - impl IRGen { - fn build(&mut self) { - let mut mapping = HashMap::::new(); - self.ast.visitor().visit( - |ast, scopes, i, tag, data| { - _ = (&mapping, ast, scopes, i, tag, data); - // pre - match tag { - Tag::Root => todo!(), - Tag::File => todo!(), - Tag::FunctionProto => todo!(), - Tag::FunctionDecl => todo!(), - Tag::ParameterList => todo!(), - Tag::Parameter => todo!(), - Tag::Block => todo!(), - Tag::BlockTrailingExpr => todo!(), - Tag::Constant => todo!(), - Tag::ExprStmt => todo!(), - Tag::ReturnStmt => todo!(), - Tag::ReturnExprStmt => todo!(), - Tag::VarDecl => todo!(), - Tag::MutVarDecl => todo!(), - Tag::VarDeclAssignment => todo!(), - Tag::MutVarDeclAssignment => todo!(), - Tag::GlobalDecl => todo!(), - Tag::StructDecl => todo!(), - Tag::FieldDecl => todo!(), - Tag::DeclRef => todo!(), - Tag::DeclRefUnresolved => todo!(), - Tag::InternedType => todo!(), - Tag::TypeDeclRef => todo!(), - Tag::TypeDeclRefUnresolved => todo!(), - Tag::PointerType => todo!(), - Tag::ArrayType => todo!(), - Tag::CallExpr => todo!(), - Tag::FieldAccess => todo!(), - Tag::ArgumentList => todo!(), - Tag::Argument => todo!(), - Tag::NamedArgument => todo!(), - Tag::ExplicitCast => todo!(), - Tag::Deref => todo!(), - Tag::AddressOf => todo!(), - Tag::Not => todo!(), - Tag::Negate => todo!(), - Tag::Or => todo!(), - Tag::And => todo!(), - Tag::BitOr => todo!(), - Tag::BitXOr => todo!(), - Tag::BitAnd => todo!(), - Tag::Eq => todo!(), - Tag::NEq => todo!(), - Tag::Lt => todo!(), - Tag::Gt => todo!(), - Tag::Le => todo!(), - Tag::Ge => todo!(), - Tag::Shl => todo!(), - Tag::Shr => todo!(), - Tag::Add => todo!(), - Tag::Sub => todo!(), - Tag::Mul => todo!(), - Tag::Div => todo!(), - Tag::Rem => todo!(), - Tag::Assign => todo!(), - Tag::SubscriptExpr => todo!(), - Tag::IfExpr => todo!(), - Tag::IfElseExpr => todo!(), - Tag::Error => todo!(), - Tag::Undefined => todo!(), - Tag::PlaceToValueConversion => todo!(), - Tag::ValueToPlaceConversion => todo!(), - } - }, - |ast, scopes, i, tag, data| { - _ = (&mapping, ast, scopes, i, tag, data); - // post - match tag { - Tag::Root => todo!(), - Tag::File => todo!(), - Tag::FunctionProto => todo!(), - Tag::FunctionDecl => { - todo!() - } - Tag::ParameterList => todo!(), - Tag::Parameter => todo!(), - Tag::Block => todo!(), - Tag::BlockTrailingExpr => todo!(), - Tag::Constant => todo!(), - Tag::ExprStmt => todo!(), - Tag::ReturnStmt => todo!(), - Tag::ReturnExprStmt => todo!(), - Tag::VarDecl => todo!(), - Tag::MutVarDecl => todo!(), - Tag::VarDeclAssignment => todo!(), - Tag::MutVarDeclAssignment => todo!(), - Tag::GlobalDecl => todo!(), - Tag::StructDecl => todo!(), - Tag::FieldDecl => todo!(), - Tag::DeclRef => todo!(), - Tag::DeclRefUnresolved => todo!(), - Tag::InternedType => todo!(), - Tag::TypeDeclRef => todo!(), - Tag::TypeDeclRefUnresolved => todo!(), - Tag::PointerType => todo!(), - Tag::ArrayType => todo!(), - Tag::CallExpr => todo!(), - Tag::FieldAccess => todo!(), - Tag::ArgumentList => todo!(), - Tag::Argument => todo!(), - Tag::NamedArgument => todo!(), - Tag::ExplicitCast => todo!(), - Tag::Deref => todo!(), - Tag::AddressOf => todo!(), - Tag::Not => todo!(), - Tag::Negate => todo!(), - Tag::Or => todo!(), - Tag::And => todo!(), - Tag::BitOr => todo!(), - Tag::BitXOr => todo!(), - Tag::BitAnd => todo!(), - Tag::Eq => todo!(), - Tag::NEq => todo!(), - Tag::Lt => todo!(), - Tag::Gt => todo!(), - Tag::Le => todo!(), - Tag::Ge => todo!(), - Tag::Shl => todo!(), - Tag::Shr => todo!(), - Tag::Add => todo!(), - Tag::Sub => todo!(), - Tag::Mul => todo!(), - Tag::Div => todo!(), - Tag::Rem => todo!(), - Tag::Assign => todo!(), - Tag::SubscriptExpr => todo!(), - Tag::IfExpr => todo!(), - Tag::IfElseExpr => todo!(), - Tag::Error => todo!(), - Tag::Undefined => todo!(), - Tag::PlaceToValueConversion => todo!(), - Tag::ValueToPlaceConversion => todo!(), - } - }, - ); - } - } -} diff --git a/src/ast2/parser.rs b/src/ast2/parser.rs new file mode 100644 index 0000000..6dcf183 --- /dev/null +++ b/src/ast2/parser.rs @@ -0,0 +1,1915 @@ +use intern::{PointerFlags, SimpleType}; +use itertools::Itertools; +use num_bigint::{BigInt, BigUint}; + +use crate::{ + common::from_lo_hi_dwords, + comptime, + lexer::{Radix, TokenItem, TokenIterator}, + symbol_table::syms2::SymbolKind, + tokens::PRECEDENCE_MAP, + variant, +}; + +use super::*; + +#[derive(Debug)] +pub struct ErrorInfo { + error: ParseError, + loc: SourceLocation, +} + +#[derive(Debug)] +pub struct Parser { + pub ast: Ast, + pub intern: InternPool, + pub syms: crate::symbol_table::syms2::Symbols, + scopes: Vec, + pub errors: Vec, +} + +type ParseResult = core::result::Result; + +impl Display for Parser { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.display().render(f) + } +} + +impl Parser { + pub fn new() -> Parser { + Self { + ast: Ast::new(), + intern: InternPool::new(), + syms: crate::symbol_table::syms2::Symbols::new(), + scopes: Vec::new(), + errors: Vec::new(), + } + } + + pub fn display(&self) -> AstRenderer<'_> { + AstRenderer::new(&self.ast, &self.intern, &self.syms) + } + + pub fn node_display(&self, node: Index) -> NodeDisplay<'_> { + NodeDisplay { + node, + ast: &self.ast, + ip: &self.intern, + } + } + + pub fn create_comptime_folding_graph(&mut self, pointer_bits: u16) { + let mut type_cache = TypeCache::new(); + let mut cache = ComptimeCache::default(); + let mut nodes = self.ast.get_root_file_indices().collect::>(); + while let Some(node) = nodes.pop() { + if !self.ast.is_node_comptime_evaluable(&mut cache, node) { + nodes.extend(self.ast.get_node_children(node)); + } + } + + let mut node_map = Vec::::new(); + let edges = cache + .inner + .iter() + .filter(|(_, b)| **b) + .map(|(e, _)| self.ast.get_node_children(*e).into_iter().map(|d| (*e, d))) + .flatten() + // .map(|(a, b)| (a.into_u32(), b.into_u32())) + .map(|(a, b)| { + ( + node_map.iter().position(|&i| i == a).unwrap_or_else(|| { + node_map.push(a); + node_map.len() - 1 + }) as u32, + node_map.iter().position(|&i| i == b).unwrap_or_else(|| { + node_map.push(b); + node_map.len() - 1 + }) as u32, + ) + }) + .collect::>(); + + let extra_nodes = cache + .inner + .iter() + .filter(|(_, b)| **b) + .filter_map(|(i, _)| (!node_map.contains(i)).then(|| node_map.push(*i))) + .count(); + + eprintln!("cache: {cache:?}"); + eprintln!("node_map: {node_map:?}"); + eprintln!("edges: {edges:?}"); + + let mut graph = petgraph::stable_graph::StableDiGraph::<(), ()>::from_edges(edges); + for _ in 0..extra_nodes { + graph.add_node(()); + } + std::fs::write( + "comptime_graph.dot", + &format!( + "{:?}", + petgraph::dot::Dot::with_attr_getters( + &graph, + &[], + &|_graph, _edgeref| { "".to_string() }, + &|_graph, noderef| { format!("label = \"{}\"", node_map[noderef.0.index()]) } + ) + ), + ) + .expect("writing comptime graph repr"); + + while let Some(external) = graph.externals(petgraph::Direction::Outgoing).next() { + let node = node_map[external.index()]; + if !(self.ast.tags[node] == Tag::Constant || self.ast.tags[node].is_type()) + && self.ast.tags[node].is_expr() + { + eprintln!("folding {node}:\n{}", self.node_display(node)); + let value = self + .ast + .comptime_value_of_node(&self.intern, pointer_bits, &mut type_cache, node) + .expect(&format!("{node} has value of None?")); + let (value, ty) = comptime_number_to_interned_type_and_value( + &mut self.intern, + pointer_bits, + value, + ); + let ty = self.ast.push_interend_type(ty, self.ast.get_loc(node)); + self.ast.set_tag_data_source_loc( + node, + Tag::Constant, + Data::index_and_intern(ty, value), + self.ast.get_loc(node), + ); + } else { + eprintln!("rejecting {node}:\n{}", self.node_display(node)); + } + // comptime fold node + graph.remove_node(external); + } + } + + /// folds more AST-patterns into structures that are easier to build the IR with + pub fn fold_more_patterns(&mut self) { + use visitor::AstExt; + self.ast.visitor_mut().visit_post(|ast, _, _i, tag, data| { + match tag { + // normalise functions with block-with-trailing-expr into block + Tag::FunctionDecl => { + let (_, block) = data.as_two_indices(); + + let (block_tag, block_data) = ast.get_node_tag_and_data(block); + if block_tag == Tag::BlockTrailingExpr { + let (_, end) = block_data.as_extra_range(); + let end = end - 1; + let expr = Index::from_u32(ast.extra[end]).unwrap(); + let loc = ast.get_loc(expr); + let ret = ast.push_ret(Some(expr), loc); + // modify last element in place to be a return instruction + ast.extra[end] = ret.as_u32(); + ast.tags[block] = Tag::Block; + eprintln!("folding ({block}): {block_tag:?} into Tag::Block"); + eprintln!("expr: {expr:?}"); + } + } + _ => {} + } + }); + } + + pub fn intern_types(&mut self) { + self.ast.visitor_mut().visit_post(|ast, _, i, tag, data| { + match tag { + Tag::ArrayType => { + let (length, pointee) = data.as_two_indices(); + let pointee = + ast.datas[pointee].as_intern(); + variant!( self.intern.get_key(pointee) => intern::Key::PointerType { pointee, flags }); + + // get interened value from constant node + let length = { + let value = ast.datas[length] + .as_index_intern() + .1; + + match self.intern.get_key(value) { + intern::Key::SIntSmall { bits } => { + bits as u32 + } + intern::Key::UIntSmall { bits } => { + bits as u32 + } + intern::Key::SInt64 { bits } => { + bits as u32 + } + intern::Key::UInt64 { bits } => { + bits as u32 + } + intern::Key::NegativeInt { bigint } + | intern::Key::PositiveInt { bigint } => { + bigint + .iter_u32_digits() + .next() + .unwrap_or(0) + } + _ => 0, + } + }; + + let ty = self.intern.get_array_type( + pointee, + Some(flags), + length, + ); + ast.tags[i] = Tag::InternedType; + ast.datas[i] = Data::intern(ty); + } + Tag::PointerType => { + let (pointee, flags) = + data.as_index_and_extra_offset(); + let pointee = + ast.datas[pointee].as_intern(); + let ty = self.intern.get_pointer_type( + pointee, + Some(PointerFlags::unpack(flags as u8)), + ); + ast.tags[i] = Tag::InternedType; + ast.datas[i] = Data::intern(ty); + } + Tag::TypeDeclRef => { + let decl = data.as_index(); + let (name, _) = ast.datas[decl] + .as_intern_and_extra_offset(); + + let ty = + self.intern.get_struct_type(name, decl); + ast.tags[i] = Tag::InternedType; + ast.datas[i] = Data::intern(ty); + } + Tag::FunctionProto => { + let (_, i) = data.as_intern_and_extra_offset(); + let (return_type, parameter_list) = ( + Index::from_u32(ast.extra[i]).unwrap(), + Index::from_u32(ast.extra[i + 1]).unwrap(), + ); + let return_type = ast.get_type_of_node( + &self.intern, + &mut TypeCache::new(), + return_type + ); + let parameters = { + let (a, b) = ast.datas + [parameter_list] + .as_extra_range(); + ast.extra[a..b].iter() + .map(|&i| Index::from_u32(i).unwrap()) + .map(|i| { + // i is index to a parameter, a parameter is (index, intern) + let ty = ast.datas[i] + .as_index_intern() + .0; + ast.datas[ty].as_intern() + }) + }; + + self.intern + .get_function_type(return_type, parameters); + } + // Tag::VarDeclAssignment|Tag::MutVarDeclAssignment| + // Tag::VarDecl | Tag::MutVarDecl => { + // let (a,b) = + // data.as_extra_range(); + // let extra = &self.ast.extra[a..b]; + // let typed = Index::from_u32( + // extra.last().unwrap()).unwrap(); + // self.ast.get_type_of_node(&self.intern, cache, index) + // } + Tag::StructDecl => { + let (name, offset) = + data.as_intern_and_extra_offset(); + let flags = + StructFlags::unpack(ast.extra[offset]); + + let types = (offset + 1) + ..(offset + 1 + flags.num_fields as usize); + let names = + (offset + 1 + flags.num_fields as usize) + ..(offset + + 1 + + flags.num_fields as usize * 2); + + let types = ast.extra[types] + .iter() + .map(|&i| Index::from_u32(i).unwrap()) + .map(|i| { + ast.datas[i].as_intern() + }); + let names = ast.extra[names] + .iter() + .map(|&i| intern::Index::from_u32(i)); + + self.intern.insert_or_replace_struct_type( + name, + i, + flags.packed, + flags.c_like, + names.zip(types), + ); + } + _ => {} + } + }); + } + + pub fn resolve_decl_refs(&mut self) { + self.ast + .visitor_rev_mut() + .visit_post(|ast, _, node, tag, _| { + match tag { + Tag::TypeDeclRefUnresolved => { + let (scope, name) = ast.datas[node].as_index_intern(); + // look in my_scope + if let Some((_, decl)) = + self.syms + .find_type_symbol(scope, name, ast.source_locs[node]) + { + ast.resolve_type_ref(node, decl) + }; + } + Tag::DeclRefUnresolved => { + let (scope, name) = ast.datas[node].as_index_intern(); + + // look in my_scope + if let Some((key, decl)) = + self.syms.find_symbol(scope, name, ast.source_locs[node]) + { + ast.resolve_decl_ref( + node, + decl, + Option::::from(key.kind().unwrap()).unwrap(), + ) + }; + } + _ => {} + } + }); + } + + fn current_scope(&self) -> Index { + self.scopes.last().cloned().unwrap() + } + + fn parse_ident(&mut self, tokens: &mut TokenIterator) -> Result { + let ident = tokens.expect_token(Token::Ident).map_err(|_| ErrorInfo { + error: ParseError::ExpectedIdent, + loc: tokens.current_source_location(), + })?; + + let name = self.intern.get_or_insert(intern::Key::String { + str: ident.lexeme(), + }); + + Ok(name) + } + + fn parse_pointer(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + tokens.eat_token(Token::Star).ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Star), + loc: tokens.current_source_location(), + })?; + + let &[cnst, vol, noalias] = + &tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3] + else { + unreachable!() + }; + let pointee = self.parse_type(tokens)?; + + Ok(self + .ast + .push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc)) + } + + /// [LENGTH]const? volatile? noalias? TYPE + fn parse_array_type(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + let length_expr = self.parse_bracketed(tokens, |this, tokens| { + this.parse_value_expr(tokens) + // let next = tokens.peek_token().ok_or(ErrorInfo { + // error: ParseError::UnexpectedEndOfTokens, + // loc: tokens.current_source_location(), + // })?; + // match next.token() { + // Token::IntegerBinConstant + // | Token::IntegerHexConstant + // | Token::IntegerOctConstant + // | Token::IntegerConstant => { + // _ = tokens.next(); + // Ok(this.parse_integral_constant(&next, next.source_location())) + // } + // _ => Err(ErrorInfo { + // error: ParseError::ExpectedConstantLiteral, + // loc: tokens.current_source_location(), + // }), + // } + })?; + + let &[cnst, vol, noalias] = + &tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3] + else { + unreachable!() + }; + + let pointee = self.parse_type(tokens)?; + let pointer = + self.ast + .push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc); + + Ok(self.ast.push_array_type(length_expr, pointer, loc)) + } + + fn parse_simple_type(&mut self, token: Token) -> Option { + match token { + Token::Void => Some(self.intern.get_assume_present(&intern::Key::SimpleType { + ty: SimpleType::Void, + })), + Token::Bool => Some(self.intern.get_assume_present(&intern::Key::SimpleType { + ty: SimpleType::Bool, + })), + Token::F32 => Some(self.intern.get_assume_present(&intern::Key::SimpleType { + ty: SimpleType::F32, + })), + Token::F64 => Some(self.intern.get_assume_present(&intern::Key::SimpleType { + ty: SimpleType::F64, + })), + Token::USize => Some(self.intern.get_assume_present(&intern::Key::SimpleType { + ty: SimpleType::USize, + })), + Token::ISize => Some(self.intern.get_assume_present(&intern::Key::SimpleType { + ty: SimpleType::ISize, + })), + _ => None, + } + } + + fn try_parse_integral_type( + &mut self, + typename: &str, + ) -> Result, ParseError> { + let mut iter = typename.chars().peekable(); + let signed = match iter.next() { + Some('u') => false, + Some('i') => true, + _ => { + return Ok(None); + } + }; + + // need 1 digit for an integral type + if iter.peek().map(|&c| crate::common::is_digit(c)) != Some(true) { + return Ok(None); + } + + // need no nondigits after digits + if iter + .clone() + .skip_while(|&c| crate::common::is_digit(c)) + .next() + .is_some() + { + return Ok(None); + } + + let mut bits = 0u16; + loop { + let Some(digit) = iter.next().map(|c| c as u8 - b'0') else { + break; + }; + + match bits + .checked_mul(10) + .and_then(|bits| bits.checked_add(digit as u16)) + { + Some(val) => { + bits = val; + } + None => { + // this IS an integral type, but it is bigger than u/i65535 + return Err(ParseError::IntegralTypeTooWide); + } + } + } + + Ok(Some(self.intern.get_int_type(signed, bits))) + } + + fn parse_integral_constant_inner( + &mut self, + item: &TokenItem, + ) -> (intern::Index, intern::Index) { + let radix = Radix::from_token(item.token()).unwrap(); + + let mut chars = item.lexeme().char_indices(); + match radix { + Radix::Dec => {} + _ => { + _ = chars.advance_by(2); + } + } + + let digits = chars + .take_while_ref(|&(_, c)| radix.is_digit()(c) || c == '_') + .filter(|&(_, c)| c != '_') + .map(|(_, c)| c) + .collect::>(); + + let value = comptime::bigint::parse_bigint(digits.into_iter(), radix); + + let ty = match chars.clone().next() { + Some((i, 'u')) | Some((i, 'i')) => self + .try_parse_integral_type(&item.lexeme()[i..]) + .expect("invalid integral type??"), + _ => None, + }; + + let interned = match value.len() { + ..1 => { + let bits = value.get(0).cloned().unwrap_or(0); + self.intern.get_or_insert(intern::Key::UIntSmall { bits }) + } + ..2 => { + let lo = value.get(0).cloned().unwrap_or(0); + let hi = value.get(1).cloned().unwrap_or(0); + let bits = from_lo_hi_dwords(lo, hi); + self.intern.get_or_insert(intern::Key::UInt64 { bits }) + } + _ => { + let bigint = BigInt::from_biguint(num_bigint::Sign::Plus, BigUint::new(value)); + self.intern + .get_or_insert(intern::Key::PositiveInt { bigint }) + } + }; + + let ty = ty.unwrap_or(self.intern.get_comptime_int_type()); + (interned, ty) + } + + fn parse_integral_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index { + let (interned, ty) = self.parse_integral_constant_inner(item); + let ty = self.ast.push_interend_type(ty, loc); + return self.ast.push_constant(interned, ty, loc); + } + + fn parse_floating_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index { + let lexeme = item.lexeme(); + let lexeme = lexeme + .strip_suffix("f32") + .map(|l| (l, self.intern.get_f32_type())) + .unwrap_or( + lexeme + .strip_suffix("f64") + .map(|l| (l, self.intern.get_f64_type())) + .unwrap_or((lexeme, self.intern.get_f64_type())), + ); + + let bits = if lexeme.1 == self.intern.get_f32_type() { + self.intern.get_or_insert(intern::Key::F32 { + bits: lexeme.0.parse::().unwrap(), + }) + } else { + self.intern.get_or_insert(intern::Key::F64 { + bits: lexeme.0.parse::().unwrap(), + }) + }; + + let ty = self.ast.push_interend_type(lexeme.1, loc); + return self.ast.push_constant(bits, ty, loc); + } + + /// TYPE <- + /// * TYPE + /// IDENTIFIER + /// SIMPLE_TYPE + /// [ TYPE ; CONSTANT_EXPR ] + /// INTEGRAL_TYPE // u[0..65535] | i[0..65535] + fn parse_type(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + match tokens + .peek_token() + .ok_or(ErrorInfo { + error: ParseError::ExpectedTypeName, + loc: tokens.current_source_location(), + })? + .token() + { + Token::Star => self.parse_pointer(tokens), + Token::OpenSquareBracket => self.parse_array_type(tokens), + Token::Ident => { + let token = tokens.next().unwrap(); + match self + .try_parse_integral_type(token.lexeme()) + .map_err(|error| ErrorInfo { + error, + loc: token.source_location(), + })? { + Some(int) => Ok(self.ast.push_interend_type(int, loc)), + None => { + let name = self.intern.get_or_insert(intern::Key::String { + str: token.lexeme(), + }); + // TODO: this will cause issues with redefinitions of types with the same name + // and actually, make type into a proper node of the ast + Ok(self + .ast + .push_type_ref_unresolved(self.current_scope(), name, loc)) + } + } + } + token => { + let ty = self.parse_simple_type(token).ok_or(ErrorInfo { + error: ParseError::ExpectedTypeName, + loc: tokens.current_source_location(), + })?; + _ = tokens.next(); + + Ok(self.ast.push_interend_type(ty, loc)) + } + } + } + + /// GLOBAL_DECL <- + /// const IDENTIFIER: TYPENAME = EXPR; + fn parse_const_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let err = 'blk: { + let loc = tokens.current_source_location(); + let Some(_) = tokens.eat_token(Token::Const) else { + break 'blk ErrorInfo { + error: ParseError::ExpectedToken(Token::Const), + loc, + }; + }; + + let ident = match self.parse_ident(tokens) { + Ok(i) => i, + Err(err) => { + break 'blk err; + } + }; + + let Some(_) = tokens.eat_token(Token::Colon) else { + return Err(ErrorInfo { + error: ParseError::ExpectedToken(Token::Colon), + loc, + }); + }; + + let typename = match self.parse_type(tokens) { + Ok(i) => i, + Err(err) => { + break 'blk err; + } + }; + + let Some(_) = tokens.eat_token(Token::Equal) else { + break 'blk ErrorInfo { + error: ParseError::ExpectedToken(Token::Equal), + loc: tokens.current_source_location(), + }; + }; + + let expr = match self.parse_value_expr(tokens) { + Ok(i) => i, + Err(err) => { + break 'blk err; + } + }; + + let Some(_) = tokens.eat_token(Token::Semi) else { + break 'blk ErrorInfo { + error: ParseError::ExpectedToken(Token::Semi), + loc: tokens.current_source_location(), + }; + }; + + let decl = self.ast.push_global_decl(ident, typename, expr, loc); + self.syms + .insert_symbol(self.current_scope(), ident, SymbolKind::Const, decl); + + return Ok(decl); + }; + + tokens.advance_past_semi().ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Semi), + loc: tokens.current_source_location(), + })?; + + Ok(self.ast.push_error(err.error, err.loc)) + } + + /// FUNCTION_PROTO <- + /// fn IDENTIFIER () + /// fn IDENTIFIER () -> TYPENAME + /// fn IDENTIFIER ( PARAMETER_LIST ,? ) + /// fn IDENTIFIER ( PARAMETER_LIST ,? ) -> TYPENAME + fn parse_fn_proto( + &mut self, + tokens: &mut TokenIterator, + ) -> ParseResult<(Index, intern::Index)> { + let loc = tokens.current_source_location(); + let _ = tokens.eat_token(Token::Fn).ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Fn), + loc, + })?; + + let ident = self.parse_ident(tokens)?; + + let parameters = self.parse_parenthesised(tokens, |this, tokens| { + if tokens.is_next_token(Token::CloseParens) { + Ok(this.ast.push_parameter_list([], loc)) + } else { + this.parse_parameter_list(tokens) + } + })?; + + let return_type = if let Some(_) = tokens.eat_token(Token::MinusGreater) { + self.parse_type(tokens)? + } else { + self.ast.push_interend_type( + self.intern.get_void_type(), + tokens.current_source_location(), + ) + }; + + let decl = self.ast.push_fn_proto(ident, return_type, parameters, loc); + + Ok((decl, ident)) + } + + fn parse_fn_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + let func = self.ast.reserve_node(Kind::Function); + + self.push_scope(func, intern::Index::invalid()); + + let (proto, ident) = self.parse_fn_proto(tokens).map_err(|e| { + self.pop_scope(); + e + })?; + let body = self + .parse_block(tokens) + .map(|pv| self.convert_to_value_expr(pv)) + .map_err(|e| { + self.pop_scope(); + e + })?; + + self.pop_scope(); + + self.ast.set_fn_decl(func, proto, body, loc); + + self.syms + .insert_symbol(self.current_scope(), ident, SymbolKind::Function, func); + + Ok(func) + } + + /// FUNCTION_DECL <- + /// FUNCTION_PROTO BLOCK + fn parse_fn_decl(&mut self, tokens: &mut TokenIterator) -> Index { + match self.parse_fn_inner(tokens) { + Ok(i) => i, + Err(err) => { + self.find_next_fn_or_const(tokens); + self.push_error(err.error, err.loc) + } + } + } + + /// RETURN_STATEMENT <- + /// return EXPRESSION? ; + fn parse_return_stmt(&mut self, tokens: &mut TokenIterator) -> ParseResult { + // SAFETY: function invariance + let ret = tokens.next().unwrap(); + let loc = ret.source_location(); + + let expr = if tokens.eat_token(Token::Semi).is_some() { + self.ast.push_ret(None, loc) + } else { + match self.parse_value_expr(tokens) { + Ok(i) => { + tokens.eat_token(Token::Semi).ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Semi), + loc: tokens.current_source_location(), + })?; + self.ast.push_ret(Some(i), loc) + } + Err(err) => { + tokens.advance_past_semi().ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Semi), + loc: tokens.current_source_location(), + })?; + self.push_error(err.error, err.loc) + } + } + }; + + Ok(expr) + } + + /// VAR_DECL <- + /// (let | var) IDENTIFIER (: TYPENAME)? ; + /// (let | var) IDENTIFIER (: TYPENAME)? = EXPRESSION ; + fn parse_var_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult { + self.parse_with_trailing_semi(tokens, Self::parse_var_decl_inner) + } + + fn parse_var_decl_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult { + // SAFETY: function invariance + let let_or_var = tokens.next().unwrap(); + let loc = let_or_var.source_location(); + + let is_let = let_or_var.token() == Token::Let; + + let name = self.parse_ident(tokens)?; + + let ty = if tokens.eat_token(Token::Colon).is_some() { + Some(self.parse_type(tokens)?) + } else { + None + }; + + let assignment = if tokens.eat_token(Token::Equal).is_some() { + Some(self.parse_value_expr(tokens)?) + } else { + None + }; + + let decl = self.ast.push_var_decl(is_let, name, ty, assignment, loc); + self.syms.insert_symbol( + self.current_scope(), + name, + SymbolKind::Local(tokens.current_source_location()), + decl, + ); + + Ok(decl) + } + + fn parse_block_inner( + &mut self, + block: Index, + tokens: &mut TokenIterator, + ) -> ParseResult { + let loc = tokens.current_source_location(); + let mut statements = Vec::new(); + + let trailing = loop { + if tokens.is_next_token(Token::CloseBrace) { + break None; + } + let next = tokens.peek_token().ok_or(ErrorInfo { + error: ParseError::UnexpectedEndOfTokens, + loc: tokens.current_source_location(), + })?; + + if let Some(decl) = self.parse_constant_decls(tokens)? { + statements.push(decl); + } else { + match next.token() { + Token::Return => { + statements.push(self.parse_return_stmt(tokens)?); + } + Token::Var | Token::Let => { + statements.push(self.parse_var_decl(tokens)?); + } + _ => { + if self.is_statement(tokens) { + // expr -> statements + let expr = self.parse_with_trailing_semi(tokens, |this, tokens| { + Ok(this.parse_expr(tokens)?.into_index()) + })?; + + statements.push(expr); + } else { + // expr -> trailing + let expr = self.parse_expr(tokens)?; + if !tokens.is_next_token(Token::CloseBrace) { + statements.push(self.push_error( + ParseError::ExpectedEndOfBlock, + tokens.current_source_location(), + )); + } else { + break Some(expr); + } + } + } + } + } + }; + + self.ast.set_block( + block, + statements, + trailing.map(PlaceOrValue::into_index), + loc, + ); + + let block = trailing + .map(|pv| pv.with_index(block)) + .unwrap_or(PlaceOrValue::Value(block)); + Ok(block) + } + + /// BLOCK <- + /// { STATEMENT* EXPRESSION? } + fn parse_block(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let block = self.parse_braced(tokens, |this, tokens| { + let block = this.ast.reserve_node_other(); + this.push_scope(block, intern::Index::invalid()); + let block_result = this.parse_block_inner(block, tokens); + this.pop_scope(); + + block_result + })?; + + Ok(block) + } + + /// PARAMETER_LIST <- + /// PARAMETER + /// PARAMETER_LIST , ARGUMENT + fn parse_parameter_list(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + + let mut params = Vec::new(); + loop { + params.push(self.parse_parameter(tokens)?); + + if !tokens.is_next_token(Token::Comma) { + break; + } + if tokens.is_next_token2(Token::CloseParens) { + break; + } + // skip comma + _ = tokens.next(); + } + + return Ok(self.ast.push_parameter_list(params, loc)); + } + + /// PARAMETER <- + /// IDENT : TYPENAME + fn parse_parameter(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + let name = self.parse_ident(tokens)?; + let Some(_) = tokens.eat_token(Token::Colon) else { + return Err(ErrorInfo { + error: ParseError::ExpectedToken(Token::Colon), + loc, + }); + }; + let ty = self.parse_type(tokens)?; + + let param = self.ast.push_parameter(name, ty, loc); + self.syms.insert_symbol( + self.current_scope(), + name, + SymbolKind::Parameter(loc), + param, + ); + + return Ok(param); + } + + /// ARGUMENT <- + /// IDENT : EXPR + /// EXPR + fn parse_argument(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + let name = if tokens.is_next_token2(Token::Colon) && tokens.is_next_token(Token::Ident) { + let name = self.parse_ident(tokens)?; + // we checked `is_next_token2` + _ = tokens.eat_token(Token::Colon).unwrap(); + Some(name) + } else { + None + }; + let expr = self.parse_value_expr(tokens)?; + + let i = match name { + Some(name) => self.ast.push_named_argument(name, expr, loc), + None => self.ast.push_argument(expr, loc), + }; + + Ok(i) + } + + /// ARGUMENT_LIST <- + /// ARGUMENT + /// ARGUMENT_LIST , ARGUMENT + fn parse_argument_list(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + let mut args = Vec::new(); + loop { + args.push(self.parse_argument(tokens)?); + + if !tokens.is_next_token(Token::Comma) { + break; + } + if tokens.is_next_token2(Token::CloseParens) { + break; + } + // skip comma + _ = tokens.next(); + } + return Ok(self.ast.push_argument_list(args, loc)); + } + + /// PRIMARY_EXPR <- + /// IDENTIFIER + /// INTEGER_CONSTANT + /// FLOATING_CONSTANT + /// ( EXPRESSION ) + /// BLOCK + fn parse_primary_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + + let Some(next) = tokens.peek_token() else { + return Err(ErrorInfo { + error: ParseError::ExpectedPrimaryExpression, + loc, + }); + }; + + match next.token() { + Token::IntegerBinConstant + | Token::IntegerHexConstant + | Token::IntegerOctConstant + | Token::IntegerConstant => { + _ = tokens.next(); + return Ok(PlaceOrValue::Value( + self.parse_integral_constant(&next, next.source_location()), + )); + } + Token::FloatingConstant + | Token::FloatingExpConstant + | Token::DotFloatingConstant + | Token::DotFloatingExpConstant => { + _ = tokens.next(); + return Ok(PlaceOrValue::Value( + self.parse_floating_constant(&next, next.source_location()), + )); + } + + Token::OpenParens => { + let expr = + self.parse_parenthesised(tokens, |this, tokens| this.parse_expr(tokens))?; + + return Ok(expr); + } + Token::OpenBrace => { + return Ok(self.parse_block(tokens)?); + } + Token::Ident => { + _ = tokens.next(); + let ident = next.lexeme(); + let ident = self + .intern + .get_or_insert(intern::Key::String { str: ident }); + + return Ok(PlaceOrValue::Place(self.ast.push_decl_ref_unresolved( + self.current_scope(), + ident, + loc, + ))); + } + // TODO: eventually handle paths + _ => { + return Err(ErrorInfo { + error: ParseError::ExpectedPrimaryExpression, + loc, + }); + } + } + } + + /// POSTFIX_EXPR <- + /// PRIMARY_EXPR + /// PRIMARY_EXPR ( ) + /// PRIMARY_EXPR ( ARGUMENT_LIST ) + /// PRIMARY_EXPR [ EXPR ] + /// POSTFIX_EXPR . IDENTIFIER + fn parse_postfix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let mut lhs = self.parse_primary_expr(tokens)?; + while let Some(postfix) = self.try_parse_postfix_expr_inner(tokens, lhs)? { + lhs = postfix; + } + + Ok(lhs) + } + + fn try_parse_postfix_expr_inner( + &mut self, + tokens: &mut TokenIterator, + lhs: PlaceOrValue, + ) -> ParseResult> { + let lhs = if let Some(next) = tokens.peek_token() { + let loc = next.source_location(); + match next.token() { + Token::OpenParens => { + let arguments = self.parse_parenthesised(tokens, |this, tokens| { + if tokens.is_next_token(Token::CloseParens) { + Ok(this.ast.push_argument_list([], loc)) + } else { + this.parse_argument_list(tokens) + } + })?; + let lhs = self.convert_to_value_expr(lhs); + + Some(PlaceOrValue::Value( + self.ast.push_call_expr(lhs, arguments, loc), + )) + } + Token::OpenSquareBracket => { + let subscript = + self.parse_bracketed(tokens, |this, tokens| this.parse_value_expr(tokens))?; + + let lhs = self.convert_to_value_expr(lhs); + + Some(PlaceOrValue::Place(self.ast.push_binary( + Tag::SubscriptExpr, + lhs, + subscript, + loc, + ))) + } + Token::Dot if tokens.is_next_token2(Token::Ident) => { + _ = tokens.next(); + let loc = tokens.current_source_location(); + let lhs = self.convert_to_place_expr(lhs); + let name = self.parse_ident(tokens)?; + + Some(self.ast.push_field_access(lhs, name, loc)) + } + _ => None, + } + } else { + None + }; + + Ok(lhs) + } + + fn push_error(&mut self, error: ParseError, loc: SourceLocation) -> Index { + self.errors.push(ErrorInfo { error, loc }); + self.ast.push_error(error, loc) + } + + /// converts the expression to a value expression, if it isn't one already. + fn convert_to_value_expr(&mut self, lrvalue: PlaceOrValue) -> Index { + match lrvalue { + PlaceOrValue::Value(index) => index, + PlaceOrValue::Place(index) => self.ast.push_place_to_value_conversion(index), + } + } + + /// converts the expression to a place expression, if it isn't one already. + fn convert_to_place_expr(&mut self, lrvalue: PlaceOrValue) -> Index { + match lrvalue { + PlaceOrValue::Place(index) => index, + PlaceOrValue::Value(index) => self.ast.push_value_to_place_conversion(index), + } + } + + /// PREFIX_EXPR <- + /// POSTFIX_EXPR + /// ! POSTFIX_EXPR + /// - POSTFIX_EXPR + /// & POSTFIX_EXPR + /// * POSTFIX_EXPR + fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let next = tokens.peek_token().ok_or(ErrorInfo { + error: ParseError::ExpectedPrefixExpression, + loc: tokens.current_source_location(), + })?; + + let loc = next.source_location(); + + let expr = match next.token() { + Token::Bang => { + _ = tokens.next(); + let lhs = self.parse_prefix_expr(tokens)?; + let lhs = self.convert_to_value_expr(lhs); + self.ast.push_unary(Tag::Not, lhs, loc) + } + Token::Minus => { + _ = tokens.next(); + let lhs = self.parse_prefix_expr(tokens)?; + let lhs = self.convert_to_value_expr(lhs); + self.ast.push_unary(Tag::Negate, lhs, loc) + } + Token::Ampersand => { + _ = tokens.next(); + // the address-of operator requires lhs to be a place + // expression. not all expressions that might be the lhs + // are automatically place expressions: the construct `let a + // = &3;` has `3`, which is a value expression, as the lhs + // of the address-of operator. + let lhs = self.parse_prefix_expr(tokens)?; + let lhs = self.convert_to_place_expr(lhs); + self.ast.push_unary(Tag::AddressOf, lhs, loc) + } + Token::Star => { + _ = tokens.next(); + let lhs = self.parse_prefix_expr(tokens)?; + self.ast.push_unary(Tag::Deref, lhs.into_index(), loc) + } + _ => self.parse_postfix_expr(tokens)?, + }; + + Ok(expr) + } + + /// AS_EXPR <- + /// PREFIX_EXPR + /// PREFIX_EXPR as TYPENAME + fn parse_as_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + let expr = self.parse_prefix_expr(tokens)?; + + if tokens.eat_token(Token::As).is_some() { + let typename = self.parse_type(tokens)?; + let expr = self.convert_to_value_expr(expr); + + return Ok(PlaceOrValue::Value(self.ast.push_cast(expr, typename, loc))); + } else { + return Ok(expr); + } + } + + /// BINARY_EXPR <- + /// AS_EXPR + /// AS_EXPR * EXPRESSION + /// AS_EXPR / EXPRESSION + /// AS_EXPR % EXPRESSION + /// AS_EXPR + EXPRESSION + /// AS_EXPR - EXPRESSION + /// AS_EXPR << EXPRESSION + /// AS_EXPR >> EXPRESSION + /// AS_EXPR < EXPRESSION + /// AS_EXPR > EXPRESSION + /// AS_EXPR <= EXPRESSION + /// AS_EXPR >= EXPRESSION + /// AS_EXPR == EXPRESSION + /// AS_EXPR != EXPRESSION + /// AS_EXPR & EXPRESSION + /// AS_EXPR ^ EXPRESSION + /// AS_EXPR | EXPRESSION + /// AS_EXPR && EXPRESSION + /// AS_EXPR || EXPRESSION + fn parse_binary_expr( + &mut self, + tokens: &mut TokenIterator, + precedence: u32, + ) -> ParseResult { + let mut node = self.parse_as_expr(tokens)?; + + loop { + let Some(tok) = tokens.peek_token() else { + break; + }; + let loc = tok.source_location(); + let Some(prec) = PRECEDENCE_MAP.get(&tok.token()).cloned() else { + break; + }; + + if prec < precedence { + break; + } + + // SAFETY: we peeked `tok` + let tok = tokens.next().unwrap(); + + let lhs = self.convert_to_value_expr(node); + let rhs = self.parse_binary_expr(tokens, prec + 1)?; + let rhs = self.convert_to_value_expr(rhs); + + let tag = match tok.token() { + Token::PipePipe => Tag::Or, + Token::AmpersandAmpersand => Tag::And, + Token::Pipe => Tag::BitOr, + Token::Caret => Tag::BitXOr, + Token::Ampersand => Tag::BitAnd, + Token::BangEqual => Tag::NEq, + Token::EqualEqual => Tag::Eq, + Token::LessEqual => Tag::Le, + Token::GreaterEqual => Tag::Ge, + Token::Less => Tag::Lt, + Token::Greater => Tag::Gt, + Token::GreaterGreater => Tag::Shr, + Token::LessLess => Tag::Shl, + Token::Plus => Tag::Add, + Token::Minus => Tag::Sub, + Token::Percent => Tag::Rem, + Token::Star => Tag::Mul, + Token::Slash => Tag::Div, + _ => unreachable!(), + }; + + node = PlaceOrValue::Value(self.ast.push_binary(tag, lhs, rhs, loc)); + } + + Ok(node) + } + + /// ASSIGNMENT_EXPR <- + /// BINARY_EXPRESSION + /// BINARY_EXPRESSION ASSIGNMENT_OP EXPRESSION + /// ASSIGNMENT_OP <- + /// = += -= *= /= %= ... + fn parse_assignment_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let lhs = self.parse_binary_expr(tokens, 0)?; + + if tokens + .peek_token() + .map(|itm| itm.token().is_assignment_op()) + == Some(true) + { + // SAFETY: we peeked + let op = tokens.next().unwrap(); + let loc = op.source_location(); + // rhs (src) must be a value + let rhs = self.parse_value_expr(tokens)?; + + let rhs = if op.token() == Token::Equal { + rhs + } else { + let tag = match op.token() { + Token::PlusEqual => Tag::Add, + Token::MinusEqual => Tag::Sub, + Token::StarEqual => Tag::Mul, + Token::SlashEqual => Tag::Sub, + Token::PercentEqual => Tag::Rem, + Token::PipeEqual => Tag::BitOr, + Token::CaretEqual => Tag::BitXOr, + Token::AmpersandEqual => Tag::BitAnd, + Token::LessLessEqual => Tag::Shl, + Token::GreaterGreaterEqual => Tag::Shr, + _ => { + unreachable!() + } + }; + + // convert lhs (dest) to value + let lhs = self.convert_to_value_expr(lhs); + self.ast.push_binary(tag, lhs, rhs, loc) + }; + + // for the assignment, lhs (dest) must be a place + // I think this is the only case where the AST is a dag. + let lhs = self.convert_to_place_expr(lhs); + // the assignment is a value + Ok(PlaceOrValue::Value(self.ast.push_assign(lhs, rhs, loc))) + } else { + // but if we don't have an assignment, this might be a place + Ok(lhs) + } + } + + /// ELSE_EXPR <- + /// 'else' (IF_EXPR | EXPR_OR_STATEMENT_OR_BLOCK) + fn parse_else_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + // SAFETY: function invariance + let _else_ = tokens.eat_token(Token::Else).unwrap(); + + if tokens.is_next_token(Token::If) { + self.parse_if_expr(tokens) + } else { + self.parse_expr_or_block_as_block(tokens) + } + } + + /// IF_EXPR <- + /// 'if' ( EXPR ) EXPR_OR_STATEMENT_OR_BLOCK ELSE_EXPR? + fn parse_if_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + // SAFETY: function invariance + let iff = tokens.eat_token(Token::If).unwrap(); + let loc = iff.source_location(); + + let cond = + self.parse_parenthesised(tokens, |this, tokens| this.parse_value_expr(tokens))?; + + let body = self.parse_expr_or_block_as_block(tokens)?; + + if tokens.is_next_token(Token::Else) { + let else_expr = self.parse_else_expr(tokens)?; + Ok(body.with_index(self.ast.push_if_else( + cond, + body.into_index(), + else_expr.into_index(), + loc, + ))) + } else { + Ok(body.with_index(self.ast.push_if(cond, body.into_index(), loc))) + } + } + + fn parse_expr_or_block_as_block( + &mut self, + tokens: &mut TokenIterator, + ) -> ParseResult { + let Some(next) = tokens.peek_token() else { + return Err(ErrorInfo { + error: ParseError::ExpectedExpression, + loc: tokens.current_source_location(), + }); + }; + + match next.token() { + Token::OpenBrace => self.parse_block(tokens), + _ => { + let loc = tokens.current_source_location(); + let expr = self.parse_expr(tokens)?; + Ok(expr.with_index(self.ast.push_block([], Some(expr.into_index()), loc))) + } + } + } + + fn parse_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + let loc = tokens.current_source_location(); + let Some(next) = tokens.peek_token() else { + return Err(ErrorInfo { + error: ParseError::ExpectedExpression, + loc, + }); + }; + + let expr = match next.token() { + Token::If => self.parse_if_expr(tokens)?, + _ => self.parse_assignment_expr(tokens)?, + }; + + Ok(expr) + } + + fn parse_place_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + // TODO: panic if not place expr + let expr = self.parse_expr(tokens)?; + let expr = self.convert_to_place_expr(expr); + + Ok(expr) + } + fn parse_value_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult { + // TODO: convert from place to value (lvalue-to-rvalue) + let expr = self.parse_expr(tokens)?; + let expr = self.convert_to_value_expr(expr); + + Ok(expr) + } + + /// TYPE_DECL <- + /// type IDENTIFIER = TYPE_UNION ; + /// type IDENTIFIER = '(' (TYPE,)* ')' ; + /// type IDENTIFIER = extern? union { (IDENTIFIER: TYPE,)* } + /// type IDENTIFIER = extern? packed? enum { (IDENTIFIER (= EXPRESSION),)* } + /// type IDENTIFIER = extern? packed? struct { (IDENTIFIER: TYPE,)* } + fn parse_type_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult { + _ = tokens.eat_token(Token::Type).ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Type), + loc: tokens.current_source_location(), + }); + + let name = self.parse_ident(tokens)?; + let loc = tokens.current_source_location(); + + _ = tokens.eat_token(Token::Equal).ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Equal), + loc: tokens.current_source_location(), + }); + + let (has_attributes, c_like, packed) = { + let vec = tokens.eat_all_zero_or_once(&[Token::Extern, Token::Packed]); + (vec[0] || vec[1], vec[0], vec[1]) + }; + + let Some(next) = tokens.peek_token() else { + return Err(ErrorInfo { + error: ParseError::ExpectedTypeDeclaration, + loc: tokens.current_source_location(), + }); + }; + + let decl = match next.token() { + Token::Struct => self.parse_struct_decl(tokens, name, c_like, packed, loc), + Token::Union => { + unimplemented!() + } + Token::Enum => { + unimplemented!() + } + _ => { + if has_attributes { + return Err(ErrorInfo { + error: ParseError::UnexpectedTypeAttributes, + loc: tokens.current_source_location(), + }); + } + match next.token() { + Token::OpenParens => { + // tuple + unimplemented!() + } + Token::Ident => { + // sumtype + unimplemented!() + } + _ => { + return Err(ErrorInfo { + error: ParseError::ExpectedTypeDeclaration, + loc: tokens.current_source_location(), + }); + } + } + } + }?; + + self.syms + .insert_symbol(self.current_scope(), name, SymbolKind::Type, decl); + + Ok(decl) + } + + /// SUMTYPE_DECL <- + /// type IDENTIFIER = TYPE_UNION + /// TYPE_UNION <- + /// TYPE (| TYPE_UNION)? + /// IDENTIFIER: TYPE (| TYPE_UNION)? + fn parse_sumtype_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { + todo!() + } + + /// TUPLE_DECL <- + /// type IDENTIFIER = (TYPE,* ) + fn parse_tuple_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { + todo!() + } + + /// UNION_DECL <- + /// type IDENTIFIER = union { IDENTIFIER: TYPE,* } + fn parse_union_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { + todo!() + } + + /// ENUM_DECL <- + /// type IDENTIFIER = packed? enum { IDENTIFIER (= EXPRESSION),* } + fn parse_enum_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult { + todo!() + } + + /// STRUCT_DECL <- + /// type IDENTIFIER = extern? packed? struct { STRUCT_FIELD,* } + fn parse_struct_decl( + &mut self, + tokens: &mut TokenIterator, + name: intern::Index, + c_like: bool, + packed: bool, + loc: SourceLocation, + ) -> ParseResult { + // SAFETY: function invariance + + _ = tokens.eat_token(Token::Struct).ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Struct), + loc: tokens.current_source_location(), + })?; + + let decl = self.ast.reserve_node(Kind::GlobalDecl); + let decl = self.parse_braced(tokens, |this, tokens| { + this.parse_struct_fields(tokens).map(|fields| { + _ = tokens.eat_token(Token::Comma); + let flags = StructFlags::new(packed, c_like, fields.len() as u32); + + this.intern.insert_or_replace_struct_type( + name, + decl, + flags.packed, + flags.c_like, + vec![], + ); + + this.ast.set_struct_decl(decl, name, flags, fields, loc) + }) + })?; + + Ok(decl) + } + + fn parse_with_trailing_semi( + &mut self, + tokens: &mut TokenIterator, + parse: F, + ) -> ParseResult + where + F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, + Index: Into, + { + match parse(self, tokens) { + Ok(i) => { + _ = tokens.eat_token(Token::Semi).ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Semi), + loc: tokens.current_source_location(), + })?; + + Ok(i) + } + Err(err) => { + tokens.advance_past_semi().ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Semi), + loc: tokens.current_source_location(), + })?; + Ok(self.push_error(err.error, err.loc).into()) + } + } + } + + fn parse_inner( + &mut self, + tokens: &mut TokenIterator, + open: Token, + close: Token, + parse: F, + on_err: E, + ) -> ParseResult + where + F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, + E: FnOnce(&mut Self, &mut TokenIterator, ErrorInfo, TokenItem) -> ParseResult, + { + let Some(start) = tokens.eat_token(open) else { + return Err(ErrorInfo { + error: ParseError::ExpectedToken(open), + loc: tokens.current_source_location(), + }); + }; + + match parse(self, tokens) { + Ok(i) => { + _ = tokens.eat_token(close).ok_or(ErrorInfo { + error: match open { + Token::OpenBrace => ParseError::UnmatchedBrace(start.token_pos().start), + Token::OpenParens => ParseError::UnmatchedParens(start.token_pos().start), + Token::OpenSquareBracket => { + ParseError::UnmatchedSquareBracket(start.token_pos().start) + } + _ => ParseError::UnmatchedDelimiter(start.token_pos().start), + }, + loc: tokens.current_source_location(), + })?; + + Ok(i) + } + Err(e) => on_err(self, tokens, e, start), + } + } + + fn parse_inner2( + &mut self, + tokens: &mut TokenIterator, + open: Token, + close: Token, + parse: F, + ) -> ParseResult + where + F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, + Index: Into, + // I: From, + { + self.parse_inner(tokens, open, close, parse, |this, tokens, err, start| { + match close { + Token::CloseBrace => { + tokens.advance_past_end_of_braced().ok_or(ErrorInfo { + error: ParseError::UnmatchedBrace(start.token_pos().start), + loc: tokens.current_source_location(), + })?; + } + Token::CloseParens => { + tokens.advance_past_end_of_parens().ok_or(ErrorInfo { + error: ParseError::UnmatchedParens(start.token_pos().start), + loc: tokens.current_source_location(), + })?; + } + Token::CloseSquareBracket => { + tokens.advance_past_end_of_bracketed().ok_or(ErrorInfo { + error: ParseError::UnmatchedSquareBracket(start.token_pos().start), + loc: tokens.current_source_location(), + })?; + } + Token::Semi => { + tokens.advance_past_semi().ok_or(ErrorInfo { + error: ParseError::ExpectedToken(Token::Semi), + loc: tokens.current_source_location(), + })?; + } + _ => unimplemented!(), + } + Ok(this.push_error(err.error, err.loc).into()) + }) + } + + fn parse_bracketed(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult + where + F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, + Index: Into, + { + self.parse_inner2( + tokens, + Token::OpenSquareBracket, + Token::CloseSquareBracket, + parse, + ) + } + + fn parse_braced(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult + where + F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, + Index: Into, + { + self.parse_inner2(tokens, Token::OpenBrace, Token::CloseBrace, parse) + } + + fn parse_parenthesised(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult + where + F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, + Index: Into, + { + self.parse_inner2(tokens, Token::OpenParens, Token::CloseParens, parse) + } + + fn parse_struct_fields( + &mut self, + tokens: &mut TokenIterator, + ) -> ParseResult> { + let mut fields = Vec::new(); + loop { + fields.push(self.parse_struct_field(tokens)?); + + if !tokens.is_next_token(Token::Comma) { + break; + } + if tokens.is_next_token2(Token::CloseBrace) { + break; + } + // skip comma + _ = tokens.next(); + } + + Ok(fields) + } + + /// STRUCT_FIELD <- + /// IDENTIFIER: TYPE + fn parse_struct_field( + &mut self, + tokens: &mut TokenIterator, + ) -> ParseResult<(intern::Index, Index)> { + let name = self.parse_ident(tokens)?; + let Some(_) = tokens.eat_token(Token::Colon) else { + return Err(ErrorInfo { + error: ParseError::ExpectedToken(Token::Colon), + loc: tokens.current_source_location(), + }); + }; + let ty = self.parse_type(tokens)?; + + return Ok((name, ty)); + } + + /// CONSTANT_DECL <- + /// FUNCTION_DECL + /// GLOBAL_DECL + /// STRUCT_DECL + fn parse_constant_decls(&mut self, tokens: &mut TokenIterator) -> ParseResult> { + let next = tokens.peek_token().ok_or(ErrorInfo { + error: ParseError::UnexpectedEndOfTokens, + loc: tokens.current_source_location(), + })?; + + match next.token() { + Token::Fn => Ok(Some(self.parse_fn_decl(tokens))), + Token::Const => self.parse_const_decl(tokens).map(|i| Some(i)), + Token::Type => self.parse_type_decl(tokens).map(|i| Some(i)), + _ => Ok(None), + } + } + + /// FILE <- + /// (FUNCTION_DECL | GLOBAL_DECL)* + fn parse_file(&mut self, tokens: &mut TokenIterator) -> Index { + let start = tokens.current_source_location(); + let mut decls = Vec::new(); + let file = self.ast.reserve_node(Kind::File); + self.push_scope(file, intern::Index::invalid()); + + while let Some(next) = tokens.peek_token() { + let loc = next.source_location(); + let decl = match self.parse_constant_decls(tokens).and_then(|i| match i { + Some(i) => Ok(i), + None => { + let error = ParseError::UnexpectedTokenAtFileScope; + let node = self.push_error(error, loc); + + self.find_next_fn_or_const(tokens); + + Ok(node) + } + }) { + Ok(i) => i, + Err(err) => self.push_error(err.error, err.loc), + }; + decls.push(decl); + } + self.pop_scope(); + + self.ast.set_file(file, decls, start); + file + } + + /// FILE <- + /// (FUNCTION_DECL | GLOBAL_DECL)* + pub fn parse(&mut self, mut tokens: TokenIterator) { + let file = self.parse_file(&mut tokens); + self.ast.set_root([file]); + eprintln!("resolving decls:"); + self.resolve_decl_refs(); + self.create_comptime_folding_graph(intern::AMD64_POINTER_BITS); + eprintln!("interning types:"); + self.intern_types(); + self.fold_more_patterns(); + } + + fn push_scope(&mut self, ast: Index, name: intern::Index) { + let parent = self.scopes.last().cloned(); + self.scopes.push(ast); + + if let Some(parent) = parent { + self.syms.insert_symbol( + ast, + intern::Index::invalid(), + SymbolKind::ParentScope, + parent, + ); + } + self.syms.insert_scope(name, ast); + } + + fn pop_scope(&mut self) { + self.scopes.pop(); + } + + fn is_statement(&self, tokens: &mut TokenIterator) -> bool { + let mut tokens = tokens.clone(); + let mut braces = 0; + let mut parens = 0; + let mut brackets = 0; + while let Some(itm) = tokens.next() { + match itm.token() { + Token::OpenBrace => { + braces += 1; + } + Token::CloseBrace => { + braces -= 1; + } + Token::OpenParens => { + parens += 1; + } + Token::CloseParens => { + parens -= 1; + } + Token::OpenSquareBracket => { + brackets += 1; + } + Token::CloseSquareBracket => { + brackets -= 1; + } + Token::Semi => { + if braces == 0 && parens == 0 && brackets == 0 { + return true; + } + } + _ => {} + } + if braces < 0 || parens < 0 || brackets < 0 { + break; + } + } + false + } + + fn find_next_fn_or_const(&mut self, tokens: &mut TokenIterator) -> Option<()> { + tokens + .advance_until_before_one_of(&[Token::Const, Token::Fn, Token::Type]) + .map(|_| ()) + } +} diff --git a/src/ast2/visitor.rs b/src/ast2/visitor.rs new file mode 100644 index 0000000..c853efa --- /dev/null +++ b/src/ast2/visitor.rs @@ -0,0 +1,628 @@ +use super::*; +pub trait AstExt { + fn get_node_children(&self, node: Index) -> Vec; + fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data); +} + +impl AstExt for &Ast { + fn get_node_children(&self, node: Index) -> Vec { + Ast::get_node_children(self, node) + } + + fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) { + (self.tags[node], self.datas[node]) + } +} +impl AstExt for &mut Ast { + fn get_node_children(&self, node: Index) -> Vec { + Ast::get_node_children(self, node) + } + + fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) { + (self.tags[node], self.datas[node]) + } +} + +pub struct AstVisitor { + pub(super) ast: AstT, + pub(super) scopes: Vec, + pub(super) nodes: Vec, + pub(super) rev: bool, +} + +impl AstVisitor +where + AstT: AstExt, +{ + pub fn visit< + F: FnMut(&mut AstT, &[Index], Index, Tag, Data), + G: FnMut(&mut AstT, &[Index], Index, Tag, Data), + >( + &mut self, + mut pre: F, + mut post: G, + ) { + while let Some(node) = self.nodes.pop() { + match node { + A::PushChildren(i) => { + self.nodes.push(A::PopSelf(i)); + let children_iter = self + .ast + .get_node_children(i) + .into_iter() + .map(|i| A::PushChildren(i)); + // inverse because we are popping from the end + if !self.rev { + self.nodes.extend(children_iter.rev()) + } else { + self.nodes.extend(children_iter) + }; + + let (tag, data) = self.ast.get_node_tag_and_data(i); + + let _ = pre(&mut self.ast, &self.scopes, i, tag, data); + + match tag { + Tag::File + | Tag::FunctionDecl + | Tag::GlobalDecl + | Tag::Block + | Tag::BlockTrailingExpr => { + self.scopes.push(i); + } + _ => {} + } + } + A::PopSelf(i) => { + // already popped. + let (tag, data) = self.ast.get_node_tag_and_data(i); + + let _ = post(&mut self.ast, &self.scopes, i, tag, data); + + match tag { + Tag::File + | Tag::FunctionDecl + | Tag::GlobalDecl + | Tag::Block + | Tag::BlockTrailingExpr => { + self.scopes.pop(); + } + _ => {} + } + } + } + } + } + pub fn visit_pre(&mut self, mut cb: F) { + while let Some(node) = self.nodes.pop() { + match node { + A::PushChildren(i) => { + self.nodes.push(A::PopSelf(i)); + let children_iter = self + .ast + .get_node_children(i) + .into_iter() + .map(|i| A::PushChildren(i)); + // inverse because we are popping from the end + if !self.rev { + self.nodes.extend(children_iter.rev()) + } else { + self.nodes.extend(children_iter) + }; + + let (tag, data) = self.ast.get_node_tag_and_data(i); + + let _ = cb(&mut self.ast, &self.scopes, i, tag, data); + + match tag { + Tag::File + | Tag::FunctionDecl + | Tag::GlobalDecl + | Tag::Block + | Tag::BlockTrailingExpr => { + self.scopes.push(i); + } + _ => {} + } + } + A::PopSelf(i) => { + // already popped. + let (tag, _data) = self.ast.get_node_tag_and_data(i); + + match tag { + Tag::File + | Tag::FunctionDecl + | Tag::GlobalDecl + | Tag::Block + | Tag::BlockTrailingExpr => { + self.scopes.pop(); + } + _ => {} + } + } + } + } + } + pub fn visit_post(&mut self, mut cb: F) { + while let Some(node) = self.nodes.pop() { + match node { + A::PushChildren(i) => { + self.nodes.push(A::PopSelf(i)); + let children_iter = self + .ast + .get_node_children(i) + .into_iter() + .map(|i| A::PushChildren(i)); + if self.rev { + self.nodes.extend(children_iter.rev()) + } else { + self.nodes.extend(children_iter) + }; + + let (tag, _data) = self.ast.get_node_tag_and_data(i); + + match tag { + Tag::File + | Tag::FunctionDecl + | Tag::GlobalDecl + | Tag::Block + | Tag::BlockTrailingExpr => { + self.scopes.push(i); + } + _ => {} + } + } + A::PopSelf(i) => { + // already popped. + let (tag, data) = self.ast.get_node_tag_and_data(i); + + let _ = cb(&mut self.ast, &self.scopes, i, tag, data); + + match tag { + Tag::File + | Tag::FunctionDecl + | Tag::GlobalDecl + | Tag::Block + | Tag::BlockTrailingExpr => { + self.scopes.pop(); + } + _ => {} + } + } + } + } + } +} + +pub enum A { + PushChildren(Index), + PopSelf(Index), +} + +impl Ast { + pub fn visitor_mut(&mut self) -> AstVisitor<&mut Self> { + AstVisitor { + scopes: vec![], + nodes: self + .get_root_file_indices() + .map(|i| visitor::A::PushChildren(i)) + .collect(), + ast: self, + rev: false, + } + } + pub fn visitor_rev_mut(&mut self) -> AstVisitor<&mut Self> { + AstVisitor { + scopes: vec![], + nodes: self + .get_root_file_indices() + .map(|i| visitor::A::PushChildren(i)) + .collect(), + ast: self, + rev: true, + } + } + + pub fn visitor(&self) -> AstVisitor<&Self> { + AstVisitor { + scopes: vec![], + nodes: self + .get_root_file_indices() + .map(|i| visitor::A::PushChildren(i)) + .collect(), + ast: self, + rev: false, + } + } +} + +impl Ast { + pub fn visit_all_functions_mut(&mut self, visitor: &mut impl AstVisitorTrait) { + for i in + (0..self.tags.functions.len()).map(|i| Index::new(Kind::Function, i as u32).unwrap()) + { + visitor.visit_function_decl(self, i); + } + } + + pub fn visit_function_mut(&mut self) {} +} + +pub trait AstVisitorTrait { + type Error; + type Value; + const UNIMPL: Self::Error; + + fn visit_function_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_parameter(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_parameter_list( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_block(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_block_trailing_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_block_maybe_trailing( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + use visitor::AstExt; + match ast.get_node_tag_and_data(idx).0 { + Tag::BlockTrailingExpr => self.visit_block(ast, idx), + Tag::Block => self.visit_block_trailing_expr(ast, idx), + _ => unreachable!(), + } + } + fn visit_function_proto( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_call_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_add_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_sub_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_mul_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_div_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_rem_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_eq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_neq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_lt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_gt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_le_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_ge_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_shl_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_shr_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_bitor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_bitxor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_bitand_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_or_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_and_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_not_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_negate_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_deref_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_address_of_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_explicit_cast_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_assign(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_subscript_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_if_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_if_else_expr( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_argument(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_any_argument( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + use visitor::AstExt; + match ast.get_node_tag_and_data(idx).0 { + Tag::Argument => self.visit_argument(ast, idx), + Tag::NamedArgument => self.visit_named_argument(ast, idx), + _ => unreachable!(), + } + } + + fn visit_named_argument( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_argument_list( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_constant(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + + fn visit_return(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_return_expr(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_global_decl(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_var_decl(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_mut_var_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_var_assign_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_mut_var_assign_decl( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_decl_ref(&mut self, ast: &mut Ast, idx: Index) -> Result { + _ = (ast, idx); + Err(Self::UNIMPL) + } + fn visit_value_to_place_conversion( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + let idx = ast + .get_node_data_for_tag(idx, Tag::ValueToPlaceConversion) + .unwrap() + .as_index(); + self.visit_any(ast, idx) + } + fn visit_place_to_value_conversion( + &mut self, + ast: &mut Ast, + idx: Index, + ) -> Result { + let idx = ast + .get_node_data_for_tag(idx, Tag::PlaceToValueConversion) + .unwrap() + .as_index(); + self.visit_any(ast, idx) + } + + fn visit_any(&mut self, ast: &mut Ast, idx: Index) -> Result { + use visitor::AstExt; + match ast.get_node_tag_and_data(idx).0 { + Tag::FunctionProto => self.visit_function_proto(ast, idx), + Tag::FunctionDecl => self.visit_function_decl(ast, idx), + Tag::ParameterList => self.visit_parameter_list(ast, idx), + Tag::Parameter => self.visit_parameter(ast, idx), + Tag::Block => self.visit_block(ast, idx), + Tag::BlockTrailingExpr => self.visit_block_trailing_expr(ast, idx), + Tag::Constant => self.visit_constant(ast, idx), + Tag::ExprStmt => todo!(), + Tag::ReturnStmt => self.visit_return(ast, idx), + Tag::ReturnExprStmt => self.visit_return_expr(ast, idx), + Tag::VarDecl => self.visit_var_decl(ast, idx), + Tag::MutVarDecl => self.visit_mut_var_decl(ast, idx), + Tag::VarDeclAssignment => self.visit_var_assign_decl(ast, idx), + Tag::MutVarDeclAssignment => self.visit_mut_var_assign_decl(ast, idx), + Tag::GlobalDecl => self.visit_global_decl(ast, idx), + Tag::StructDecl => todo!(), + Tag::FieldDecl => todo!(), + Tag::DeclRef => self.visit_decl_ref(ast, idx), + Tag::DeclRefUnresolved => todo!(), + Tag::InternedType => todo!(), + Tag::TypeDeclRef => todo!(), + Tag::TypeDeclRefUnresolved => todo!(), + Tag::PointerType => todo!(), + Tag::ArrayType => todo!(), + Tag::CallExpr => self.visit_call_expr(ast, idx), + Tag::FieldAccess => todo!(), + Tag::ArgumentList => self.visit_argument_list(ast, idx), + Tag::Argument => self.visit_argument(ast, idx), + Tag::NamedArgument => self.visit_named_argument(ast, idx), + Tag::ExplicitCast => self.visit_explicit_cast_expr(ast, idx), + Tag::Deref => self.visit_deref_expr(ast, idx), + Tag::AddressOf => self.visit_add_expr(ast, idx), + Tag::Not => self.visit_not_expr(ast, idx), + Tag::Negate => self.visit_negate_expr(ast, idx), + Tag::Or => self.visit_or_expr(ast, idx), + Tag::And => self.visit_and_expr(ast, idx), + Tag::BitOr => self.visit_bitor_expr(ast, idx), + Tag::BitXOr => self.visit_bitxor_expr(ast, idx), + Tag::BitAnd => self.visit_bitand_expr(ast, idx), + Tag::Eq => self.visit_eq_expr(ast, idx), + Tag::NEq => self.visit_neq_expr(ast, idx), + Tag::Lt => self.visit_lt_expr(ast, idx), + Tag::Gt => self.visit_gt_expr(ast, idx), + Tag::Le => self.visit_le_expr(ast, idx), + Tag::Ge => self.visit_ge_expr(ast, idx), + Tag::Shl => self.visit_shl_expr(ast, idx), + Tag::Shr => self.visit_shr_expr(ast, idx), + Tag::Add => self.visit_add_expr(ast, idx), + Tag::Sub => self.visit_sub_expr(ast, idx), + Tag::Mul => self.visit_mul_expr(ast, idx), + Tag::Div => self.visit_div_expr(ast, idx), + Tag::Rem => self.visit_rem_expr(ast, idx), + Tag::Assign => self.visit_assign(ast, idx), + Tag::SubscriptExpr => self.visit_subscript_expr(ast, idx), + Tag::IfExpr => self.visit_if_expr(ast, idx), + Tag::IfElseExpr => self.visit_if_else_expr(ast, idx), + Tag::PlaceToValueConversion => self.visit_place_to_value_conversion(ast, idx), + Tag::ValueToPlaceConversion => self.visit_value_to_place_conversion(ast, idx), + Tag::Error => todo!(), + Tag::Undefined => todo!(), + Tag::Root => todo!(), + Tag::File => todo!(), + } + } +} + +impl Ast { + pub fn get_node_data_for_tag(&self, idx: Index, tag: Tag) -> Option { + use visitor::AstExt; + let (t, data) = self.get_node_tag_and_data(idx); + if t == tag { + Some(data) + } else { + None + } + } + + pub fn expect_node_data_for_tag(&self, idx: Index, tag: Tag) -> Data { + self.get_node_data_for_tag(idx, tag) + .expect(&format!("node {idx} is not a {tag:?}")) + } +} diff --git a/src/bin/main.rs b/src/bin/main.rs index b46523b..6b6cdd3 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -55,7 +55,7 @@ fn main() { println!("AST:\n{buf}"); } "ast2" => { - let mut tree2 = compiler::ast2::ast_gen::Parser::new(); + let mut tree2 = compiler::ast2::parser::Parser::new(); tree2.parse(tokens.iter()); eprintln!("{tree2:#?}"); println!("AST (new):\n{tree2}");