#![allow(dead_code)] use std::{ collections::BTreeMap, fmt::{Debug, Display}, num::NonZero, }; use intern::{InternPool, PointerFlags, StructFlags, AMD64_POINTER_TYPE_INFO}; use num_bigint::BigInt; use crate::{ ast::FloatingType, comptime::ComptimeNumber, lexer::SourceLocation, tokens::Token, writeln_indented, }; pub mod intern; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum Tag { /// pseudo tag, contains a range from a..b into extra of all files. Root, /// `data` is a range from a..b into extra of all global nodes. File, /// `data` is an intern to a name, and an index into extra of [index: return_type, index: ParameterList] FunctionProto, /// `data` is an index to a FunctionProto and an index to a Block FunctionDecl, /// `data` is a range from a..b into extra of indices to parameters ParameterList, /// `data` is an index to a type, and an intern to a name Parameter, /// `data` is range from a..b into `extra` of indices to statements Block, /// `data` is range from a..b into `extra` of indices to statements, where the last one is an expression BlockTrailingExpr, /// `data` is an index to a type, and an intern to a value Constant, /// `data` is an index to an expression ExprStmt, /// `data` is none ReturnStmt, /// `data` is an index to an expr ReturnExprStmt, /// `data` is a range from a..b into `extra` of `[name: intern, type: index]` VarDecl, /// `data` is a range from a..b into `extra` of `[name: intern, type: index]` MutVarDecl, /// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]` VarDeclAssignment, /// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]` MutVarDeclAssignment, /// `data` is an intern to a name, and an offset into `extra` of `[type: index, expr: index]` GlobalDecl, /// `data` is an intern to a name, and an offset into extra of `[flags, type0 ,..., typeN ,name0 ,..., nameN]` StructDecl, /// `data` is an index to a type, and an intern to a name FieldDecl, /// `data` is an index to a VarDecl, GlobalDecl or FunctionDecl DeclRef, /// `data` is an inlined key into the symbol table (scope: index, name: intern) DeclRefUnresolved, /// `data` is an intern of a type InternedType, /// `data` is an index to a StructDecl TypeDeclRef, /// `data` is an inlined key into the symbol table (scope: index, name: intern) TypeDeclRefUnresolved, /// `data` is an index to a Type and u32 PointerFlags (extra offset) PointerType, /// `data` is an index to a length expression, and an underlying pointer type ArrayType, /// `data` is an index to an expr and an index to an ArgumentList CallExpr, /// `data` is an index to an expr and an intern to a field name FieldAccess, /// `data` is a range from a..b into extra of indices to arguments ArgumentList, /// `data` is an index to an expression Argument, /// `data` is an index to an expression, and an intern to a name NamedArgument, /// `data` is an index to lhs, and an index to the type ExplicitCast, /// `data` is a single index to an expr Deref, AddressOf, Not, Negate, /// data is two indices for `lhs` and `rhs` Or, And, BitOr, BitXOr, BitAnd, Eq, NEq, Lt, Gt, Le, Ge, Shl, Shr, Add, Sub, Mul, Div, Rem, Assign, SubscriptExpr, IfExpr, /// `data` is an index to an expression and an index into extra for [if, else] IfElseExpr, // TODO: /// `data` is a ParseError Error, /// placeholder tag for reserved indices/nodes, `data` is none Undefined, } impl Tag { fn is_type(&self) -> bool { match self { Tag::TypeDeclRef | Tag::TypeDeclRefUnresolved | Tag::PointerType | Tag::InternedType | Tag::ArrayType | Tag::StructDecl => true, _ => false, } } fn is_expr(&self) -> bool { match self { Tag::Constant | Tag::DeclRef | Tag::Deref | Tag::CallExpr | Tag::AddressOf | Tag::Not | Tag::Negate | Tag::Or | Tag::And | Tag::BitOr | Tag::BitXOr | Tag::BitAnd | Tag::Eq | Tag::NEq | Tag::Lt | Tag::Gt | Tag::Le | Tag::Ge | Tag::Shl | Tag::Shr | Tag::Add | Tag::Sub | Tag::Mul | Tag::Div | Tag::Rem | Tag::SubscriptExpr | Tag::IfExpr | Tag::IfElseExpr | Tag::Block | &Tag::BlockTrailingExpr => true, _ => false, } } } #[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)] enum ParseError { #[error("Unexpected end of token iter.")] UnexpectedEndOfTokens, #[error("Expected Token {0}.")] ExpectedToken(Token), #[error("Expected Token {0}, but other token was found.")] ExpectedTokenNotFound(Token), #[error("Expected either a function declaration or a global variable.")] UnexpectedTokenAtFileScope, #[error("Expected Ident.")] ExpectedIdent, #[error("Integral types may not be wider than 65535 bits.")] IntegralTypeTooWide, #[error("Expected typename.")] ExpectedTypeName, #[error("Dummy Message.")] ExpectedFunctionPrototype, #[error("Dummy Message.")] ExpectedPrimaryExpression, #[error("Dummy Message.")] ExpectedConstantLiteral, #[error("Dummy Message.")] ExpectedExpression, #[error("Dummy Message.")] ExpectedPostfixExpression, #[error("Dummy Message.")] ExpectedPrefixExpression, #[error("Dummy Message.")] ExpectedArgumentList, #[error("Dummy Message.")] ExpectedStatement, #[error("Dummy Message.")] UnmatchedParens(u32), #[error("Dummy Message.")] ExpectedTypeDeclaration, #[error("Dummy Message.")] UnexpectedTypeAttributes, #[error("Dummy Message.")] UnmatchedSquareBracket(u32), #[error("Dummy Message.")] ExpectedEndOfBlock, #[error("Dummy Message.")] UnmatchedBrace(u32), #[error("Dummy Message.")] UnmatchedDelimiter(u32), #[error("Error in child node {0:?}.")] ErrorNode(Index), } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct Index(NonZero); impl Display for Index { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "%{}", self.0.get()) } } impl Index { pub fn new(i: u32) -> Index { Self(NonZero::::new(i).unwrap()) } pub fn as_u32(&self) -> &u32 { unsafe { core::mem::transmute(self) } } pub fn into_u32(self) -> u32 { unsafe { core::mem::transmute(self) } } fn index(self) -> usize { self.0.get() as usize } } #[repr(packed)] #[derive(Clone, Copy)] struct Node { /// defines the type of the node in the tree tag: Tag, data: Data, } #[derive(Clone, Copy)] union Data { none: (), error: ParseError, index: Index, two_indices: (Index, Index), range: (Index, Index), extra_range: (u32, u32), intern: intern::Index, index_intern: (Index, intern::Index), two_interns: (intern::Index, intern::Index), intern_and_extra_offset: (intern::Index, u32), index_and_extra_offset: (Index, u32), index_and_opaque: (Index, u32), } #[derive(Debug)] #[allow(dead_code)] enum ExpandedData { None, Error(ParseError), Index(Index), TwoIndices(Index, Index), Range(Index, Index), ExtraRange(usize, usize), Intern(intern::Index), IndexIntern(Index, intern::Index), TwoInterns(intern::Index, intern::Index), InternAndExtraOffset(intern::Index, usize), IndexAndExtraOffset(Index, usize), IndexAndOpaque(Index, u32), } impl ExpandedData { fn from_none() -> Self { Self::None } fn from_error(data: Data) -> Self { Self::Error(data.as_error()) } fn from_index(data: Data) -> Self { Self::Index(data.as_index()) } fn from_two_indices(data: Data) -> Self { let data = data.as_two_indices(); Self::TwoIndices(data.0, data.1) } fn from_range(data: Data) -> Self { let data = data.as_index_range(); Self::Range(data.0, data.1) } fn from_extra_range(data: Data) -> Self { let data = data.as_extra_range(); Self::ExtraRange(data.0, data.1) } fn from_intern(data: Data) -> Self { let data = data.as_intern(); Self::Intern(data) } fn from_index_intern(data: Data) -> Self { let data = data.as_index_intern(); Self::IndexIntern(data.0, data.1) } fn from_two_interns(data: Data) -> Self { let data = data.as_two_interns(); Self::TwoInterns(data.0, data.1) } fn from_intern_and_extra_offset(data: Data) -> Self { let data = data.as_intern_and_extra_offset(); Self::InternAndExtraOffset(data.0, data.1) } fn from_index_and_extra_offset(data: Data) -> Self { let data = data.as_index_and_extra_offset(); Self::IndexAndExtraOffset(data.0, data.1) } fn from_index_and_opaque(data: Data) -> Self { let data = data.as_index_and_opaque(); Self::IndexAndExtraOffset(data.0, data.1) } } impl From<(Tag, Data)> for ExpandedData { fn from((tag, data): (Tag, Data)) -> Self { match tag { Tag::FunctionProto => Self::from_index_and_extra_offset(data), Tag::ParameterList => Self::from_extra_range(data), Tag::Root => Self::from_extra_range(data), Tag::File => Self::from_extra_range(data), Tag::ArgumentList | Tag::VarDecl | Tag::MutVarDecl | Tag::VarDeclAssignment | Tag::MutVarDeclAssignment | Tag::BlockTrailingExpr | Tag::Block => Self::from_extra_range(data), Tag::FieldDecl | Tag::Constant | Tag::Parameter => { Self::from_index_intern(data) } Tag::Or | Tag::And | Tag::BitOr | Tag::BitXOr | Tag::BitAnd | Tag::Eq | Tag::NEq | Tag::Lt | Tag::Gt | Tag::Le | Tag::Ge | Tag::Shl | Tag::Shr | Tag::Add | Tag::Sub | Tag::Mul | Tag::Div | Tag::Rem | Tag::Assign | Tag::IfExpr | Tag::SubscriptExpr | Tag::CallExpr | Tag::ArrayType | Tag::FunctionDecl => Self::from_two_indices(data), Tag::ReturnExprStmt | Tag::DeclRef | Tag::TypeDeclRef | Tag::Argument | Tag::Deref | Tag::AddressOf | Tag::Not | Tag::Negate | Tag::ExprStmt => Self::from_index(data), Tag::FieldAccess | Tag::DeclRefUnresolved | Tag::TypeDeclRefUnresolved | Tag::NamedArgument | Tag::ExplicitCast => Self::from_index_intern(data), Tag::GlobalDecl => Self::from_intern_and_extra_offset(data), Tag::InternedType | Tag::StructDecl => Self::from_intern(data), Tag::PointerType | Tag::IfElseExpr => { Self::from_index_and_extra_offset(data) } Tag::Error => Self::from_error(data), Tag::ReturnStmt | Tag::Undefined => Self::from_none(), } } } impl Data { fn as_error(self) -> ParseError { unsafe { self.error } } fn as_index(self) -> Index { unsafe { self.index } } fn as_two_indices(self) -> (Index, Index) { unsafe { self.two_indices } } fn as_index_range(self) -> (Index, Index) { unsafe { self.range } } fn as_extra_range(self) -> (usize, usize) { let (a, b) = unsafe { self.extra_range }; (a as usize, b as usize) } fn as_intern(self) -> intern::Index { unsafe { self.intern } } fn as_two_interns(self) -> (intern::Index, intern::Index) { unsafe { self.two_interns } } fn as_index_intern(self) -> (Index, intern::Index) { unsafe { self.index_intern } } fn as_index_and_extra_offset(self) -> (Index, usize) { let (i, e) = unsafe { self.index_and_extra_offset }; (i, e as usize) } fn as_intern_and_extra_offset(self) -> (intern::Index, usize) { let (i, e) = unsafe { self.intern_and_extra_offset }; (i, e as usize) } fn as_index_and_opaque(self) -> (Index, usize) { let (i, e) = unsafe { self.index_and_opaque }; (i, e as usize) } } impl Data { fn none() -> Self { Self { none: () } } fn error(error: ParseError) -> Self { Self { error } } fn index(index: Index) -> Self { Self { index } } fn two_indices(a: Index, b: Index) -> Self { Self { two_indices: (a, b), } } fn two_interns(a: intern::Index, b: intern::Index) -> Self { Self { two_interns: (a, b), } } fn range_of_indices(a: Index, b: Index) -> Self { Self { range: (a, b) } } fn extra_range(a: u32, b: u32) -> Self { Self { extra_range: (a, b), } } fn intern(intern: intern::Index) -> Self { Self { intern } } fn index_and_intern(index: Index, intern: intern::Index) -> Self { Self { index_intern: (index, intern), } } fn intern_and_extra_offset(intern: intern::Index, offset: u32) -> Self { Self { intern_and_extra_offset: (intern, offset), } } fn index_and_extra_offset(index: Index, offset: u32) -> Self { Self { index_and_extra_offset: (index, offset), } } fn index_and_opaque(index: Index, value: u32) -> Self { Self { index_and_opaque: (index, value), } } } pub struct Ast { tags: Vec, datas: Vec, extra: Vec, source_locs: Vec, } impl Debug for Ast { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Ast") .field_with("nodes", |f| { let mut list = f.debug_list(); struct LocDisplay(SourceLocation); impl Debug for LocDisplay { fn fmt( &self, f: &mut std::fmt::Formatter<'_>, ) -> std::fmt::Result { write!(f, "({})", self.0) } } let entries = self .tags .iter() .cloned() .zip(self.datas.iter().cloned()) .zip(self.source_locs.iter().cloned()) .enumerate() .map(|(i, ((tag, data), loc))| { ( i, tag, ExpandedData::from((tag, data)), LocDisplay(loc), ) }); list.entries(entries).finish() }) .field("extra", &self.extra) .finish() } } impl Ast { fn new() -> Ast { Self { tags: vec![Tag::Root], datas: vec![Data::extra_range(0, 0)], extra: vec![], source_locs: vec![SourceLocation::new(0, 0)], } } fn reserve_node(&mut self) -> Index { let i = unsafe { Index(NonZero::new_unchecked(self.tags.len() as u32)) }; self.tags.push(Tag::Undefined); self.datas.push(Data::none()); self.source_locs.push(SourceLocation::invalid()); i } fn get_loc(&self, index: Index) -> SourceLocation { self.source_locs[index.index()] } fn push_error(&mut self, error: ParseError, loc: SourceLocation) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc(i, Tag::Error, Data::error(error), loc); i } fn set_file>( &mut self, i: Index, decls: I, loc: SourceLocation, ) { let (extra_start, extra_end) = self.extend_extra_by_indices(decls); self.set_tag_data_source_loc( i, Tag::File, Data::extra_range(extra_start, extra_end), loc, ); } fn push_file>( &mut self, decls: I, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_file(i, decls, loc); i } fn set_root>(&mut self, decls: I) { let (extra_start, extra_end) = self.extend_extra_by_indices(decls); self.tags[0] = Tag::Root; self.datas[0] = Data::extra_range(extra_start, extra_end); } fn get_root_file_indices<'a>(&'a self) -> impl Iterator + 'a { let (a, b) = self.datas[0].as_extra_range(); self.extra[a..b].iter().cloned().map(|i| Index::new(i)) } fn push_global_decl( &mut self, ident: intern::Index, ty: Index, expr: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); let (extra_start, _) = self.extend_extra([ty.into_u32(), expr.into_u32()]); self.set_tag_data_source_loc( i, Tag::GlobalDecl, Data::intern_and_extra_offset(ident, extra_start), loc, ); i } fn set_fn_decl( &mut self, i: Index, proto: Index, body: Index, loc: SourceLocation, ) { self.set_tag_data_source_loc( i, Tag::FunctionDecl, Data::two_indices(proto, body), loc, ); } fn push_fn_decl( &mut self, proto: Index, body: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_fn_decl(i, proto, body, loc); i } fn push_ret(&mut self, expr: Option, loc: SourceLocation) -> Index { let i = self.reserve_node(); match expr { Some(expr) => self.set_tag_data_source_loc( i, Tag::ReturnExprStmt, Data::index(expr), loc, ), None => self.set_tag_data_source_loc( i, Tag::ReturnStmt, Data::none(), loc, ), } i } fn push_var_decl( &mut self, is_let: bool, name: intern::Index, ty: Option, assignment: Option, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); let start = self.extra.len() as u32; self.extra.push(name.into_u32()); _ = self.extend_extra(assignment.map(|i| i.into_u32())); _ = self.extend_extra(ty.map(|i| i.into_u32())); let end = self.extra.len() as u32; let tag = match (is_let, assignment.is_some()) { (true, false) => Tag::VarDecl, (true, true) => Tag::VarDeclAssignment, (false, false) => Tag::MutVarDecl, (false, true) => Tag::MutVarDeclAssignment, }; self.set_tag_data_source_loc( i, tag, Data::extra_range(start, end), loc, ); i } fn push_fn_proto( &mut self, ident: intern::Index, return_type: Index, parameter_list: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); let (extra_start, _) = self .extend_extra([return_type.into_u32(), parameter_list.into_u32()]); self.set_tag_data_source_loc( i, Tag::FunctionProto, Data::intern_and_extra_offset(ident, extra_start), loc, ); i } fn set_block>( &mut self, i: Index, statements: I, trailing: Option, loc: SourceLocation, ) { let (extra_start, extra_end) = self.extend_extra_by_indices( statements.into_iter().chain(trailing.into_iter()), ); if trailing.is_some() { self.set_tag_data_source_loc( i, Tag::BlockTrailingExpr, Data::extra_range(extra_start, extra_end), loc, ); } else { self.set_tag_data_source_loc( i, Tag::Block, Data::extra_range(extra_start, extra_end), loc, ); } } fn push_block>( &mut self, statements: I, trailing: Option, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_block(i, statements, trailing, loc); i } fn push_parameter_list>( &mut self, parameters: I, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); let (extra_start, extra_end) = self.extend_extra_by_indices(parameters); self.set_tag_data_source_loc( i, Tag::ParameterList, Data::extra_range(extra_start, extra_end), loc, ); i } fn push_argument(&mut self, expr: Index, loc: SourceLocation) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc(i, Tag::Argument, Data::index(expr), loc); i } fn push_named_argument( &mut self, name: intern::Index, expr: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::NamedArgument, Data::index_and_intern(expr, name), loc, ); i } fn push_parameter( &mut self, name: intern::Index, ty: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::Parameter, Data::index_and_intern(ty, name), loc, ); i } fn push_argument_list>( &mut self, args: I, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); let (extra_start, extra_end) = self.extend_extra_by_indices(args); self.set_tag_data_source_loc( i, Tag::ArgumentList, Data::extra_range(extra_start, extra_end), loc, ); i } fn push_unary( &mut self, tag: Tag, lhs: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc(i, tag, Data::index(lhs), loc); i } fn push_binary( &mut self, tag: Tag, lhs: Index, rhs: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc(i, tag, Data::two_indices(lhs, rhs), loc); i } fn push_assign( &mut self, lhs: Index, rhs: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::Assign, Data::two_indices(lhs, rhs), loc, ); i } fn push_cast( &mut self, lhs: Index, ty: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::ExplicitCast, Data::two_indices(lhs, ty), loc, ); i } fn push_if( &mut self, cond: Index, body: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::IfExpr, Data::two_indices(cond, body), loc, ); i } fn push_if_else( &mut self, cond: Index, body: Index, other: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); let (extra_start, _) = self.extend_extra_by_indices([body, other]); self.set_tag_data_source_loc( i, Tag::IfElseExpr, Data::index_and_extra_offset(cond, extra_start), loc, ); i } fn push_call_expr( &mut self, lhs: Index, args: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::CallExpr, Data::two_indices(lhs, args), loc, ); i } fn push_decl_ref_unresolved( &mut self, scope: Index, ident: intern::Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::DeclRefUnresolved, Data::index_and_intern(scope, ident), loc, ); i } fn resolve_decl_ref(&mut self, i: Index, decl: Index) { self.tags[i.index()] = Tag::DeclRef; self.datas[i.index()] = Data::index(decl); } fn push_struct_decl>( &mut self, name: intern::Index, flags: StructFlags, fields: I, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_struct_decl(i, name, flags, fields, loc) } fn set_struct_decl>( &mut self, i: Index, name: intern::Index, flags: StructFlags, fields: I, loc: SourceLocation, ) -> Index { let (offset, _) = self.extend_extra([flags.pack()]); let (names, types) = fields .into_iter() .map(|(name, ty)| (name.into_u32(), ty.into_u32())) .unzip::<_, _, Vec<_>, Vec<_>>(); self.extend_extra(types); self.extend_extra(names); self.set_tag_data_source_loc( i, Tag::StructDecl, Data::intern_and_extra_offset(name, offset), loc, ); i } fn push_field_decl( &mut self, name: intern::Index, ty: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::FieldDecl, Data::index_and_intern(ty, name), loc, ); i } fn push_field_access( &mut self, expr: Index, name: intern::Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::FieldAccess, Data::index_and_intern(expr, name), loc, ); i } fn push_interend_type( &mut self, ty: intern::Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::InternedType, Data::intern(ty), loc, ); i } fn push_array_type( &mut self, length_expr: Index, pointer_ty: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::ArrayType, Data::two_indices(length_expr, pointer_ty), loc, ); i } fn push_pointer_type( &mut self, ty: Index, flags: PointerFlags, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::PointerType, Data::index_and_extra_offset(ty, flags.pack() as u32), loc, ); i } fn push_type_ref_unresolved( &mut self, scope: Index, ident: intern::Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::TypeDeclRefUnresolved, Data::index_and_intern(scope, ident), loc, ); i } fn resolve_type_ref(&mut self, i: Index, decl: Index) { self.tags[i.index()] = Tag::TypeDeclRef; self.datas[i.index()] = Data::index(decl); } fn push_expr_stmt(&mut self, expr: Index) -> Index { let i = self.reserve_node(); let loc = self.get_loc(expr); self.set_tag_data_source_loc(i, Tag::ExprStmt, Data::index(expr), loc); i } fn push_constant( &mut self, value: intern::Index, ty: Index, loc: SourceLocation, ) -> Index { let i = self.reserve_node(); self.set_tag_data_source_loc( i, Tag::Constant, Data::index_and_intern(ty, value), loc, ); i } fn extend_extra_by_indices>( &mut self, indices: I, ) -> (u32, u32) { self.extend_extra(indices.into_iter().map(|i| i.0.get())) } fn extend_extra>( &mut self, words: I, ) -> (u32, u32) { let i = self.extra.len() as u32; self.extra.extend(words); (i, self.extra.len() as u32) } fn set_tag_data_source_loc( &mut self, index: Index, tag: Tag, data: Data, loc: SourceLocation, ) { self.tags[index.index()] = tag; self.datas[index.index()] = data; self.source_locs[index.index()] = loc; } } struct Children(Vec); impl Display for Children { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "[")?; if let Some((last, rest)) = self.0.split_last() { for i in rest { write!(f, "{i}, ")?; } write!(f, "{last}")?; } write!(f, "]") } } type TypeCache = BTreeMap; // type ComptimeCache = BTreeMap; #[derive(Debug, Default)] struct ComptimeCache { inner: BTreeMap, // this is (a,b) where b dominates a // meaning: // when a is marked as runtime, b can be updated to be runtime as well. dependencies: BTreeMap, } impl ComptimeCache { fn get(&self, key: &Index) -> Option { self.inner.get(key).cloned() } fn insert(&mut self, key: Index, value: bool) { self.inner.insert(key, value); if !value { self.set_runtime(key); } } fn mark_as_dominated_by(&mut self, a: Index, b: Index) { self.dependencies.insert(a, b); } fn set_runtime(&mut self, key: Index) { self.inner.insert(key, false); if let Some(&dom) = self.dependencies.get(&key) { self.set_runtime(dom); } } } impl Ast { fn get_type_of_node( &self, ip: &InternPool, cache: &mut TypeCache, index: Index, ) -> intern::Index { if let Some(ty) = cache.get(&index) { return *ty; } let void = ip.get_void_type(); let tag = self.tags[index.index()]; let data = self.datas[index.index()]; let ty = match tag { Tag::ArgumentList | Tag::ExprStmt | Tag::ReturnExprStmt | Tag::Block | Tag::ParameterList | Tag::File => void, Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => { let (_, b) = data.as_extra_range(); self.get_type_of_node(ip, cache, Index::new(self.extra[b - 1])) } Tag::VarDecl | Tag::MutVarDecl => { let (a, b) = data.as_extra_range(); self.get_type_of_node(ip, cache, Index::new(self.extra[a + 1])) } Tag::GlobalDecl => { let (_, a) = data.as_intern_and_extra_offset(); self.get_type_of_node(ip, cache, Index::new(self.extra[a])) } Tag::FunctionDecl => { self.get_type_of_node(ip, cache, data.as_two_indices().0) } Tag::FunctionProto => { let (_, i) = data.as_intern_and_extra_offset(); let return_type = { self.datas[self.extra[i] as usize].as_intern() }; let parameters = { let (a, b) = self.datas[self.extra[i + 1] as usize].as_extra_range(); self.extra[a..b].iter().map(|&i| { // i is index to a parameter, a parameter is (index, intern) let ty = self.datas[i as usize].as_index_intern().0; self.datas[ty.index()].as_intern() }) }; ip.try_get_function_type(return_type, parameters).unwrap() } Tag::BlockTrailingExpr => { let (a, b) = data.as_extra_range(); self.get_type_of_node(ip, cache, Index::new(self.extra[b - 1])) } Tag::CallExpr => { let (expr, _args) = data.as_two_indices(); let fn_ty = self.get_type_of_node(ip, cache, expr); if let intern::Key::FunctionType { return_type, .. } = ip.get_key(fn_ty) { return_type } else { eprintln!("lhs of call expr is not a function!"); void } } Tag::Argument => self.get_type_of_node(ip, cache, data.as_index()), Tag::NamedArgument => { let (a, _) = data.as_index_intern(); self.get_type_of_node(ip, cache, a) } Tag::ExplicitCast => { let (_, a) = data.as_two_indices(); self.get_type_of_node(ip, cache, a) } Tag::FieldAccess => { let (ty_expr, name) = data.as_index_intern(); let ty = self.get_type_of_node(ip, cache, ty_expr); match ip.get_key(ty) { intern::Key::PointerType { pointee, .. } if let intern::Key::StructType { fields, .. } = ip.get_key(pointee) => { fields .iter() .cloned() .find(|(n, _)| n == &name) .map(|(_, t)| t) .unwrap_or(void) } intern::Key::StructType { fields, .. } => fields .iter() .cloned() .find(|(n, _)| n == &name) .map(|(_, t)| t) .unwrap_or(void), _ => { unimplemented!() } } } Tag::Deref => { let ty = self.get_type_of_node(ip, cache, data.as_index()); if let intern::Key::PointerType { pointee, .. } = ip.get_key(ty) { pointee } else { eprintln!("lhs of deref is not a pointer!"); void } } Tag::SubscriptExpr => { let ty = self.get_type_of_node(ip, cache, data.as_two_indices().0); match ip.get_key(ty) { intern::Key::PointerType { pointee, .. } | intern::Key::ArrayType { pointee, .. } => pointee, _ => { eprintln!( "lhs of subscript is not an array or pointer!" ); void } } } Tag::AddressOf => { let ty = self.get_type_of_node(ip, cache, data.as_index()); // TODO: find out of the expression is const, volatile for flags ip.try_get_pointer_type(ty, None).unwrap() } Tag::Not | Tag::Negate => { self.get_type_of_node(ip, cache, data.as_index()) } Tag::Or | Tag::And | Tag::BitOr | Tag::BitXOr | Tag::BitAnd | Tag::Eq | Tag::NEq | Tag::Lt | Tag::Gt | Tag::Le | Tag::Ge | Tag::Shl | Tag::Shr | Tag::Add | Tag::Sub | Tag::Mul | Tag::Div | Tag::Rem => { self.get_type_of_node(ip, cache, data.as_two_indices().0) } Tag::IfExpr => ip.get_bool_type(), // really? Tag::IfElseExpr => { let (_, b) = data.as_index_and_extra_offset(); let if_ = Index::new(self.extra[b]); self.get_type_of_node(ip, cache, if_) } Tag::Constant | Tag::Parameter => { self.get_type_of_node(ip, cache, data.as_index_intern().0) } Tag::DeclRef => self.get_type_of_node(ip, cache, data.as_index()), Tag::StructDecl => { let (name, _) = data.as_intern_and_extra_offset(); ip.try_get_struct_type(name, index).unwrap() } Tag::Assign | Tag::Root | Tag::DeclRefUnresolved | Tag::Error | Tag::Undefined | Tag::ReturnStmt => void, Tag::FieldDecl => { self.get_type_of_node(ip, cache, data.as_index_intern().0) } Tag::InternedType => data.as_intern(), Tag::TypeDeclRef | Tag::TypeDeclRefUnresolved | Tag::PointerType | Tag::ArrayType => ip.get_void_type(), }; cache.insert(index, ty); ty } fn get_node_children(&self, index: Index) -> Vec { let tag = self.tags[index.index()]; let data = self.datas[index.index()]; match tag { Tag::File => { let (a, b) = data.as_extra_range(); self.extra[a..b].iter().map(|&i| Index::new(i)).collect() } Tag::FunctionProto => { let (_, i) = data.as_intern_and_extra_offset(); self.extra[i..=i + 1] .iter() .map(|&i| Index::new(i)) .collect() } Tag::FunctionDecl => { let (a, b) = data.as_two_indices(); vec![a, b] } Tag::ParameterList => { let (a, b) = data.as_extra_range(); self.extra[a..b].iter().map(|&i| Index::new(i)).collect() } Tag::Block | Tag::BlockTrailingExpr => { let (a, b) = data.as_extra_range(); self.extra[a..b].iter().map(|&i| Index::new(i)).collect() } Tag::ExprStmt | Tag::ReturnExprStmt => { let a = data.as_index(); vec![a] } Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => { let (a, b) = data.as_extra_range(); self.extra[a + 1..b] .iter() .map(|&i| Index::new(i)) .collect() } Tag::GlobalDecl => { let (_, offset) = data.as_intern_and_extra_offset(); self.extra[offset..=offset + 1] .iter() .map(|&i| Index::new(i)) .collect() } Tag::CallExpr | Tag::ExplicitCast => { let (a, b) = data.as_two_indices(); vec![a, b] } Tag::ArgumentList => { let (a, b) = data.as_extra_range(); self.extra[a..b].iter().map(|&i| Index::new(i)).collect() } Tag::Argument => { let a = data.as_index(); vec![a] } Tag::FieldDecl | Tag::FieldAccess | Tag::NamedArgument => { let (a, _) = data.as_index_intern(); vec![a] } Tag::Deref | Tag::AddressOf | Tag::Not | Tag::Negate => { let a = data.as_index(); vec![a] } Tag::Or | Tag::And | Tag::BitOr | Tag::BitXOr | Tag::BitAnd | Tag::Eq | Tag::NEq | Tag::Lt | Tag::Gt | Tag::Le | Tag::Ge | Tag::Shl | Tag::Shr | Tag::Add | Tag::Sub | Tag::Mul | Tag::Div | Tag::Rem | Tag::Assign | Tag::SubscriptExpr | Tag::ArrayType | Tag::IfExpr => { let (a, b) = data.as_two_indices(); vec![a, b] } Tag::IfElseExpr => { let (a, b) = data.as_index_and_extra_offset(); let if_ = Index::new(self.extra[b]); let else_ = Index::new(self.extra[b + 1]); vec![a, if_, else_] } Tag::PointerType => { let (a, _) = data.as_index_and_extra_offset(); vec![a] } Tag::StructDecl => { let (a, offset) = data.as_intern_and_extra_offset(); let flags = StructFlags::unpack(self.extra[offset]); self.extra[offset + 1..(offset + 1 + flags.num_fields as usize)] .iter() .map(|&i| Index::new(i)) .collect() } Tag::InternedType | Tag::Root | Tag::TypeDeclRefUnresolved | Tag::DeclRefUnresolved | Tag::Error | Tag::Undefined | Tag::TypeDeclRef | Tag::DeclRef | Tag::ReturnStmt => vec![], Tag::Parameter | Tag::Constant => { let (a, _) = data.as_index_intern(); vec![a] } Tag::VarDecl | Tag::MutVarDecl => { let (a, _) = data.as_extra_range(); vec![Index::new(self.extra[a + 1])] } } } fn is_node_comptime_evaluable( &self, cache: &mut ComptimeCache, index: Index, ) -> bool { if let Some(a) = cache.get(&index) { a } else { let tag = self.tags[index.index()]; let data = self.datas[index.index()]; let children = self.get_node_children(index); let are_children_comptime = |this: &Self, cache: &mut ComptimeCache| { children .iter() .all(|&i| this.is_node_comptime_evaluable(cache, i)) }; let is_comptime = match tag { Tag::Parameter => false, // TODO: figure out if there are function protos that arent const // Tag::FunctionProto | Tag::FunctionDecl | Tag::Block | Tag::BlockTrailingExpr => { // are_children_comptime(self, cache) // } Tag::Constant => true, Tag::ReturnStmt => true, Tag::ReturnExprStmt => are_children_comptime(self, cache), Tag::MutVarDecl | Tag::MutVarDeclAssignment => false, // Tag::VarDecl => true, Tag::VarDeclAssignment => are_children_comptime(self, cache), Tag::GlobalDecl => true, Tag::StructDecl => true, Tag::FieldDecl => true, Tag::DeclRef => { self.tags[data.as_index().index()] == Tag::GlobalDecl } Tag::InternedType | Tag::PointerType | Tag::ArrayType | Tag::TypeDeclRef => true, // Tag::CallExpr => are_children_comptime(self, cache), // Tag::FieldAccess => { // let parent = data.as_index_intern().0; // cache.mark_as_dominated_by(index, parent); // self.is_node_comptime_evaluable(cache, parent) // } Tag::ArgumentList => are_children_comptime(self, cache), Tag::Argument => { self.is_node_comptime_evaluable(cache, data.as_index()) } Tag::NamedArgument => self.is_node_comptime_evaluable( cache, data.as_index_intern().0, ), Tag::ExplicitCast => self .is_node_comptime_evaluable(cache, data.as_two_indices().0), Tag::Deref | Tag::AddressOf => false, Tag::Not | Tag::Negate | Tag::Or | Tag::And | Tag::BitOr | Tag::BitXOr | Tag::BitAnd | Tag::Eq | Tag::NEq | Tag::Lt | Tag::Gt | Tag::Le | Tag::Ge | Tag::Shl | Tag::Shr | Tag::Add | Tag::Sub | Tag::Mul | Tag::Div | Tag::SubscriptExpr | Tag::Rem => are_children_comptime(self, cache), Tag::Assign => { let (left, _) = data.as_two_indices(); cache.mark_as_dominated_by(index, left); are_children_comptime(self, cache) } // Tag::IfExpr | Tag::IfElseExpr => are_children_comptime(self, cache), Tag::Root | Tag::File | Tag::ParameterList | Tag::ExprStmt | Tag::DeclRefUnresolved | Tag::TypeDeclRefUnresolved | Tag::Error | Tag::Undefined => false, _ => false, }; cache.insert(index, is_comptime); is_comptime } } fn comptime_value_of_node( &self, ip: &InternPool, pointer_bits: u16, cache: &mut TypeCache, index: Index, ) -> Option { let tag = self.tags[index.index()]; let data = self.datas[index.index()]; match tag { Tag::Constant => { let (ty, value) = data.as_index_intern(); let ty = self.get_type_of_node(ip, cache, ty); Some(interned_type_and_value_to_comptime_number( ip, pointer_bits, ty, value, )) } Tag::GlobalDecl => { let (_, offset) = data.as_intern_and_extra_offset(); self.comptime_value_of_node( ip, pointer_bits, cache, Index::new(self.extra[offset + 1]), ) } Tag::VarDeclAssignment => { let (a, _) = data.as_extra_range(); self.comptime_value_of_node( ip, pointer_bits, cache, Index::new(self.extra[a + 1]), ) } Tag::DeclRef => self.comptime_value_of_node( ip, pointer_bits, cache, data.as_index(), ), Tag::ExplicitCast => { let (expr, ty) = data.as_two_indices(); let ty = ip.as_ast1_type( intern::AMD64_POINTER_BITS, self.datas[ty.index()].as_intern(), ); let val = self.comptime_value_of_node(ip, pointer_bits, cache, expr); val.and_then(|i| i.explicit_cast(ty).ok()) } Tag::Add => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.add(b).ok()) }) } Tag::Sub => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.sub(b).ok()) }) } Tag::Mul => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.mul(b).ok()) }) } Tag::Div => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.div(b).ok()) }) } Tag::Rem => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.rem(b).ok()) }) } Tag::Shl => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.shl(b).ok()) }) } Tag::Shr => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.shr(b).ok()) }) } Tag::BitAnd => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.bitand(b).ok()) }) } Tag::BitOr => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.bitor(b).ok()) }) } Tag::BitXOr => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.bitxor(b).ok()) }) } Tag::And => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.and(b).ok()) }) } Tag::Or => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.or(b).ok()) }) } Tag::Eq => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.eq(b).ok()) }) } Tag::NEq => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.eq(b).and_then(|i| i.not()).ok()) }) } Tag::Gt => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.gt(b).ok()) }) } Tag::Lt => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.lt(b).ok()) }) } Tag::Le => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.le(b).ok()) }) } Tag::Ge => { let (a, b) = data.as_two_indices(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| { self.comptime_value_of_node(ip, pointer_bits, cache, b) .and_then(|b| a.ge(b).ok()) }) } Tag::Not => { let a = data.as_index(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| a.not().ok()) } Tag::Negate => { let a = data.as_index(); self.comptime_value_of_node(ip, pointer_bits, cache, a) .and_then(|a| a.neg().ok()) } _ => None, } } } pub fn comptime_number_to_interned_type_and_value( ip: &mut InternPool, pointer_bits: u16, comptime: ComptimeNumber, ) -> (intern::Index, intern::Index) { use crate::ast::IntegralType; let (value, ty) = comptime.into_bytes_and_type(); let value = match ty { crate::ast::Type::Bool => { if value.get(0) != Some(&1) { ip.get_false_value() } else { ip.get_true_value() } } crate::ast::Type::Integer(IntegralType { bits: 65.., .. }) | crate::ast::Type::ComptimeNumber => { let bigint = BigInt::from_signed_bytes_le(&value); if bigint.sign() == num_bigint::Sign::Minus { ip.get_or_insert(intern::Key::NegativeInt { bigint }) } else { ip.get_or_insert(intern::Key::PositiveInt { bigint }) } } crate::ast::Type::Integer(i) => match i.bits { ..=32 => { let mut buf = [0u8; 4]; buf[..value.len()].copy_from_slice(&value[..]); if i.signed { ip.get_or_insert(intern::Key::SIntSmall { bits: i32::from_le_bytes(buf), }) } else { ip.get_or_insert(intern::Key::UIntSmall { bits: u32::from_le_bytes(buf), }) } } ..=64 => { let mut buf = [0u8; 8]; buf[..value.len()].copy_from_slice(&value[..]); if i.signed { ip.get_or_insert(intern::Key::SInt64 { bits: i64::from_le_bytes(buf), }) } else { ip.get_or_insert(intern::Key::UInt64 { bits: u64::from_le_bytes(buf), }) } } _ => unreachable!(), }, crate::ast::Type::Floating(FloatingType::Binary32) => { let mut buf = [0u8; 4]; buf[..value.len()].copy_from_slice(&value[..]); ip.get_or_insert(intern::Key::F32 { bits: f32::from_le_bytes(buf), }) } crate::ast::Type::Floating(FloatingType::Binary64) => { let mut buf = [0u8; 8]; buf[..value.len()].copy_from_slice(&value[..]); ip.get_or_insert(intern::Key::F64 { bits: f64::from_le_bytes(buf), }) } _ => unimplemented!(), }; let ty = ip.from_ast1_type(pointer_bits, &ty); (value, ty) } pub fn interned_type_and_value_to_comptime_number( ip: &InternPool, pointer_bits: u16, ty: intern::Index, val: intern::Index, ) -> crate::comptime::ComptimeNumber { use crate::ast::IntegralType; use crate::comptime::*; let ty_key = ip.get_key(ty); let signed = ip.is_type_signed(ty, AMD64_POINTER_TYPE_INFO); match ty_key { intern::Key::SIntType { bit_width: bits } | intern::Key::UIntType { bit_width: bits } => { let ty = IntegralType::new(signed, bits); match ip.get_key(val) { intern::Key::SIntSmall { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::UIntSmall { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::SInt64 { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::UInt64 { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::PositiveInt { bigint } => { ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty, }) } intern::Key::NegativeInt { bigint } => { ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty, }) } _ => { unreachable!() } } } intern::Key::SimpleType { ty } => match ty { intern::SimpleType::F32 => match ip.get_key(val) { intern::Key::F32 { bits } => { ComptimeNumber::Floating(ComptimeFloat::Binary32(bits)) } _ => { unreachable!() } }, intern::SimpleType::F64 => match ip.get_key(val) { intern::Key::F64 { bits } => { ComptimeNumber::Floating(ComptimeFloat::Binary64(bits)) } _ => { unreachable!() } }, intern::SimpleType::Bool => match ip.get_key(val) { intern::Key::TrueValue => ComptimeNumber::Bool(true), intern::Key::FalseValue => ComptimeNumber::Bool(false), _ => unreachable!(), }, intern::SimpleType::Void => todo!(), intern::SimpleType::USize | intern::SimpleType::ISize => { let ty = IntegralType::new( matches!( ty_key, intern::Key::SimpleType { ty: intern::SimpleType::ISize } ), pointer_bits, ); match ip.get_key(val) { intern::Key::SIntSmall { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::UIntSmall { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::SInt64 { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::UInt64 { bits } => { ComptimeNumber::Integral(ComptimeInt::Native { bits: bits as _, ty, }) } intern::Key::PositiveInt { bigint } => { ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty, }) } intern::Key::NegativeInt { bigint } => { ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty, }) } _ => { unreachable!() } } } intern::SimpleType::ComptimeInt => { let bigint = match ip.get_key(val) { intern::Key::SIntSmall { bits } => { BigInt::from_signed_bytes_le(&bits.to_le_bytes()) } intern::Key::UIntSmall { bits } => { BigInt::from_signed_bytes_le(&bits.to_le_bytes()) } intern::Key::SInt64 { bits } => { BigInt::from_signed_bytes_le(&bits.to_le_bytes()) } intern::Key::UInt64 { bits } => { BigInt::from_signed_bytes_le(&bits.to_le_bytes()) } intern::Key::PositiveInt { bigint } | intern::Key::NegativeInt { bigint } => bigint, _ => { unreachable!() } }; ComptimeNumber::Integral(ComptimeInt::Comptime(bigint)) } }, _ => { unreachable!() } } } use ast_visitor::AstVisitor; impl Ast { pub fn visitor_mut(&mut self) -> AstVisitor<&mut Self> { AstVisitor { scopes: vec![], nodes: self .get_root_file_indices() .map(|i| ast_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| ast_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| ast_visitor::A::PushChildren(i)) .collect(), ast: self, rev: false, } } } pub mod ast_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.index()], self.datas[node.index()]) } } 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.index()], self.datas[node.index()]) } } 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_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)] syms: &'a crate::symbol_table::syms2::Symbols, ip: &'a InternPool, cache: TypeCache, comptime_cache: ComptimeCache, } pub struct NodeDisplay<'a> { node: Index, ast: &'a Ast, ip: &'a InternPool, } impl<'a> Display for NodeDisplay<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let node = self.node; let tag = self.ast.tags[node.index()]; let loc = self.ast.source_locs[node.index()]; let children = Children(self.ast.get_node_children(node)); let ty = self.ast .get_type_of_node(self.ip, &mut TypeCache::new(), node); let is_comptime = self .ast .is_node_comptime_evaluable(&mut ComptimeCache::default(), node); writeln!( f, "{node} {}({ty}) = ({loc}) {tag:?} {children}", if is_comptime { "CONST " } else { "" } )?; Ok(()) } } impl<'a> AstRenderer<'a> { pub fn new( ast: &'a Ast, ip: &'a InternPool, syms: &'a crate::symbol_table::syms2::Symbols, ) -> Self { Self { ast, syms, ip, cache: TypeCache::new(), comptime_cache: ComptimeCache::default(), } } fn render(&mut self, w: &mut W) -> core::fmt::Result { self.ast.visitor().visit_pre(|ast, scopes, node, tag, _| { let loc = ast.source_locs[node.index()]; let children = Children(ast.get_node_children(node)); let ty = self.ast.get_type_of_node(self.ip, &mut self.cache, node); let is_comptime = ast.is_node_comptime_evaluable(&mut self.comptime_cache, node); _ = writeln_indented!( scopes.len() as u32 * 2, w, "{node} {}({ty}) = ({loc}) {tag:?} {children}", if is_comptime { "CONST " } else { "" } ); }); 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: 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: 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.index()] == Tag::Constant || self.ast.tags[node.index()].is_type()) && self.ast.tags[node.index()].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); } } 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.index()].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.index()] .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.index()] = Tag::InternedType; ast.datas[i.index()] = Data::intern(ty); } Tag::PointerType => { let (pointee, flags) = data.as_index_and_extra_offset(); let pointee = ast.datas[pointee.index()].as_intern(); let ty = self.intern.get_pointer_type( pointee, Some(PointerFlags::unpack(flags as u8)), ); ast.tags[i.index()] = Tag::InternedType; ast.datas[i.index()] = Data::intern(ty); } Tag::TypeDeclRef => { let decl = data.as_index(); let (name, _) = ast.datas[decl.index()] .as_intern_and_extra_offset(); let ty = self.intern.get_struct_type(name, decl); ast.tags[i.index()] = Tag::InternedType; ast.datas[i.index()] = Data::intern(ty); } Tag::FunctionProto => { let (_, i) = data.as_intern_and_extra_offset(); let return_type = ast.get_type_of_node( &self.intern, &mut TypeCache::new(), Index::new(ast.extra[i]), ); let parameters = { let (a, b) = ast.datas [ast.extra[i + 1] as usize] .as_extra_range(); ast.extra[a..b].iter().map(|&i| { // i is index to a parameter, a parameter is (index, intern) let ty = ast.datas[i as usize] .as_index_intern() .0; ast.datas[ty.index()].as_intern() }) }; self.intern .get_function_type(return_type, parameters); } 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::new(i)) .map(|i| { ast.datas[i.index()].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.index()].as_index_intern(); // look in my_scope if let Some(decl) = self.syms.find_type_symbol( scope, name, ast.source_locs[node.index()], ) { ast.resolve_type_ref(node, decl) }; } Tag::DeclRefUnresolved => { let (scope, name) = ast.datas[node.index()].as_index_intern(); // look in my_scope if let Some(decl) = self.syms.find_symbol( scope, name, ast.source_locs[node.index()], ) { ast.resolve_decl_ref(node, decl) }; } _ => {} } }); } 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_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_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(); 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_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_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 { match self.parse_var_decl_inner(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)) } } } 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_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| this.parse_expr(tokens), )?; 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, loc); 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(); 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::Local(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_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(self.parse_integral_constant( &next, next.source_location(), )); } Token::FloatingConstant | Token::FloatingExpConstant | Token::DotFloatingConstant | Token::DotFloatingExpConstant => { _ = tokens.next(); return Ok(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 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(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: Index, ) -> 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) } }, )?; Some(self.ast.push_call_expr(lhs, arguments, loc)) } Token::OpenSquareBracket => { let subscript = self .parse_bracketed(tokens, |this, tokens| { this.parse_expr(tokens) })?; Some(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 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) } /// 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_postfix_expr(tokens)?; self.ast.push_unary(Tag::Not, lhs, loc) } Token::Minus => { _ = tokens.next(); let lhs = self.parse_postfix_expr(tokens)?; self.ast.push_unary(Tag::Negate, lhs, loc) } Token::Ampersand => { _ = tokens.next(); let lhs = self.parse_postfix_expr(tokens)?; self.ast.push_unary(Tag::AddressOf, lhs, loc) } Token::Star => { _ = tokens.next(); let lhs = self.parse_postfix_expr(tokens)?; self.ast.push_unary(Tag::Deref, lhs, 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)?; return Ok(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 = node; let rhs = self.parse_binary_expr(tokens, prec + 1)?; 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 = 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(); let rhs = self.parse_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!() } }; self.ast.push_binary(tag, lhs, rhs, loc) }; Ok(self.ast.push_assign(lhs, rhs, loc)) } else { 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_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(self.ast.push_if_else(cond, body, else_expr, loc)) } else { Ok(self.ast.push_if(cond, body, 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(self.ast.push_block([], Some(expr), 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, }); }; match next.token() { Token::If => self.parse_if_expr(tokens), _ => self.parse_assignment_expr(tokens), } } /// 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(); 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, { 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)) } } } 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, { 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)) }, ) } fn parse_bracketed( &mut self, tokens: &mut TokenIterator, parse: F, ) -> ParseResult where F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult, { 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, { 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, { 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(); 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(); } 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(|_| ()) } } } pub mod ir_gen { use super::*; use crate::{symbol_table::syms2::Symbols, triples::*}; struct IRGen { ast: Ast, syms: Symbols, ir: IR, ip: intern::InternPool, } impl IRGen {} }