visitor pattern for ast
This commit is contained in:
parent
13df06421c
commit
4e59e02178
|
@ -379,7 +379,7 @@ pub struct Index(u32);
|
|||
|
||||
impl Display for Index {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "#{}", self.index())
|
||||
write!(f, "${}", self.index())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
246
src/ast2/mod.rs
246
src/ast2/mod.rs
|
@ -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> {
|
||||
ast: &'a Ast,
|
||||
#[allow(dead_code)]
|
||||
|
@ -2357,41 +2490,17 @@ pub mod ast_gen {
|
|||
}
|
||||
|
||||
pub fn intern_types(&mut self) {
|
||||
let mut nodes = self
|
||||
.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()];
|
||||
self.ast.visitor_mut().visit(|ast, i, tag, data| {
|
||||
match tag {
|
||||
Tag::ArrayType => {
|
||||
let (length, pointee) = data.as_two_indices();
|
||||
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 });
|
||||
|
||||
// get interened value from constant node
|
||||
let length = {
|
||||
let value = self.ast.datas[length.index()]
|
||||
let value = ast.datas[length.index()]
|
||||
.as_index_intern()
|
||||
.1;
|
||||
|
||||
|
@ -2424,48 +2533,48 @@ pub mod ast_gen {
|
|||
Some(flags),
|
||||
length,
|
||||
);
|
||||
self.ast.tags[i.index()] = Tag::InternedType;
|
||||
self.ast.datas[i.index()] = Data::intern(ty);
|
||||
ast.tags[i.index()] = Tag::InternedType;
|
||||
ast.datas[i.index()] = Data::intern(ty);
|
||||
}
|
||||
Tag::PointerType => {
|
||||
let (pointee, flags) =
|
||||
data.as_index_and_extra_offset();
|
||||
let pointee =
|
||||
self.ast.datas[pointee.index()].as_intern();
|
||||
ast.datas[pointee.index()].as_intern();
|
||||
let ty = self.intern.get_pointer_type(
|
||||
pointee,
|
||||
Some(PointerFlags::unpack(flags as u8)),
|
||||
);
|
||||
self.ast.tags[i.index()] = Tag::InternedType;
|
||||
self.ast.datas[i.index()] = Data::intern(ty);
|
||||
ast.tags[i.index()] = Tag::InternedType;
|
||||
ast.datas[i.index()] = Data::intern(ty);
|
||||
}
|
||||
Tag::TypeDeclRef => {
|
||||
let decl = data.as_index();
|
||||
let (name, _) = self.ast.datas[decl.index()]
|
||||
let (name, _) = ast.datas[decl.index()]
|
||||
.as_intern_and_extra_offset();
|
||||
|
||||
let ty =
|
||||
self.intern.get_struct_type(name, decl);
|
||||
self.ast.tags[i.index()] = Tag::InternedType;
|
||||
self.ast.datas[i.index()] = Data::intern(ty);
|
||||
ast.tags[i.index()] = Tag::InternedType;
|
||||
ast.datas[i.index()] = Data::intern(ty);
|
||||
}
|
||||
Tag::FunctionProto => {
|
||||
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,
|
||||
&mut TypeCache::new(),
|
||||
Index::new(self.ast.extra[i]),
|
||||
Index::new(ast.extra[i]),
|
||||
);
|
||||
let parameters = {
|
||||
let (a, b) = self.ast.datas
|
||||
[self.ast.extra[i + 1] as usize]
|
||||
let (a, b) = ast.datas
|
||||
[ast.extra[i + 1] as usize]
|
||||
.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)
|
||||
let ty = self.ast.datas[i as usize]
|
||||
let ty = ast.datas[i as usize]
|
||||
.as_index_intern()
|
||||
.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) =
|
||||
data.as_intern_and_extra_offset();
|
||||
let flags =
|
||||
StructFlags::unpack(self.ast.extra[offset]);
|
||||
StructFlags::unpack(ast.extra[offset]);
|
||||
|
||||
let types = (offset + 1)
|
||||
..(offset + 1 + flags.num_fields as usize);
|
||||
|
@ -2486,13 +2595,13 @@ pub mod ast_gen {
|
|||
+ 1
|
||||
+ flags.num_fields as usize * 2);
|
||||
|
||||
let types = self.ast.extra[types]
|
||||
let types = ast.extra[types]
|
||||
.iter()
|
||||
.map(|&i| Index::new(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()
|
||||
.map(|&i| intern::Index::from_u32(i));
|
||||
|
||||
|
@ -2506,65 +2615,40 @@ pub mod ast_gen {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn resolve_decl_refs(&mut self) {
|
||||
let mut nodes =
|
||||
self.ast.get_root_file_indices().collect::<Vec<_>>();
|
||||
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();
|
||||
}
|
||||
self.ast.visitor_rev_mut().visit(|ast, node, tag, _data| {
|
||||
match tag {
|
||||
Tag::TypeDeclRefUnresolved => {
|
||||
let (scope, name) =
|
||||
self.ast.datas[node.index()].as_index_intern();
|
||||
ast.datas[node.index()].as_index_intern();
|
||||
// look in my_scope
|
||||
if let Some(decl) = self.syms.find_type_symbol(
|
||||
scope,
|
||||
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 => {
|
||||
let (scope, name) =
|
||||
self.ast.datas[node.index()].as_index_intern();
|
||||
ast.datas[node.index()].as_index_intern();
|
||||
|
||||
// look in my_scope
|
||||
if let Some(decl) = self.syms.find_symbol(
|
||||
scope,
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue