changed globaldecl to only allow const instead of let or var as keyword
This commit is contained in:
parent
efff2446bc
commit
2689179ed4
|
@ -69,6 +69,13 @@ pub enum Tag {
|
||||||
explicit_type: Option<Node>,
|
explicit_type: Option<Node>,
|
||||||
assignment: Option<Node>,
|
assignment: Option<Node>,
|
||||||
},
|
},
|
||||||
|
GlobalDecl {
|
||||||
|
/// Ident
|
||||||
|
name: Node,
|
||||||
|
/// TypeName
|
||||||
|
explicit_type: Option<Node>,
|
||||||
|
assignment: Node,
|
||||||
|
},
|
||||||
DeclRef(Node),
|
DeclRef(Node),
|
||||||
CallExpr {
|
CallExpr {
|
||||||
/// Ident | Expr
|
/// Ident | Expr
|
||||||
|
|
102
src/parser.rs
102
src/parser.rs
|
@ -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
|
let let_or_var = match tokens
|
||||||
.eat_token(Token::Let)
|
.eat_token(Token::Let)
|
||||||
.or_else(|| tokens.eat_token(Token::Var))
|
.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 name_str = self.nodes.get_ident_str(name).unwrap().to_owned();
|
||||||
let node = if global {
|
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
|
|
||||||
} else {
|
|
||||||
let node = self.nodes.reserve_node();
|
let node = self.nodes.reserve_node();
|
||||||
self.st.insert_symbol(&name_str, node, SymbolKind::Var);
|
self.st.insert_symbol(&name_str, node, SymbolKind::Var);
|
||||||
node
|
node
|
||||||
|
@ -357,11 +348,53 @@ impl Tree {
|
||||||
Ok(assignment.unwrap_or(node))
|
Ok(assignment.unwrap_or(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GLOBAL_DECL <-
|
||||||
|
/// const IDENTIFIER (: TYPENAME)? = EXPR;
|
||||||
pub fn parse_global_decl(&mut self, tokens: &mut TokenIterator) -> Result<Node> {
|
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)?;
|
tokens.expect_token(Token::Semi)?;
|
||||||
|
|
||||||
Ok(node)
|
Ok(assignment)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PARAMETER <-
|
/// PARAMETER <-
|
||||||
|
@ -499,7 +532,7 @@ impl Tree {
|
||||||
stmts.push(self.try_parse_return_stmt(tokens)?.unwrap());
|
stmts.push(self.try_parse_return_stmt(tokens)?.unwrap());
|
||||||
}
|
}
|
||||||
Token::Var | Token::Let => {
|
Token::Var | Token::Let => {
|
||||||
let node = self.parse_var_decl(tokens, false)?;
|
let node = self.parse_var_decl(tokens)?;
|
||||||
tokens.expect_token(Token::Semi)?;
|
tokens.expect_token(Token::Semi)?;
|
||||||
|
|
||||||
stmts.push(node);
|
stmts.push(node);
|
||||||
|
@ -608,7 +641,7 @@ impl Tree {
|
||||||
match tokens.peek_token_or_err()?.token() {
|
match tokens.peek_token_or_err()?.token() {
|
||||||
Token::Return => Ok(self.try_parse_return_stmt(tokens)?.unwrap()),
|
Token::Return => Ok(self.try_parse_return_stmt(tokens)?.unwrap()),
|
||||||
Token::Var | Token::Let => {
|
Token::Var | Token::Let => {
|
||||||
let node = self.parse_var_decl(tokens, false)?;
|
let node = self.parse_var_decl(tokens)?;
|
||||||
tokens.expect_token(Token::Semi)?;
|
tokens.expect_token(Token::Semi)?;
|
||||||
|
|
||||||
Ok(node)
|
Ok(node)
|
||||||
|
@ -816,7 +849,7 @@ impl Tree {
|
||||||
};
|
};
|
||||||
|
|
||||||
let decl = match token {
|
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)?,
|
Token::Fn => self.parse_fn_decl(tokens)?,
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("unexpected token: {}", token);
|
eprintln!("unexpected token: {}", token);
|
||||||
|
@ -994,6 +1027,26 @@ impl Tree {
|
||||||
writeln!(writer, ");")?;
|
writeln!(writer, ");")?;
|
||||||
Ok(())
|
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::CallExpr { .. } => todo!(),
|
||||||
Tag::ArgumentList { .. } => todo!(),
|
Tag::ArgumentList { .. } => todo!(),
|
||||||
Tag::Argument { .. } => todo!(),
|
Tag::Argument { .. } => todo!(),
|
||||||
|
@ -1344,6 +1397,21 @@ impl Tree {
|
||||||
lhs.or(rhs)
|
lhs.or(rhs)
|
||||||
.expect("Type could not be automatically deduced.")
|
.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::CallExpr { lhs, .. } => self.type_of_node(*lhs),
|
||||||
Tag::ExplicitCast { typename, .. } => self.type_of_node(*typename),
|
Tag::ExplicitCast { typename, .. } => self.type_of_node(*typename),
|
||||||
Tag::Deref { lhs } => self.type_of_node(*lhs).remove_ptr().unwrap(),
|
Tag::Deref { lhs } => self.type_of_node(*lhs).remove_ptr().unwrap(),
|
||||||
|
@ -1443,7 +1511,7 @@ fn main() -> void {
|
||||||
let a: u32 = 0;
|
let a: u32 = 0;
|
||||||
a == global
|
a == global
|
||||||
}
|
}
|
||||||
let global: u32 = 42;
|
const global: u32 = 42;
|
||||||
";
|
";
|
||||||
let tokens = Tokenizer::new(src.as_bytes()).unwrap();
|
let tokens = Tokenizer::new(src.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
|
122
src/triples.rs
122
src/triples.rs
|
@ -1,6 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{FloatingType, IntegralType, Node as AstNode, Tag, Type},
|
ast::{FloatingType, IntegralType, Node as AstNode, Tag, Type},
|
||||||
|
@ -10,10 +10,17 @@ use crate::{
|
||||||
|
|
||||||
type Node = u32;
|
type Node = u32;
|
||||||
|
|
||||||
|
enum NodeOrList {
|
||||||
|
Node(Node), // node of alloca location
|
||||||
|
List(Vec<Node>), // list of references to `Node(_)`
|
||||||
|
}
|
||||||
|
|
||||||
enum Inst {
|
enum Inst {
|
||||||
Label(String),
|
Label(String),
|
||||||
Constant(Value),
|
Constant(Value),
|
||||||
Parameter,
|
UnresolvedRef,
|
||||||
|
Ref(Node),
|
||||||
|
Parameter { size: u32, align: u32 },
|
||||||
Add { lhs: Node, rhs: Node },
|
Add { lhs: Node, rhs: Node },
|
||||||
Sub { lhs: Node, rhs: Node },
|
Sub { lhs: Node, rhs: Node },
|
||||||
Div { lhs: Node, rhs: Node },
|
Div { lhs: Node, rhs: Node },
|
||||||
|
@ -53,7 +60,7 @@ struct IRBuilder<'tree, 'ir> {
|
||||||
ir: &'ir mut IR,
|
ir: &'ir mut IR,
|
||||||
tree: &'tree mut Tree,
|
tree: &'tree mut Tree,
|
||||||
type_map: HashMap<AstNode, Type>,
|
type_map: HashMap<AstNode, Type>,
|
||||||
lookup: HashMap<AstNode, Node>,
|
lookup: HashMap<AstNode, NodeOrList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
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 {
|
fn visit(&mut self, node: AstNode) -> Node {
|
||||||
match &self.tree.nodes[node].clone() {
|
match &self.tree.nodes[node].clone() {
|
||||||
Tag::FunctionDecl { proto, body } => {
|
Tag::FunctionDecl { proto, body } => {
|
||||||
|
@ -92,13 +120,12 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
||||||
Tag::FunctionProto {
|
Tag::FunctionProto {
|
||||||
parameters, name, ..
|
parameters, name, ..
|
||||||
} => {
|
} => {
|
||||||
parameters.map(|p| self.visit(p));
|
|
||||||
|
|
||||||
let label = self.ir.push(Inst::Label(
|
let label = self.ir.push(Inst::Label(
|
||||||
self.tree.nodes.get_ident_str(*name).unwrap().to_string(),
|
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
|
label
|
||||||
}
|
}
|
||||||
|
@ -108,10 +135,14 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
||||||
}
|
}
|
||||||
!0
|
!0
|
||||||
}
|
}
|
||||||
Tag::Parameter { .. } => {
|
Tag::Parameter { name, ty } => {
|
||||||
let param = self.ir.push(Inst::Parameter);
|
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
|
param
|
||||||
}
|
}
|
||||||
Tag::Block {
|
Tag::Block {
|
||||||
|
@ -134,7 +165,19 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
||||||
size: ty.size_of(),
|
size: ty.size_of(),
|
||||||
align: ty.align_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
|
alloca
|
||||||
}
|
}
|
||||||
Tag::ReturnStmt { expr } => {
|
Tag::ReturnStmt { expr } => {
|
||||||
|
@ -257,7 +300,20 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
||||||
let lhs = self.visit(*lhs);
|
let lhs = self.visit(*lhs);
|
||||||
self.ir.push(Inst::Negate { 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 } => {
|
Tag::Ref { lhs } => {
|
||||||
let lhs = self.visit(*lhs);
|
let lhs = self.visit(*lhs);
|
||||||
self.ir.push(Inst::AddressOf(lhs))
|
self.ir.push(Inst::AddressOf(lhs))
|
||||||
|
@ -294,12 +350,17 @@ impl IR {
|
||||||
node
|
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);
|
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>(
|
fn render_node<W: core::fmt::Write>(
|
||||||
&self,
|
&self,
|
||||||
w: &mut W,
|
w: &mut W,
|
||||||
|
@ -310,8 +371,21 @@ impl IR {
|
||||||
Inst::Label(label) => {
|
Inst::Label(label) => {
|
||||||
writeln_indented!(indent - 1, w, "%{} = {label}:", node)?;
|
writeln_indented!(indent - 1, w, "%{} = {label}:", node)?;
|
||||||
}
|
}
|
||||||
Inst::Parameter => {
|
Inst::UnresolvedRef => {
|
||||||
writeln_indented!(indent, w, "%{} = Param", node)?;
|
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) => {
|
Inst::Constant(value) => {
|
||||||
writeln_indented!(indent, w, "%{} = {}", node, value)?;
|
writeln_indented!(indent, w, "%{} = {}", node, value)?;
|
||||||
|
@ -350,7 +424,7 @@ impl IR {
|
||||||
writeln_indented!(indent, w, "%{} = return", node)?;
|
writeln_indented!(indent, w, "%{} = return", node)?;
|
||||||
}
|
}
|
||||||
Inst::Alloc { size, align } => {
|
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) => {
|
Inst::AddressOf(val) => {
|
||||||
writeln_indented!(indent, w, "%{} = addr %{val}", node)?;
|
writeln_indented!(indent, w, "%{} = addr %{val}", node)?;
|
||||||
|
@ -383,11 +457,16 @@ mod tests {
|
||||||
fn ir() {
|
fn ir() {
|
||||||
let src = "
|
let src = "
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
let a: u32 = 0 + 3;
|
let a: u32 = 0 + 3;
|
||||||
let ptr_a = &a;
|
let ptr_a = &a;
|
||||||
return *ptr_a * global;
|
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();
|
let tokens = Tokenizer::new(src.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
@ -399,8 +478,7 @@ let global: u32 = 42;
|
||||||
println!("{buf}");
|
println!("{buf}");
|
||||||
|
|
||||||
let mut ir = IR::new();
|
let mut ir = IR::new();
|
||||||
let decl = *tree.global_decls.first().unwrap();
|
ir.build(&mut tree);
|
||||||
ir.build(&mut tree, decl);
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
ir.render(&mut buf).unwrap();
|
ir.render(&mut buf).unwrap();
|
||||||
println!("{buf}");
|
println!("{buf}");
|
||||||
|
|
Loading…
Reference in a new issue