From 2689179ed454750d9c4bb9668036949985c1ee5c Mon Sep 17 00:00:00 2001 From: Janis Date: Wed, 14 Aug 2024 17:55:03 +0200 Subject: [PATCH] changed globaldecl to only allow const instead of let or var as keyword --- src/ast.rs | 7 +++ src/parser.rs | 102 ++++++++++++++++++++++++++++++++++------- src/triples.rs | 122 ++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 192 insertions(+), 39 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 5efd82f..dbda4cf 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -69,6 +69,13 @@ pub enum Tag { explicit_type: Option, assignment: Option, }, + GlobalDecl { + /// Ident + name: Node, + /// TypeName + explicit_type: Option, + assignment: Node, + }, DeclRef(Node), CallExpr { /// Ident | Expr diff --git a/src/parser.rs b/src/parser.rs index dedf160..f64e237 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -297,7 +297,7 @@ impl Tree { } } - pub fn parse_var_decl(&mut self, tokens: &mut TokenIterator, global: bool) -> Result { + 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)) @@ -318,16 +318,7 @@ impl Tree { }; let name_str = self.nodes.get_ident_str(name).unwrap().to_owned(); - let node = if global { - 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 - } else { + let node = { let node = self.nodes.reserve_node(); self.st.insert_symbol(&name_str, node, SymbolKind::Var); node @@ -357,11 +348,53 @@ impl Tree { Ok(assignment.unwrap_or(node)) } + /// GLOBAL_DECL <- + /// const IDENTIFIER (: TYPENAME)? = EXPR; pub fn parse_global_decl(&mut self, tokens: &mut TokenIterator) -> Result { - let node = self.parse_var_decl(tokens, true)?; + _ = 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.nodes.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(node) + Ok(assignment) } /// PARAMETER <- @@ -499,7 +532,7 @@ impl Tree { stmts.push(self.try_parse_return_stmt(tokens)?.unwrap()); } Token::Var | Token::Let => { - let node = self.parse_var_decl(tokens, false)?; + let node = self.parse_var_decl(tokens)?; tokens.expect_token(Token::Semi)?; stmts.push(node); @@ -608,7 +641,7 @@ impl Tree { 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, false)?; + let node = self.parse_var_decl(tokens)?; tokens.expect_token(Token::Semi)?; Ok(node) @@ -816,7 +849,7 @@ impl Tree { }; let decl = match token { - Token::Var | Token::Let => self.parse_global_decl(tokens)?, + Token::Const => self.parse_global_decl(tokens)?, Token::Fn => self.parse_fn_decl(tokens)?, _ => { eprintln!("unexpected token: {}", token); @@ -994,6 +1027,26 @@ impl Tree { 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.nodes.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!(), @@ -1344,6 +1397,21 @@ impl Tree { 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(), @@ -1443,7 +1511,7 @@ fn main() -> void { let a: u32 = 0; a == global } -let global: u32 = 42; +const global: u32 = 42; "; let tokens = Tokenizer::new(src.as_bytes()).unwrap(); diff --git a/src/triples.rs b/src/triples.rs index f793a58..02152e2 100644 --- a/src/triples.rs +++ b/src/triples.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::collections::HashMap; +use std::collections::{hash_map::Entry, HashMap}; use crate::{ ast::{FloatingType, IntegralType, Node as AstNode, Tag, Type}, @@ -10,10 +10,17 @@ use crate::{ type Node = u32; +enum NodeOrList { + Node(Node), // node of alloca location + List(Vec), // list of references to `Node(_)` +} + enum Inst { Label(String), Constant(Value), - Parameter, + UnresolvedRef, + Ref(Node), + Parameter { size: u32, align: u32 }, Add { lhs: Node, rhs: Node }, Sub { lhs: Node, rhs: Node }, Div { lhs: Node, rhs: Node }, @@ -53,7 +60,7 @@ struct IRBuilder<'tree, 'ir> { ir: &'ir mut IR, tree: &'tree mut Tree, type_map: HashMap, - lookup: HashMap, + lookup: HashMap, } impl<'tree, 'ir> IRBuilder<'tree, 'ir> { @@ -66,6 +73,27 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { } } + fn patch_unresolved(&mut self, node: AstNode, resolved: Node) { + match self.lookup.entry(node) { + Entry::Occupied(mut o) => { + match o.get_mut() { + NodeOrList::Node(_) => { + panic!("there shouldn't be a node here.") + } + NodeOrList::List(refs) => { + for &r in refs.iter() { + self.ir.nodes[r as usize] = Inst::Ref(resolved); + } + } + } + o.insert(NodeOrList::Node(resolved)); + } + Entry::Vacant(v) => { + v.insert(NodeOrList::Node(resolved)); + } + } + } + fn visit(&mut self, node: AstNode) -> Node { match &self.tree.nodes[node].clone() { Tag::FunctionDecl { proto, body } => { @@ -92,13 +120,12 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { Tag::FunctionProto { parameters, name, .. } => { - parameters.map(|p| self.visit(p)); - let label = self.ir.push(Inst::Label( self.tree.nodes.get_ident_str(*name).unwrap().to_string(), )); + parameters.map(|p| self.visit(p)); - self.lookup.insert(node, label); + self.patch_unresolved(node, label); label } @@ -108,10 +135,14 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { } !0 } - Tag::Parameter { .. } => { - let param = self.ir.push(Inst::Parameter); + Tag::Parameter { name, ty } => { + let ty = self.tree.type_of_node(*ty); + let param = self.ir.push(Inst::Parameter { + size: ty.size_of(), + align: ty.align_of(), + }); - self.lookup.insert(node, param); + self.lookup.insert(node, NodeOrList::Node(param)); param } Tag::Block { @@ -134,7 +165,19 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { size: ty.size_of(), align: ty.align_of(), }); - self.lookup.insert(node, alloca); + self.patch_unresolved(node, alloca); + alloca + } + Tag::GlobalDecl { name, .. } => { + let ty = self.tree.type_of_node(node); + let _label = self.ir.push(Inst::Label( + self.tree.nodes.get_ident_str(*name).unwrap().to_string(), + )); + let alloca = self.ir.push(Inst::Alloc { + size: ty.size_of(), + align: ty.align_of(), + }); + self.patch_unresolved(node, alloca); alloca } Tag::ReturnStmt { expr } => { @@ -257,7 +300,20 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { let lhs = self.visit(*lhs); self.ir.push(Inst::Negate { lhs }) } - Tag::DeclRef(decl) => *self.lookup.get(decl).expect("declref not in lookup map"), + Tag::DeclRef(decl) => match self.lookup.get_mut(decl) { + Some(NodeOrList::Node(decl)) => *decl, + Some(NodeOrList::List(refs)) => { + let unresolved = self.ir.push(Inst::UnresolvedRef); + refs.push(unresolved); + unresolved + } + None => { + let unresolved = self.ir.push(Inst::UnresolvedRef); + self.lookup + .insert(*decl, NodeOrList::List(vec![unresolved])); + unresolved + } + }, Tag::Ref { lhs } => { let lhs = self.visit(*lhs); self.ir.push(Inst::AddressOf(lhs)) @@ -294,12 +350,17 @@ impl IR { node } - pub fn build(&mut self, tree: &mut Tree, ast_node: crate::ast::Node) { + pub fn build(&mut self, tree: &mut Tree) { + let global_decls = tree.global_decls.clone(); let mut builder = IRBuilder::new(self, tree); - builder.visit(ast_node); + for node in &global_decls { + builder.visit(*node); + } } +} +impl IR { fn render_node( &self, w: &mut W, @@ -310,8 +371,21 @@ impl IR { Inst::Label(label) => { writeln_indented!(indent - 1, w, "%{} = {label}:", node)?; } - Inst::Parameter => { - writeln_indented!(indent, w, "%{} = Param", node)?; + Inst::UnresolvedRef => { + writeln_indented!(indent, w, "%{} = unresolved reference", node)?; + } + Inst::Ref(reference) => { + writeln_indented!(indent, w, "%{} = reference(%{})", node, reference)?; + } + Inst::Parameter { size, align } => { + writeln_indented!( + indent, + w, + "%{} = Param(size: {}, align: {})", + node, + size, + align + )?; } Inst::Constant(value) => { writeln_indented!(indent, w, "%{} = {}", node, value)?; @@ -350,7 +424,7 @@ impl IR { writeln_indented!(indent, w, "%{} = return", node)?; } Inst::Alloc { size, align } => { - writeln_indented!(indent, w, "%{} = alloca {size} (algin: {align})", node)?; + writeln_indented!(indent, w, "%{} = alloca {size} (align: {align})", node)?; } Inst::AddressOf(val) => { writeln_indented!(indent, w, "%{} = addr %{val}", node)?; @@ -383,11 +457,16 @@ mod tests { fn ir() { let src = " fn main() -> u32 { -let a: u32 = 0 + 3; -let ptr_a = &a; -return *ptr_a * global; + let a: u32 = 0 + 3; + let ptr_a = &a; + return *ptr_a * global; } -let global: u32 = 42; + +fn square(x: u32) -> u32 { + x * x +} + +const global: u32 = 42; "; let tokens = Tokenizer::new(src.as_bytes()).unwrap(); @@ -399,8 +478,7 @@ let global: u32 = 42; println!("{buf}"); let mut ir = IR::new(); - let decl = *tree.global_decls.first().unwrap(); - ir.build(&mut tree, decl); + ir.build(&mut tree); let mut buf = String::new(); ir.render(&mut buf).unwrap(); println!("{buf}");