visitor pattern for ast

This commit is contained in:
Janis 2024-12-26 00:40:11 +01:00
parent 13df06421c
commit 4e59e02178
2 changed files with 166 additions and 82 deletions

View file

@ -379,7 +379,7 @@ pub struct Index(u32);
impl Display for Index { impl Display for Index {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#{}", self.index()) write!(f, "${}", self.index())
} }
} }

View file

@ -2086,6 +2086,139 @@ pub fn interned_type_and_value_to_comptime_number(
} }
} }
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<Index>;
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data);
}
impl AstExt for &Ast {
fn get_node_children(&self, node: Index) -> Vec<Index> {
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<Index> {
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<AstT> {
pub(super) ast: AstT,
pub(super) scopes: Vec<Index>,
pub(super) nodes: Vec<A>,
pub(super) rev: bool,
}
impl<AstT> AstVisitor<AstT>
where
AstT: AstExt,
{
pub fn visit<F: FnMut(&mut AstT, Index, Tag, Data)>(
&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::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, i, tag, data);
match tag {
Tag::File
| Tag::FunctionDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.pop();
}
_ => {}
}
}
}
}
}
}
pub enum A {
PushChildren(Index),
PopSelf(Index),
}
}
pub struct AstRenderer<'a> { pub struct AstRenderer<'a> {
ast: &'a Ast, ast: &'a Ast,
#[allow(dead_code)] #[allow(dead_code)]
@ -2357,41 +2490,17 @@ pub mod ast_gen {
} }
pub fn intern_types(&mut self) { pub fn intern_types(&mut self) {
let mut nodes = self self.ast.visitor_mut().visit(|ast, i, tag, data| {
.ast
.get_root_file_indices()
.map(|i| A::PushChildren(i))
.collect::<Vec<_>>();
enum A {
PushChildren(Index),
PopSelf(Index),
}
while let Some(node) = nodes.pop() {
match node {
A::PushChildren(i) => {
nodes.push(A::PopSelf(i));
nodes.extend(
self.ast
.get_node_children(i)
.into_iter()
.map(|i| A::PushChildren(i)),
);
}
A::PopSelf(i) => {
let tag = self.ast.tags[i.index()];
let data = self.ast.datas[i.index()];
match tag { match tag {
Tag::ArrayType => { Tag::ArrayType => {
let (length, pointee) = data.as_two_indices(); let (length, pointee) = data.as_two_indices();
let pointee = let pointee =
self.ast.datas[pointee.index()].as_intern(); ast.datas[pointee.index()].as_intern();
variant!( self.intern.get_key(pointee) => intern::Key::PointerType { pointee, flags }); variant!( self.intern.get_key(pointee) => intern::Key::PointerType { pointee, flags });
// get interened value from constant node // get interened value from constant node
let length = { let length = {
let value = self.ast.datas[length.index()] let value = ast.datas[length.index()]
.as_index_intern() .as_index_intern()
.1; .1;
@ -2424,48 +2533,48 @@ pub mod ast_gen {
Some(flags), Some(flags),
length, length,
); );
self.ast.tags[i.index()] = Tag::InternedType; ast.tags[i.index()] = Tag::InternedType;
self.ast.datas[i.index()] = Data::intern(ty); ast.datas[i.index()] = Data::intern(ty);
} }
Tag::PointerType => { Tag::PointerType => {
let (pointee, flags) = let (pointee, flags) =
data.as_index_and_extra_offset(); data.as_index_and_extra_offset();
let pointee = let pointee =
self.ast.datas[pointee.index()].as_intern(); ast.datas[pointee.index()].as_intern();
let ty = self.intern.get_pointer_type( let ty = self.intern.get_pointer_type(
pointee, pointee,
Some(PointerFlags::unpack(flags as u8)), Some(PointerFlags::unpack(flags as u8)),
); );
self.ast.tags[i.index()] = Tag::InternedType; ast.tags[i.index()] = Tag::InternedType;
self.ast.datas[i.index()] = Data::intern(ty); ast.datas[i.index()] = Data::intern(ty);
} }
Tag::TypeDeclRef => { Tag::TypeDeclRef => {
let decl = data.as_index(); let decl = data.as_index();
let (name, _) = self.ast.datas[decl.index()] let (name, _) = ast.datas[decl.index()]
.as_intern_and_extra_offset(); .as_intern_and_extra_offset();
let ty = let ty =
self.intern.get_struct_type(name, decl); self.intern.get_struct_type(name, decl);
self.ast.tags[i.index()] = Tag::InternedType; ast.tags[i.index()] = Tag::InternedType;
self.ast.datas[i.index()] = Data::intern(ty); ast.datas[i.index()] = Data::intern(ty);
} }
Tag::FunctionProto => { Tag::FunctionProto => {
let (_, i) = data.as_intern_and_extra_offset(); let (_, i) = data.as_intern_and_extra_offset();
let return_type = self.ast.get_type_of_node( let return_type = ast.get_type_of_node(
&self.intern, &self.intern,
&mut TypeCache::new(), &mut TypeCache::new(),
Index::new(self.ast.extra[i]), Index::new(ast.extra[i]),
); );
let parameters = { let parameters = {
let (a, b) = self.ast.datas let (a, b) = ast.datas
[self.ast.extra[i + 1] as usize] [ast.extra[i + 1] as usize]
.as_extra_range(); .as_extra_range();
self.ast.extra[a..b].iter().map(|&i| { ast.extra[a..b].iter().map(|&i| {
// i is index to a parameter, a parameter is (index, intern) // i is index to a parameter, a parameter is (index, intern)
let ty = self.ast.datas[i as usize] let ty = ast.datas[i as usize]
.as_index_intern() .as_index_intern()
.0; .0;
self.ast.datas[ty.index()].as_intern() ast.datas[ty.index()].as_intern()
}) })
}; };
@ -2476,7 +2585,7 @@ pub mod ast_gen {
let (name, offset) = let (name, offset) =
data.as_intern_and_extra_offset(); data.as_intern_and_extra_offset();
let flags = let flags =
StructFlags::unpack(self.ast.extra[offset]); StructFlags::unpack(ast.extra[offset]);
let types = (offset + 1) let types = (offset + 1)
..(offset + 1 + flags.num_fields as usize); ..(offset + 1 + flags.num_fields as usize);
@ -2486,13 +2595,13 @@ pub mod ast_gen {
+ 1 + 1
+ flags.num_fields as usize * 2); + flags.num_fields as usize * 2);
let types = self.ast.extra[types] let types = ast.extra[types]
.iter() .iter()
.map(|&i| Index::new(i)) .map(|&i| Index::new(i))
.map(|i| { .map(|i| {
self.ast.datas[i.index()].as_intern() ast.datas[i.index()].as_intern()
}); });
let names = self.ast.extra[names] let names = ast.extra[names]
.iter() .iter()
.map(|&i| intern::Index::from_u32(i)); .map(|&i| intern::Index::from_u32(i));
@ -2506,65 +2615,40 @@ pub mod ast_gen {
} }
_ => {} _ => {}
} }
} });
}
}
} }
pub fn resolve_decl_refs(&mut self) { pub fn resolve_decl_refs(&mut self) {
let mut nodes = self.ast.visitor_rev_mut().visit(|ast, node, tag, _data| {
self.ast.get_root_file_indices().collect::<Vec<_>>(); match tag {
let mut scopes = Vec::new();
while let Some(node) = nodes.pop() {
match self.ast.tags[node.index()] {
Tag::File
| Tag::FunctionDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
scopes.push(node);
}
_ => {}
}
let children = self.ast.get_node_children(node);
nodes.extend(children.into_iter().rev());
match self.ast.tags[node.index()] {
Tag::File
| Tag::FunctionDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
scopes.pop();
}
Tag::TypeDeclRefUnresolved => { Tag::TypeDeclRefUnresolved => {
let (scope, name) = let (scope, name) =
self.ast.datas[node.index()].as_index_intern(); ast.datas[node.index()].as_index_intern();
// look in my_scope // look in my_scope
if let Some(decl) = self.syms.find_type_symbol( if let Some(decl) = self.syms.find_type_symbol(
scope, scope,
name, name,
self.ast.source_locs[node.index()], ast.source_locs[node.index()],
) { ) {
self.ast.resolve_type_ref(node, decl) ast.resolve_type_ref(node, decl)
}; };
} }
Tag::DeclRefUnresolved => { Tag::DeclRefUnresolved => {
let (scope, name) = let (scope, name) =
self.ast.datas[node.index()].as_index_intern(); ast.datas[node.index()].as_index_intern();
// look in my_scope // look in my_scope
if let Some(decl) = self.syms.find_symbol( if let Some(decl) = self.syms.find_symbol(
scope, scope,
name, name,
self.ast.source_locs[node.index()], ast.source_locs[node.index()],
) { ) {
self.ast.resolve_decl_ref(node, decl) ast.resolve_decl_ref(node, decl)
}; };
} }
_ => {} _ => {}
} }
} });
} }
fn current_scope(&self) -> Index { fn current_scope(&self) -> Index {