use std::{collections::HashMap, fmt::Display}; use itertools::Itertools; use num_bigint::{BigInt, BigUint}; use crate::{ ast::{self, FloatingType, IntegralType, LetOrVar, Node, PrimitiveType, Tag, Type}, common::NextIf, comptime::{self, ComptimeNumber}, error::{AnalysisError, AnalysisErrorTag}, lexer::{Radix, TokenIterator}, string_table::{ImmOrIndex, Index, StringTable}, symbol_table::{SymbolKind, SymbolTable}, tokens::Token, variant, }; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Unexpected end of token iter.")] UnexpectedEndOfTokens, #[error("Expected primitive type.")] ExpectedPrimitiveType, #[error("Expected token {0}.")] ExpectedTokenNotFound(Token), #[error("Dummy message.")] ExpectedLetOrVar, #[error("Dummy message.")] IntegralTypeTooWide, #[error("Dummy message.")] TriedToDerefNonPointer, } pub type Result = core::result::Result; #[derive(Debug)] pub struct Nodes { inner: Vec, } impl core::ops::Index for Nodes { type Output = Tag; fn index(&self, index: Node) -> &Self::Output { &self.inner[index.get() as usize] } } impl core::ops::IndexMut for Nodes { fn index_mut(&mut self, index: Node) -> &mut Self::Output { &mut self.inner[index.get() as usize] } } impl Nodes { fn new() -> Nodes { Self { inner: vec![Tag::Root], } } fn len(&self) -> u32 { self.inner.len() as u32 } fn set_node(&mut self, node: Node, tag: Tag) { *self.get_node_mut(node) = tag; } fn get_node_mut(&mut self, node: Node) -> &mut Tag { self.inner.get_mut(node.get() as usize).unwrap() } pub fn get_node(&self, node: Node) -> &Tag { self.inner.get(node.get() as usize).unwrap() } fn push_tag(&mut self, tag: Tag) -> Node { let node = Node::new(self.len()).unwrap(); self.inner.push(tag); node } fn reserve_node(&mut self) -> Node { self.push_tag(Tag::Undefined) } fn swap_nodes(&mut self, lhs: Node, rhs: Node) { self.inner.swap(lhs.get() as usize, rhs.get() as usize); } } // TODO: add a string-table which stores strings and maybe other bytes and // returns a range for identifiers, constants, etc. where bytes are stored // flatly, and next to each other. #[derive(Debug)] pub struct Tree { pub nodes: Nodes, pub st: SymbolTable, pub strings: StringTable, pub global_decls: Vec, } pub fn write_indented_inner( dst: &mut W, indent: u32, nl: bool, args: core::fmt::Arguments, ) -> std::result::Result<(), std::fmt::Error> { for _ in 0..indent { dst.write_char(' ')?; } dst.write_fmt(args)?; if nl { dst.write_char('\n')?; } Ok(()) } #[macro_export] macro_rules! write_indented { ($indent:expr, $w:expr, $($arg:tt)*) => { $crate::parser::write_indented_inner($w, $indent, false, format_args!($($arg)*)) }; } #[macro_export] macro_rules! writeln_indented { ($indent:expr, $w:expr, $($arg:tt)*) => { $crate::parser::write_indented_inner($w, $indent, true, format_args!($($arg)*)) }; } impl Tree { pub fn new() -> Tree { Self { nodes: Nodes::new(), st: SymbolTable::new(), strings: StringTable::new(), global_decls: Vec::new(), } } pub fn global_decls(&self) -> Vec<(Node, String)> { self.global_decls .iter() .map(|decl| { let name = match self.nodes.get_node(*decl) { Tag::FunctionDecl { proto, .. } => { let Tag::FunctionProto { name, .. } = self.nodes.get_node(*proto) else { unreachable!() }; self.get_ident_str(*name).unwrap().to_owned() } Tag::GlobalDecl { name, .. } => self.get_ident_str(*name).unwrap().to_owned(), _ => { unreachable!() } }; (*decl, name) }) .collect::>() } #[allow(unused)] fn is_integral_type(lexeme: &str) -> Option<()> { let mut iter = lexeme.chars(); iter.next_if(|&c| c == 'u' || c == 'i')?; iter.next_if(|&c| crate::common::is_digit(c))?; iter.take_while_ref(|&c| crate::common::is_digit(c)).count(); iter.next().is_none().then_some(()) } // returns an option instead of a result because failure here means the // lexeme is actually an identifier. fn try_parse_integral_type(lexeme: &str) -> Result> { let mut iter = lexeme.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(Error::IntegralTypeTooWide); } } } Ok(Some(IntegralType { signed, bits })) } /// returns (signed, bits) fn parse_integral_type(lexeme: &str) -> IntegralType { let mut iter = lexeme.chars(); let signed = match iter.next().unwrap() { 'u' => false, 'i' | 's' => true, _ => unreachable!(), }; let bits = iter.fold(0u16, |acc, c| { let digit = c as u8 - b'0'; acc * 10 + digit as u16 }); IntegralType { signed, bits } } fn parse_integral_constant(token: Token, lexeme: &str) -> (BigInt, Option) { let radix = Radix::from_token(token).unwrap(); // TODO: figure out how to do this safely for bigger types, whether to // wrap, saturate, or else. let iter = &mut lexeme.char_indices(); match radix { Radix::Bin | Radix::Oct | Radix::Hex => { _ = iter.advance_by(2); } _ => {} } let digits = iter .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 iter.clone().next() { Some((_, 'u')) | Some((_, 'i')) => { Some(Self::parse_integral_type(&lexeme[iter.next().unwrap().0..])) } _ => None, }; ( BigInt::from_biguint(num_bigint::Sign::Plus, BigUint::new(value)), ty, ) } fn parse_floating_constant(_token: Token, lexeme: &str) -> (u64, FloatingType) { // let (dot, exp) = match token { // Token::DotFloatingExpConstant => (true, true), // Token::DotFloatingConstant => (true, false), // Token::FloatingExpConstant => (false, true), // Token::FloatingConstant => (false, false), // _ => unreachable!(), // }; let lexeme = lexeme .strip_suffix("f32") .map(|l| (l, FloatingType::Binary32)) .unwrap_or( lexeme .strip_suffix("f64") .map(|l| (l, FloatingType::Binary64)) .unwrap_or((lexeme, FloatingType::Binary64)), ); let bits = match lexeme.1 { FloatingType::Binary32 => lexeme.0.parse::().unwrap().to_bits() as u64, FloatingType::Binary64 => lexeme.0.parse::().unwrap().to_bits() as u64, }; (bits, lexeme.1) } fn parse_ident(&mut self, tokens: &mut TokenIterator) -> Result { let ident = tokens.expect_token(Token::Ident)?; let name = self.strings.insert(ident.lexeme().as_bytes()); Ok(self.nodes.push_tag(Tag::Ident { name })) } fn ident_index(&self, node: Node) -> Index { match &self.nodes[node] { Tag::Ident { name } => *name, _ => Index::new(0, 0), } } pub fn parse_primitive_type(&mut self, tokens: &mut TokenIterator) -> Result { let token = tokens.next().ok_or(Error::UnexpectedEndOfTokens)?; let prim = match token.token() { Token::Void => PrimitiveType::Void, Token::Bool => PrimitiveType::Bool, Token::F32 => PrimitiveType::FloatingType(FloatingType::Binary32), Token::F64 => PrimitiveType::FloatingType(FloatingType::Binary64), _ => { return Err(Error::ExpectedPrimitiveType); } }; Ok(self.nodes.push_tag(Tag::PrimitiveType(prim))) } pub fn parse_pointer(&mut self, tokens: &mut TokenIterator) -> Result { tokens.expect_token(Token::Star)?; let _constness = tokens.eat_token(Token::Const); let typename = self.parse_typename(tokens)?; Ok(self.nodes.push_tag(Tag::Pointer { pointee: typename })) } pub fn parse_typename(&mut self, tokens: &mut TokenIterator) -> Result { match tokens.peek_token_or_err()?.token() { Token::Star => self.parse_pointer(tokens), Token::Ident => { let token = tokens.next().unwrap(); match Self::try_parse_integral_type(token.lexeme())? { Some(int) => Ok(self.nodes.push_tag(Tag::IntegralType(int))), None => { let name = self.strings.insert(token.lexeme().as_bytes()); Ok(self.nodes.push_tag(Tag::Ident { name })) } } } _ => self.parse_primitive_type(tokens), } } pub fn parse_var_decl(&mut self, tokens: &mut TokenIterator) -> Result { let let_or_var = match tokens .eat_token(Token::Let) .or_else(|| tokens.eat_token(Token::Var)) .map(|itm| itm.token()) .ok_or(Error::ExpectedLetOrVar)? { Token::Let => LetOrVar::Let, Token::Var => LetOrVar::Var, _ => unreachable!(), }; let name = self.parse_ident(tokens)?; let explicit_type = if tokens.eat_token(Token::Colon).is_some() { Some(self.parse_typename(tokens)?) } else { None }; let name_str = self.strings.get_str(self.ident_index(name)).to_owned(); let node = { let node = self.nodes.reserve_node(); self.st.insert_symbol(&name_str, node, SymbolKind::Var); node }; let assignment = if tokens.eat_token(Token::Equal).is_some() { let expr = self.parse_expr(tokens)?; Some(self.nodes.push_tag(Tag::Assign { lhs: node, rhs: expr, })) } else { None }; self.nodes.set_node( node, Tag::VarDecl { let_or_var, name, explicit_type, assignment, }, ); // return assignment if it exists, to make rendering and visiting easier Ok(assignment.unwrap_or(node)) } /// GLOBAL_DECL <- /// const IDENTIFIER (: TYPENAME)? = EXPR; pub fn parse_global_decl(&mut self, tokens: &mut TokenIterator) -> Result { _ = tokens.expect_token(Token::Const)?; let name = self.parse_ident(tokens)?; let explicit_type = if tokens.eat_token(Token::Colon).is_some() { Some(self.parse_typename(tokens)?) } else { None }; let name_str = self.get_ident_str(name).unwrap().to_owned(); let node = { let node = match self.st.find_root_symbol(&name_str) { Some(r) => r.node(), None => self .st .insert_root_symbol(&name_str, self.nodes.reserve_node()) .node(), }; node }; _ = tokens.expect_token(Token::Equal)?; let assignment = { let expr = self.parse_expr(tokens)?; self.nodes.push_tag(Tag::Assign { lhs: node, rhs: expr, }) }; self.nodes.set_node( node, Tag::GlobalDecl { name, explicit_type, assignment, }, ); tokens.expect_token(Token::Semi)?; Ok(assignment) } /// PARAMETER <- /// IDENTIFIER : TYPENAME pub fn parse_parameter(&mut self, tokens: &mut TokenIterator) -> Result { let name = self.parse_ident(tokens)?; tokens.expect_token(Token::Colon)?; let ty = self.parse_typename(tokens)?; let param = self.nodes.reserve_node(); self.st.insert_symbol( &self.get_ident_str(name).unwrap().to_owned(), param, SymbolKind::Var, ); self.nodes.set_node(param, Tag::Parameter { name, ty }); Ok(param) } /// PARAMETER_LIST <- /// PARAMETER /// PARAMETER_LIST , PARAMETER pub fn parse_parameter_list(&mut self, tokens: &mut TokenIterator) -> Result { let mut parameters = Vec::new(); loop { // PARAMETER parameters.push(self.parse_parameter(tokens)?); // COMMA if !tokens.is_next_token(Token::Comma) { break; } if !tokens.is_next_token2(Token::Ident) { break; } // skip comma _ = tokens.next(); } Ok(self.nodes.push_tag(Tag::ParameterList { parameters })) } /// FUNCTION_PROTO <- /// fn IDENTIFIER () /// fn IDENTIFIER () -> TYPENAME /// fn IDENTIFIER ( PARAMETER_LIST ,? ) /// fn IDENTIFIER ( PARAMETER_LIST ,? ) -> TYPENAME pub fn parse_fn_proto(&mut self, tokens: &mut TokenIterator) -> Result<(Node, Node)> { tokens.expect_token(Token::Fn)?; let name = self.parse_ident(tokens)?; tokens.expect_token(Token::OpenParens)?; let parameters = if !tokens.is_next_token(Token::CloseParens) { let parameters = self.parse_parameter_list(tokens)?; // trailing comma _ = tokens.eat_token(Token::Comma); Some(parameters) } else { None }; tokens.expect_token(Token::CloseParens)?; let return_type = if tokens.eat_token(Token::MinusGreater).is_some() { self.parse_typename(tokens)? } else { self.nodes.push_tag(Tag::PrimitiveType(PrimitiveType::Void)) }; let proto = self.nodes.push_tag(Tag::FunctionProto { name, parameters, return_type, }); Ok((proto, name)) } /// FUNCTION_DECL <- /// FUNCTION_PROTO BLOCK pub fn parse_fn_decl(&mut self, tokens: &mut TokenIterator) -> Result { let (proto, name) = self.parse_fn_proto(tokens)?; let decl = match self .st .find_orderless_symbol(self.get_ident_str(name).unwrap()) { Some(record) => record.node(), None => { let decl = self.nodes.reserve_node(); self.st .insert_orderless_symbol(&self.get_ident_str(name).unwrap().to_owned(), decl); decl } }; let block = self.nodes.reserve_node(); self.st.into_child(block); let body = self.parse_block(tokens, Some(block))?; let unresolved = self .st .extract_orderless_if(|_, v| self.nodes.get_node(v.node()) == &Tag::Undefined) .collect::>(); self.st.into_parent(); self.st.extend_orderless(unresolved); self.nodes.set_node(decl, Tag::FunctionDecl { proto, body }); Ok(decl) } /// BLOCK <- /// { STATEMENT* EXPRESSION? } pub fn parse_block( &mut self, tokens: &mut TokenIterator, reserved_node: Option, ) -> Result { let block = reserved_node.unwrap_or_else(|| self.nodes.reserve_node()); let mut stmts = Vec::new(); _ = tokens.expect_token(Token::OpenBrace)?; loop { if tokens.is_next_token(Token::CloseBrace) { break self.nodes.set_node( block, Tag::Block { statements: stmts, trailing_expr: None, }, ); } match tokens.peek_token_or_err()?.token() { Token::Return => { stmts.push(self.try_parse_return_stmt(tokens)?.unwrap()); } Token::Var | Token::Let => { let node = self.parse_var_decl(tokens)?; tokens.expect_token(Token::Semi)?; stmts.push(node); } _ => { let node = self.parse_expr(tokens)?; match tokens.peek_token_or_err()?.token() { Token::CloseBrace => { break self.nodes.set_node( block, Tag::Block { statements: stmts, trailing_expr: Some(node), }, ); } Token::Semi => { _ = tokens.next(); stmts.push(node); } _ => { unreachable!() } } } } } tokens.expect_token(Token::CloseBrace)?; Ok(block) } /// ASSIGNMENT_EXPR <- /// BINARY_EXPRESSION /// BINARY_EXPRESSION ASSIGNMENT_OP EXPRESSION pub fn parse_assignment_expr(&mut self, tokens: &mut TokenIterator) -> Result { let lhs = self.parse_binary_expr(tokens, 0)?; Ok(self.try_parse_assignment(lhs, tokens)?.unwrap_or(lhs)) } /// ASSIGNMENT_EXPR <- /// BINARY_EXPRESSION ASSIGNMENT_OP EXPRESSION /// ASSIGNMENT_OP <- /// = += -= *= /= %= ... pub fn try_parse_assignment( &mut self, lhs: Node, tokens: &mut TokenIterator, ) -> Result> { if tokens .peek_token() .map(|itm| itm.token().is_assignment_op()) == Some(true) { let op = tokens.next().unwrap(); let rhs = self.parse_expr(tokens)?; let rhs = match op.token() { Token::PlusEqual => self.nodes.push_tag(Tag::Add { lhs, rhs }), Token::MinusEqual => self.nodes.push_tag(Tag::Sub { lhs, rhs }), Token::StarEqual => self.nodes.push_tag(Tag::Mul { lhs, rhs }), Token::SlashEqual => self.nodes.push_tag(Tag::Sub { lhs, rhs }), Token::PercentEqual => self.nodes.push_tag(Tag::Rem { lhs, rhs }), Token::PipeEqual => self.nodes.push_tag(Tag::BitOr { lhs, rhs }), Token::CaretEqual => self.nodes.push_tag(Tag::BitXOr { lhs, rhs }), Token::AmpersandEqual => self.nodes.push_tag(Tag::BitAnd { lhs, rhs }), Token::LessLessEqual => self.nodes.push_tag(Tag::Shl { lhs, rhs }), Token::GreaterGreaterEqual => self.nodes.push_tag(Tag::Shr { lhs, rhs }), Token::Equal => rhs, _ => { unreachable!() } }; Ok(Some(self.nodes.push_tag(Tag::Assign { lhs, rhs }))) } else { Ok(None) } } /// RETURN_STATEMENT <- /// return EXPRESSION? ; pub fn try_parse_return_stmt(&mut self, tokens: &mut TokenIterator) -> Result> { if tokens.eat_token(Token::Return).is_some() { let expr = if !tokens.is_next_token(Token::Semi) { let expr = Some(self.parse_expr(tokens)?); expr } else { None }; tokens.expect_token(Token::Semi)?; Ok(Some(self.nodes.push_tag(Tag::ReturnStmt { expr }))) } else { Ok(None) } } /// STATEMENT <- /// RETURN_EXPRESSION /// VAR_DECL ; /// EXPRESSION ; pub fn parse_statement(&mut self, tokens: &mut TokenIterator) -> Result { match tokens.peek_token_or_err()?.token() { Token::Return => Ok(self.try_parse_return_stmt(tokens)?.unwrap()), Token::Var | Token::Let => { let node = self.parse_var_decl(tokens)?; tokens.expect_token(Token::Semi)?; Ok(node) } _ => { let node = self.parse_expr(tokens)?; tokens.expect_token(Token::Semi)?; Ok(node) } } } /// 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 pub fn parse_binary_expr( &mut self, tokens: &mut TokenIterator, precedence: u32, ) -> Result { let mut node = self.parse_as_expr(tokens)?; loop { let Some(tok) = tokens.peek_token() else { break; }; let Some(prec) = PRECEDENCE_MAP.get(&tok.token()).cloned() else { break; }; if prec < precedence { break; } 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 { lhs, rhs }, Token::AmpersandAmpersand => Tag::And { lhs, rhs }, Token::Pipe => Tag::BitOr { lhs, rhs }, Token::Caret => Tag::BitXOr { lhs, rhs }, Token::Ampersand => Tag::BitAnd { lhs, rhs }, Token::BangEqual => Tag::NEq { lhs, rhs }, Token::EqualEqual => Tag::Eq { lhs, rhs }, Token::LessEqual => Tag::Le { lhs, rhs }, Token::GreaterEqual => Tag::Ge { lhs, rhs }, Token::Less => Tag::Lt { lhs, rhs }, Token::Greater => Tag::Gt { lhs, rhs }, Token::GreaterGreater => Tag::Shr { lhs, rhs }, Token::LessLess => Tag::Shl { lhs, rhs }, Token::Plus => Tag::Add { lhs, rhs }, Token::Minus => Tag::Sub { lhs, rhs }, Token::Percent => Tag::Rem { lhs, rhs }, Token::Star => Tag::Mul { lhs, rhs }, Token::Slash => Tag::Div { lhs, rhs }, _ => unreachable!(), }; node = self.nodes.push_tag(tag); } Ok(node) } /// PREFIX_EXPR <- /// PRIMARY_EXPR /// ! PRIMARY_EXPR /// - PRIMARY_EXPR /// & PRIMARY_EXPR /// * PRIMARY_EXPR pub fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> Result { match tokens.peek_token_or_err()?.token() { Token::Bang => { _ = tokens.next(); let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Not { lhs })) } Token::Minus => { _ = tokens.next(); let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Negate { lhs })) } Token::Ampersand => { _ = tokens.next(); let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Ref { lhs })) } Token::Star => { _ = tokens.next(); let lhs = self.parse_primary_expr(tokens)?; Ok(self.nodes.push_tag(Tag::Deref { lhs })) } _ => self.parse_primary_expr(tokens), } } /// AS_EXPR <- /// PREFIX_EXPR /// PREFIX_EXPR as TYPENAME pub fn parse_as_expr(&mut self, tokens: &mut TokenIterator) -> Result { let expr = self.parse_prefix_expr(tokens)?; if tokens.eat_token(Token::As).is_some() { let typename = self.parse_typename(tokens)?; Ok(self.nodes.push_tag(Tag::ExplicitCast { lhs: expr, typename, })) } else { Ok(expr) } } pub fn parse_postfix_expr(&mut self, tokens: &mut TokenIterator) -> Result { // TODO self.parse_primary_expr(tokens) } /// PRIMARY_EXPR <- /// IDENTIFIER /// INTEGER_CONSTANT /// FLOATING_CONSTANT /// ( EXPRESSION ) /// { STATEMENT* EXPRESSION? } pub fn parse_primary_expr(&mut self, tokens: &mut TokenIterator) -> Result { let token = tokens.peek_token_or_err()?; match token.token() { Token::Ident => { let ident = tokens.expect_token(Token::Ident)?; let name = ident.lexeme(); if let Some(record) = self.st.find_ordered_symbol(name) { Ok(self.nodes.push_tag(Tag::DeclRef(record.node()))) } else if let Some(record) = self.st.find_orderless_symbol(name) { Ok(self.nodes.push_tag(Tag::GlobalRef(record.node()))) } else { let node = self .st .insert_orderless_symbol(name, self.nodes.reserve_node()) .node(); Ok(self.nodes.push_tag(Tag::GlobalRef(node))) } } Token::IntegerBinConstant | Token::IntegerHexConstant | Token::IntegerOctConstant | Token::IntegerConstant => { _ = tokens.next(); let (bits, ty) = Self::parse_integral_constant(token.token(), token.lexeme()); let (_, bytes) = bits.to_bytes_le(); const BUF_SIZE: usize = core::mem::size_of::(); let mut buf = [0u8; BUF_SIZE]; buf[..bytes.len().min(BUF_SIZE)] .copy_from_slice(&bytes[..bytes.len().min(BUF_SIZE)]); let bytes = match bytes.len() { 0..2 => { let (buf, _) = buf.split_at(core::mem::size_of::()); let dw = u32::from_le_bytes(buf.try_into().unwrap()); ImmOrIndex::U32(dw) } 0..4 => { let (buf, _) = buf.split_at(core::mem::size_of::()); let qw = u64::from_le_bytes(buf.try_into().unwrap()); ImmOrIndex::U64(qw) } 0.. => { let idx = self.strings.insert(bytes); ImmOrIndex::Index(idx) } }; let ty = match ty { Some(int) => Type::Integer(int), None => Type::ComptimeNumber, }; Ok(self.nodes.push_tag(Tag::Constant { bytes, ty })) } Token::FloatingConstant | Token::FloatingExpConstant | Token::DotFloatingConstant | Token::DotFloatingExpConstant => { _ = tokens.next(); let (bits, ty) = Self::parse_floating_constant(token.token(), token.lexeme()); let bytes = match ty { FloatingType::Binary32 => ImmOrIndex::U32(bits as u32), FloatingType::Binary64 => ImmOrIndex::U64(bits as u64), }; Ok(self.nodes.push_tag(Tag::Constant { bytes, ty: Type::Floating(ty), })) } Token::OpenParens => { _ = tokens.next(); let node = self.parse_expr(tokens)?; tokens.expect_token(Token::CloseParens)?; Ok(node) } Token::OpenBrace => { let node = self.parse_block(tokens, None)?; Ok(node) } _ => unreachable!(), } } /// EXPRESSION <- /// ASSIGNMENT_EXPR pub fn parse_expr(&mut self, tokens: &mut TokenIterator) -> Result { self.parse_assignment_expr(tokens) } /// PROGRAM <- /// (FUNCTION_DECL | GLOBAL_DECL)* pub fn parse_program(&mut self, tokens: &mut TokenIterator) -> Result<()> { while tokens.peek_token().is_some() { let Some(token) = tokens.peek_token().map(|itm| itm.token()) else { break; }; let decl = match token { Token::Const => self.parse_global_decl(tokens)?, Token::Fn => self.parse_fn_decl(tokens)?, _ => { eprintln!("unexpected token: {}", token); panic!("unexpected token at global scope"); } }; self.global_decls.push(decl); } Ok(()) } pub fn parse(&mut self, mut tokens: TokenIterator) -> Result<()> { self.parse_program(&mut tokens) } pub fn get_ident_str(&self, node: Node) -> Option<&str> { match &self.nodes[node] { Tag::Ident { name } => Some(self.strings.get_str(*name)), _ => None, } } fn get_typename_str(&self, node: Node) -> Option { match self.nodes.get_node(node) { Tag::IntegralType(i) => Some(i.to_string()), Tag::Ident { name } => Some(self.strings.get_str(*name).to_owned()), Tag::Pointer { pointee } => self.get_typename_str(*pointee), Tag::PrimitiveType(prim) => Some(prim.to_string()), _ => None, } } } impl Tree { pub fn get_node_children(&self, node: Node) -> Vec { match self.nodes.get_node(node) { Tag::FunctionProto { name, parameters, return_type, } => { if let Some(params) = parameters { vec![*name, *params, *return_type] } else { vec![*name, *return_type] } } Tag::ParameterList { parameters } => parameters.clone(), Tag::Parameter { name, ty } => { vec![*name, *ty] } Tag::Pointer { pointee } => { vec![*pointee] } Tag::FunctionDecl { proto, body } => { vec![*proto, *body] } Tag::Block { statements, trailing_expr, } => { let mut children = statements.clone(); if let Some(expr) = trailing_expr { children.push(*expr); } children } Tag::ReturnStmt { expr } => expr.into_iter().cloned().collect::>(), &Tag::ExprStmt { expr } => { vec![expr] } Tag::VarDecl { name, explicit_type, .. } => { if let Some(ty) = *explicit_type { vec![*name, ty] } else { vec![*name] } } Tag::GlobalDecl { name, explicit_type, .. } => { if let Some(ty) = *explicit_type { vec![*name, ty] } else { vec![*name] } } &Tag::CallExpr { lhs, rhs } => { if let Some(rhs) = rhs { vec![lhs, rhs] } else { vec![lhs] } } Tag::ArgumentList { parameters } => parameters.clone(), &Tag::Argument { name, expr } => { if let Some(name) = name { vec![name, expr] } else { vec![expr] } } &Tag::ExplicitCast { lhs, typename } => { vec![lhs, typename] } Tag::Deref { lhs } | Tag::Ref { lhs } | Tag::Not { lhs } | Tag::Negate { lhs } => { vec![*lhs] } Tag::Or { lhs, rhs } | Tag::And { lhs, rhs } | Tag::BitOr { lhs, rhs } | Tag::BitAnd { lhs, rhs } | Tag::BitXOr { lhs, rhs } | Tag::Eq { lhs, rhs } | Tag::NEq { lhs, rhs } | Tag::Lt { lhs, rhs } | Tag::Gt { lhs, rhs } | Tag::Le { lhs, rhs } | Tag::Ge { lhs, rhs } | Tag::Shl { lhs, rhs } | Tag::Shr { lhs, rhs } | Tag::Add { lhs, rhs } | Tag::Sub { lhs, rhs } | Tag::Mul { lhs, rhs } | Tag::Rem { lhs, rhs } | Tag::Div { lhs, rhs } | Tag::Assign { lhs, rhs } => { vec![*lhs, *rhs] } _ => vec![], } } } impl Tree { fn render_node( &mut self, writer: &mut W, node: Node, indent: u32, ) -> core::fmt::Result { match self.nodes[node].clone() { Tag::FunctionProto { name, parameters, return_type, } => { self.render_node(writer, name, indent)?; self.render_node(writer, return_type, indent)?; if let Some(parameters) = parameters { self.render_node(writer, parameters, indent)?; } write_indented!(indent, writer, "%{} = function_proto: {{", node.get())?; write!(writer, "name: \"{}\"", self.get_ident_str(name).unwrap())?; if let Some(parameters) = parameters { write!(writer, ", parameters: %{}", parameters.get())?; } write!(writer, ", return_type: %{}", return_type.get())?; writeln!(writer, "}}") } Tag::ParameterList { parameters } => { writeln_indented!(indent, writer, "%{} = ParameterList [", node.get())?; for param in parameters { self.render_node(writer, param, indent + 1)?; } writeln_indented!(indent, writer, "]") } Tag::Parameter { name, ty } => { writeln_indented!( indent, writer, "%{} = {}: {},", node.get(), self.get_ident_str(name).unwrap(), self.get_typename_str(ty).unwrap() ) } Tag::Pointer { .. } | Tag::IntegralType(_) | Tag::PrimitiveType(_) => { writeln_indented!( indent, writer, "%{} = type({})", node.get(), self.get_typename_str(node).unwrap() ) } Tag::PointerQualifier { .. } => todo!(), Tag::FunctionDecl { proto, body } => { self.render_node(writer, proto, indent)?; writeln_indented!( indent, writer, "%{} = function_decl( proto: %{}, body: %{}) {{", node.get(), proto.get(), body.get() )?; self.render_node(writer, body, indent + 1)?; writeln_indented!(indent, writer, "}}") } Tag::Ident { name } => { writeln_indented!( indent, writer, "%{} = identifier(\"{}\")", node.get(), self.strings.get_str(name) ) } Tag::Block { statements, trailing_expr, } => { writeln_indented!(indent, writer, "%{} = {{", node.get())?; self.st.into_child(node); for stmt in statements { self.render_node(writer, stmt, indent + 1)?; } if let Some(expr) = trailing_expr { self.render_node(writer, expr, indent + 1)?; writeln_indented!( indent + 1, writer, "break %{} %{};", node.get(), expr.get() )?; } self.st.into_parent(); writeln_indented!(indent, writer, "}}") } Tag::ReturnStmt { expr } => { if let Some(expr) = expr { self.render_node(writer, expr, indent)?; writeln_indented!(indent, writer, "%{} = return %{};", node.get(), expr.get()) } else { writeln_indented!(indent, writer, "%{} = return;", node.get()) } } Tag::ExprStmt { expr } => self.render_node(writer, expr, indent), Tag::VarDecl { let_or_var, name, explicit_type, .. } => { self.render_node(writer, name, indent)?; explicit_type.map(|ty| self.render_node(writer, ty, indent)); write_indented!( indent, writer, "%{} = decl_{}(name: \"{}\"", node.get(), match let_or_var { LetOrVar::Let => { "const" } LetOrVar::Var => { "mut" } }, self.get_ident_str(name).unwrap() )?; if let Some(ty) = explicit_type { write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?; } writeln!(writer, ");")?; Ok(()) } Tag::GlobalDecl { name, explicit_type, .. } => { self.render_node(writer, name, indent)?; explicit_type.map(|ty| self.render_node(writer, ty, indent)); write_indented!( indent, writer, "%{} = global_decl(name: \"{}\"", node.get(), self.get_ident_str(name).unwrap() )?; if let Some(ty) = explicit_type { write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?; } writeln!(writer, ");")?; Ok(()) } Tag::CallExpr { .. } => todo!(), Tag::ArgumentList { .. } => todo!(), Tag::Argument { .. } => todo!(), Tag::ExplicitCast { lhs, typename } => { self.render_node(writer, lhs, indent)?; writeln_indented!( indent, writer, "%{} = cast<{}>(%{})", node.get(), self.get_typename_str(typename).unwrap(), lhs.get() ) } Tag::Deref { lhs } => { self.render_node(writer, lhs, indent)?; writeln_indented!(indent, writer, "%{} = deref(%{})", node.get(), lhs.get()) } Tag::Ref { lhs } => { self.render_node(writer, lhs, indent)?; writeln_indented!( indent, writer, "%{} = address_of(%{})", node.get(), lhs.get() ) } Tag::Not { lhs } => { self.render_node(writer, lhs, indent)?; writeln_indented!(indent, writer, "%{} = ", node.get(),) } Tag::Negate { lhs } => { self.render_node(writer, lhs, indent)?; writeln_indented!(indent, writer, "%{} = not(%{})", node.get(), lhs.get()) } Tag::Or { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} || %{}", node.get(), lhs.get(), rhs.get() ) } Tag::And { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} && %{}", node.get(), lhs.get(), rhs.get() ) } Tag::BitOr { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} | %{}", node.get(), lhs.get(), rhs.get() ) } Tag::BitAnd { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} & %{}", node.get(), lhs.get(), rhs.get() ) } Tag::BitXOr { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} ^ %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Eq { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} == %{}", node.get(), lhs.get(), rhs.get() ) } Tag::NEq { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} != %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Lt { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} < %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Gt { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} > %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Le { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} <= %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Ge { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} >= %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Shl { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} << %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Shr { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} >> %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Add { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} + %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Sub { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} - %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Mul { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} * %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Div { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} / %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Rem { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = %{} % %{}", node.get(), lhs.get(), rhs.get() ) } Tag::Assign { lhs, rhs } => { self.render_node(writer, lhs, indent)?; self.render_node(writer, rhs, indent)?; writeln_indented!( indent, writer, "%{} = store(dst: %{}, val: %{})", node.get(), lhs.get(), rhs.get() ) } Tag::DeclRef(decl) => { writeln_indented!( indent, writer, "%{} = decl_ref(%{}, name: {})", node.get(), decl.get(), self.st .find_symbol_by_decl(decl) .map(|a| a.name()) .unwrap_or(&format!( "SymbolTable entry not found?, %{}, %{}", node.get(), decl.get() )) ) } Tag::GlobalRef(decl) => { writeln_indented!( indent, writer, "%{} = global_ref(%{}, name: {})", node.get(), decl.get(), self.st .symbol_path(decl) .map(|p| p.mangle(self)) .unwrap_or(format!( "SymbolTable entry not found?, %{}, %{}", node.get(), decl.get() )) ) } Tag::Constant { bytes, ty } => { writeln_indented!( indent, writer, "%{} = constant{{ ty: {}, bytes: {}}}", node.get(), ty, self.strings.display_idx(bytes) ) } _ => unreachable!(), } } pub fn render(&mut self, writer: &mut W) -> core::fmt::Result { for decl in &self.global_decls.clone() { self.render_node(writer, *decl, 0)?; } Ok(()) } pub fn type_of_node(&self, node: Node) -> crate::ast::Type { match self.nodes.get_node(node) { Tag::FunctionDecl { proto, .. } => self.type_of_node(*proto), Tag::FunctionProto { parameters, return_type, .. } => { let return_type = self.type_of_node(*return_type); let parameter_types = parameters .map(|p| match self.nodes.get_node(p) { Tag::ParameterList { parameters } => parameters .iter() .map(|p| self.type_of_node(*p)) .collect::>(), _ => panic!("parameters is not a parameterlist!"), }) .unwrap_or(Vec::new()); crate::ast::Type::Fn { parameter_types, return_type: Box::new(return_type), } } Tag::Parameter { ty, .. } => self.type_of_node(*ty), Tag::Pointer { pointee } => Type::Pointer { constness: false, pointee: Box::new(self.type_of_node(*pointee)), }, Tag::Constant { ty, .. } => ty.clone(), Tag::IntegralType(t) => Type::Integer(*t), Tag::PrimitiveType(t) => match t { PrimitiveType::FloatingType(t) => Type::Floating(*t), PrimitiveType::IntegralType(t) => Type::Integer(*t), PrimitiveType::Bool => Type::bool(), PrimitiveType::Void => Type::void(), }, Tag::Block { trailing_expr, .. } => trailing_expr .map(|n| self.type_of_node(n)) .unwrap_or(Type::void()), Tag::VarDecl { explicit_type, assignment, // this is a Tag::Assign .. } => { let lhs = explicit_type.map(|n| self.type_of_node(n)); let rhs = assignment.map(|n| match self.nodes.get_node(n) { Tag::Assign { rhs, .. } => self.type_of_node(*rhs), _ => unreachable!(), }); if lhs.as_ref().zip(rhs.as_ref()).map(|(l, r)| l != r) == Some(true) { eprintln!("vardecl: incompatible types {lhs:?} and {rhs:?}."); } lhs.or(rhs) .expect("Type could not be automatically deduced.") } Tag::GlobalDecl { explicit_type, assignment, // this is a Tag::Assign .. } => { let lhs = explicit_type.map(|n| self.type_of_node(n)); let rhs = match self.nodes.get_node(*assignment) { Tag::Assign { rhs, .. } => self.type_of_node(*rhs), _ => unreachable!(), }; if lhs.as_ref().zip(Some(&rhs)).map(|(l, r)| l != r) == Some(true) { eprintln!("vardecl: incompatible types {lhs:?} and {rhs:?}."); } lhs.unwrap_or(rhs) } Tag::CallExpr { lhs, .. } => self.type_of_node(*lhs), Tag::ExplicitCast { typename, .. } => self.type_of_node(*typename), Tag::Deref { lhs } => self.type_of_node(*lhs).remove_ptr().unwrap(), Tag::Ref { lhs } => self.type_of_node(*lhs).into_ptr(), Tag::Not { lhs } => self.type_of_node(*lhs), Tag::Negate { lhs } => self.type_of_node(*lhs), Tag::Or { lhs, .. } => self.type_of_node(*lhs), Tag::And { lhs, .. } => self.type_of_node(*lhs), Tag::BitOr { lhs, .. } => self.type_of_node(*lhs), Tag::BitAnd { lhs, .. } => self.type_of_node(*lhs), Tag::BitXOr { lhs, .. } => self.type_of_node(*lhs), Tag::Shl { lhs, .. } => self.type_of_node(*lhs), Tag::Shr { lhs, .. } => self.type_of_node(*lhs), Tag::Add { lhs, .. } => self.type_of_node(*lhs), Tag::Sub { lhs, .. } => self.type_of_node(*lhs), Tag::Mul { lhs, .. } => self.type_of_node(*lhs), Tag::Rem { lhs, .. } => self.type_of_node(*lhs), Tag::Div { lhs, .. } => self.type_of_node(*lhs), Tag::Eq { .. } => Type::bool(), Tag::NEq { .. } => Type::bool(), Tag::Lt { .. } => Type::bool(), Tag::Gt { .. } => Type::bool(), Tag::Le { .. } => Type::bool(), Tag::Ge { .. } => Type::bool(), Tag::DeclRef(decl) => self.type_of_node(*decl), Tag::GlobalRef(decl) => self.type_of_node(*decl), _ => Type::void(), } } } // simplify tree with compile-time math impl Tree { fn is_node_comptime(&self, node: Node, check_declrefs: bool) -> bool { match self.nodes.get_node(node) { Tag::Block { statements, trailing_expr, } => statements .iter() .chain(trailing_expr.into_iter()) .all(|n| self.is_node_comptime(*n, true)), Tag::Constant { .. } => true, Tag::ExplicitCast { lhs, typename } => { self.is_node_comptime(*lhs, true) && match self.type_of_node(*typename) { Type::Bool | Type::ComptimeNumber | Type::Integer(_) | Type::Floating(_) => true, _ => false, } } &Tag::DeclRef(lhs) if check_declrefs => { let start = lhs; let end = node; let mut is_comptime = true; ast::tree_visitor::Visitor::new_seek( self,start, |_: &Tree, _| { }, |tree: &Tree, node| match tree.nodes.get_node(node) { &Tag::Assign { lhs, rhs } => { if lhs == start || matches!(tree.nodes.get_node(lhs), &Tag::DeclRef(decl) if decl == start) { is_comptime &= self.is_node_comptime(rhs, true); } } &Tag::Ref { lhs } if lhs == start => { // recursively checking for derefs would get very complicated. is_comptime = false; } _ => {} }, ) .until_after(end) .visit(self); is_comptime } Tag::Not { lhs } | Tag::Negate { lhs } => self.is_node_comptime(*lhs, true), Tag::Or { lhs, rhs } | Tag::And { lhs, rhs } | Tag::BitOr { lhs, rhs } | Tag::BitAnd { lhs, rhs } | Tag::BitXOr { lhs, rhs } | Tag::Eq { lhs, rhs } | Tag::NEq { lhs, rhs } | Tag::Lt { lhs, rhs } | Tag::Gt { lhs, rhs } | Tag::Le { lhs, rhs } | Tag::Ge { lhs, rhs } | Tag::Shl { lhs, rhs } | Tag::Shr { lhs, rhs } | Tag::Add { lhs, rhs } | Tag::Sub { lhs, rhs } | Tag::Mul { lhs, rhs } | Tag::Rem { lhs, rhs } | Tag::Div { lhs, rhs } => { self.is_node_comptime(*lhs, true) && self.is_node_comptime(*rhs, true) } _ => false, } } fn fold_comptime_with_visitor(&mut self, decl: Node) { ast::tree_visitor::Visitor::new( decl, |_: &mut Tree, _| {}, |tree: &mut Tree, node| { if let Ok(value) = tree.fold_comptime_inner(node, false) { let (bytes, ty) = value.into_bytes_and_type(); let idx = tree.strings.insert(bytes); *tree.nodes.get_node_mut(node) = Tag::Constant { bytes: ImmOrIndex::Index(idx), ty, }; } }, ) .visit_mut(self); } fn fold_comptime_inner( &mut self, decl: Node, check_declrefs: bool, ) -> comptime::Result { if self.is_node_comptime(decl, check_declrefs) { match self.nodes.get_node(decl) { Tag::Constant { bytes, ty } => { let bytes = match bytes { ImmOrIndex::U64(v) => &v.to_le_bytes()[..], ImmOrIndex::U32(v) => &v.to_le_bytes()[..], ImmOrIndex::Index(idx) => self.strings.get_bytes(*idx), }; let number: ComptimeNumber = match ty { Type::Bool => (bytes[0] != 0).into(), Type::ComptimeNumber => { BigInt::from_bytes_le(num_bigint::Sign::Plus, bytes).into() } Type::Integer(ty) => { if bytes.len() > core::mem::size_of::() { let bits = BigInt::from_bytes_le(num_bigint::Sign::Plus, bytes); (bits, *ty).into() } else { let mut buf = [0u8; core::mem::size_of::()]; buf[..bytes.len()].copy_from_slice(bytes); let bits = u128::from_le_bytes(buf); (bits, *ty).into() } } Type::Floating(ty) => match ty { FloatingType::Binary32 => { (f32::from_le_bytes((&bytes[..4]).try_into().unwrap())).into() } FloatingType::Binary64 => { (f64::from_le_bytes((&bytes[..8]).try_into().unwrap())).into() } }, _ => unimplemented!(), }; return Ok(number); } Tag::Negate { lhs } => { let lhs = self.fold_comptime_inner(*lhs, true)?; return Ok(lhs.neg()?); } Tag::ExplicitCast { lhs, typename } => { let ty = self.type_of_node(*typename); let lhs = self.fold_comptime_inner(*lhs, true)?; return match ty { Type::Bool => lhs.into_bool(), Type::Integer(ty) => lhs.into_int(ty), Type::Floating(ty) => lhs.into_float(ty), _ => unimplemented!(), }; } Tag::Not { lhs } => { let lhs = self.fold_comptime_inner(*lhs, true)?; return lhs.not(); } Tag::Or { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.or(rhs); } Tag::And { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.and(rhs); } Tag::Eq { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.eq(rhs); } Tag::NEq { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.eq(rhs)?.not(); } Tag::Lt { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.lt(rhs); } Tag::Gt { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.gt(rhs); } Tag::Le { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.le(rhs); } Tag::Ge { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.ge(rhs); } Tag::BitOr { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.bitor(rhs); } Tag::BitAnd { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.bitand(rhs); } Tag::BitXOr { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.bitxor(rhs); } Tag::Shl { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.shl(rhs); } Tag::Shr { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.shr(rhs); } Tag::Add { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.add(rhs); } Tag::Sub { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.sub(rhs); } Tag::Mul { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.mul(rhs); } Tag::Rem { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.rem(rhs); } Tag::Div { lhs, rhs } => { let (lhs, rhs) = (*lhs, *rhs); let lhs = self.fold_comptime_inner(lhs, true)?; let rhs = self.fold_comptime_inner(rhs, true)?; return lhs.div(rhs); } &Tag::DeclRef(lhs) => { let start = lhs; let end = decl; let mut last_value = None; ast::tree_visitor::Visitor::new_seek( self,start, |_: &Tree, node| { }, |tree: &Tree, node| match tree.nodes.get_node(node) { &Tag::Assign { lhs, rhs } => { if lhs == start || matches!(tree.nodes.get_node(lhs), &Tag::DeclRef(decl) if decl == start) { last_value = Some(rhs); } } _ => {} }, ) .until_after(end) .visit(self); return self.fold_comptime_inner( last_value.ok_or(comptime::Error::NotComptime)?, true, ); } _ => { unreachable!() } } } else { Err(comptime::Error::NotComptime) } } pub fn fold_comptime(&mut self) { for decl in self.global_decls.clone() { match self.nodes.get_node(decl) { Tag::FunctionDecl { body, .. } => { self.fold_comptime_with_visitor(*body); } Tag::GlobalDecl { assignment, .. } => { self.fold_comptime_with_visitor(*assignment); } _ => unreachable!(), } } } } impl Tree { /// type-checks and inserts appropriate explicit-cast nodes. pub fn typecheck(&mut self) { let mut errors = Vec::new(); for decl in self.global_decls.clone() { self.typecheck_node(&mut errors, decl); } } // TODO: inline types into the AST proper before tackling this. // for now, comptime_number is not supported in IR gen, then. fn typecheck_node(&mut self, errors: &mut Vec, node: Node) { #[allow(unused_variables)] match self.nodes[node].clone() { Tag::FunctionProto { .. } => {} Tag::FunctionDecl { proto, body } => { let Tag::FunctionProto { return_type, .. } = self.nodes[proto] else { unreachable!() }; let body_t = self.type_of_node(body); let ret_t = self.type_of_node(return_type); if let Some(peer_t) = body_t.equal_type(&ret_t) { if body_t == Type::comptime_number() { let Tag::Block { trailing_expr, .. } = self.nodes[body] else { unreachable!() }; if let Some(expr) = trailing_expr { let ty = self.nodes.push_tag(Tag::PrimitiveType( peer_t .as_primitive_type() .expect("comptime cannot be cast into a non-primitive type"), )); let expr = self.nodes.push_tag(Tag::ExplicitCast { lhs: expr, typename: ty, }); let Tag::Block { trailing_expr, .. } = &mut self.nodes[body] else { unreachable!() }; *trailing_expr = Some(expr) } } } else { errors.push(AnalysisError::new( AnalysisErrorTag::MismatchingTypesFunctionReturn, )); } } Tag::Constant { bytes, ty } => { let bits = self.strings.count_bits(bytes); if bits < ty.bit_width() as u32 { errors.push(AnalysisError::new( AnalysisErrorTag::InsufficientBitsInTypeForConstant(bits, ty.clone()), )); } } Tag::Block { statements, trailing_expr, } => { for statement in statements { self.typecheck_node(errors, statement); } if let Some(expr) = trailing_expr { self.typecheck_node(errors, expr); } } Tag::ReturnStmt { expr } => { if let Some(expr) = expr { self.typecheck_node(errors, expr); } } Tag::ExprStmt { expr } => { self.typecheck_node(errors, expr); } Tag::VarDecl { explicit_type, assignment, .. } => { assignment.map(|t| self.typecheck_node(errors, t)); let explicit_t = explicit_type.map(|t| self.type_of_node(t)); let assignment_t = assignment.map(|t| self.type_of_node(t)); match (explicit_t, assignment_t) { (None, None) => unreachable!(), (Some(explicit_t), None) => {} (Some(explicit_t), Some(assignment_t)) => { // TODO: ensure types match, explicit-cast comptime_number } (None, Some(assignment_t)) => { // TODO: set explicit_type to assignment_t } } } Tag::GlobalDecl { name, explicit_type, assignment, } => todo!(), Tag::DeclRef(_) => todo!(), Tag::GlobalRef(_) => todo!(), Tag::CallExpr { lhs, rhs } => todo!(), Tag::ArgumentList { parameters } => todo!(), Tag::Argument { name, expr } => todo!(), Tag::ExplicitCast { lhs, typename } => todo!(), Tag::Deref { lhs } => todo!(), Tag::Ref { lhs } => todo!(), Tag::Not { lhs } => todo!(), Tag::Negate { lhs } => todo!(), Tag::Or { lhs, rhs } => todo!(), Tag::And { lhs, rhs } => todo!(), Tag::BitOr { lhs, rhs } => todo!(), Tag::BitAnd { lhs, rhs } => todo!(), Tag::BitXOr { lhs, rhs } => todo!(), Tag::Eq { lhs, rhs } => todo!(), Tag::NEq { lhs, rhs } => todo!(), Tag::Lt { lhs, rhs } => todo!(), Tag::Gt { lhs, rhs } => todo!(), Tag::Le { lhs, rhs } => todo!(), Tag::Ge { lhs, rhs } => todo!(), Tag::Shl { lhs, rhs } => todo!(), Tag::Shr { lhs, rhs } => todo!(), Tag::Add { lhs, rhs } => todo!(), Tag::Sub { lhs, rhs } => todo!(), Tag::Mul { lhs, rhs } => todo!(), Tag::Rem { lhs, rhs } => todo!(), Tag::Div { lhs, rhs } => todo!(), Tag::Assign { lhs, rhs } => todo!(), _ => { unreachable!() } } } } static PRECEDENCE_MAP: std::sync::LazyLock> = std::sync::LazyLock::new(|| { HashMap::from([ (Token::PipePipe, 10), (Token::AmpersandAmpersand, 20), (Token::Pipe, 30), (Token::Caret, 40), (Token::Ampersand, 50), (Token::BangEqual, 60), (Token::EqualEqual, 60), (Token::LessEqual, 70), (Token::GreaterEqual, 70), (Token::Less, 70), (Token::Greater, 70), (Token::GreaterGreater, 80), (Token::LessLess, 80), (Token::Plus, 90), (Token::Minus, 90), (Token::Percent, 100), (Token::Star, 100), (Token::Slash, 100), ]) }); #[cfg(test)] mod tests { use crate::lexer::Tokenizer; use super::*; #[test] fn render_ast() { let src = "let a: u21 = 3u32;"; let tokens = Tokenizer::new(src.as_bytes()).unwrap(); let mut tree = Tree::new(); tree.parse(tokens.iter()).unwrap(); let mut buf = String::new(); tree.render(&mut buf).unwrap(); println!("{buf}"); } #[test] fn render_ast2() { let src = " fn main() -> void { let a: u32 = 0u32; a == 1u32 } fn square(x: u32) -> u32 { x * x } "; let tokens = Tokenizer::new(src.as_bytes()).unwrap(); let mut tree = Tree::new(); tree.parse(tokens.iter()).unwrap(); let mut buf = String::new(); tree.render(&mut buf).unwrap(); println!("{buf}"); } #[test] fn render_ast3() { let src = " fn main() -> void { let a: u32 = 0u32; a == global } const global: u32 = 42u32; "; let tokens = Tokenizer::new(src.as_bytes()).unwrap(); let mut tree = Tree::new(); tree.parse(tokens.iter()).unwrap(); let mut buf = String::new(); tree.render(&mut buf).unwrap(); println!("{buf}"); } #[test] fn comptime() { let src = " fn main() -> void { let x: u32; x = 666u32; let a = x + 3 * 49573 << 4; } "; let tokens = Tokenizer::new(src.as_bytes()).unwrap(); let mut tree = Tree::new(); tree.parse(tokens.iter()).unwrap(); let mut buf = String::new(); tree.render(&mut buf).unwrap(); println!("{buf}"); tree.fold_comptime_with_visitor(tree.global_decls.first().cloned().unwrap()); let mut buf = String::new(); tree.render(&mut buf).unwrap(); println!("{buf}"); } }