changed globaldecl to only allow const instead of let or var as keyword

This commit is contained in:
Janis 2024-08-14 17:55:03 +02:00
parent efff2446bc
commit 2689179ed4
3 changed files with 192 additions and 39 deletions

View file

@ -69,6 +69,13 @@ pub enum Tag {
explicit_type: Option<Node>,
assignment: Option<Node>,
},
GlobalDecl {
/// Ident
name: Node,
/// TypeName
explicit_type: Option<Node>,
assignment: Node,
},
DeclRef(Node),
CallExpr {
/// Ident | Expr

View file

@ -297,7 +297,7 @@ impl Tree {
}
}
pub fn parse_var_decl(&mut self, tokens: &mut TokenIterator, global: bool) -> Result<Node> {
pub fn parse_var_decl(&mut self, tokens: &mut TokenIterator) -> Result<Node> {
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<Node> {
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();

View file

@ -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<Node>), // 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<AstNode, Type>,
lookup: HashMap<AstNode, Node>,
lookup: HashMap<AstNode, NodeOrList>,
}
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<W: core::fmt::Write>(
&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}");