Compare commits

..

4 Commits

Author SHA1 Message Date
Jesse Brault
b5c0e44eeb Bunch of work on name analysis. Reintroduce Rc<RefCell<_>> for symbols. 2025-10-20 20:55:29 -05:00
Jesse Brault
273d197841 New phases for name analysis. 2025-10-20 19:20:43 -05:00
Jesse Brault
af8f0b5dac Various new ideas for name analysis. 2025-10-20 18:31:54 -05:00
Jesse Brault
d32580a1d4 Remove scope table usage. 2025-10-20 13:24:37 -05:00
23 changed files with 984 additions and 610 deletions

View File

@ -1,5 +1,5 @@
use convert_case::{Case, Casing};
use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec}; use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec};
use convert_case::{Case, Casing};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -10,20 +10,19 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
.map(|rule| { .map(|rule| {
let rule_ident = format_ident!("{}", rule.rule()); let rule_ident = format_ident!("{}", rule.rule());
match rule.child() { match rule.child() {
Some(child) => { Some(child) => match child.kind() {
match child.kind() { EnumRuleChildKind::Node(node_child) => {
EnumRuleChildKind::Node(node_child) => { let child_ident =
let child_ident = format_ident!("{}", node_child.node_kind().to_case(Case::Snake)); format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
quote! { quote! {
#type_ident::#rule_ident(#child_ident) => vec![ #type_ident::#rule_ident(#child_ident) => vec![
#child_ident #child_ident
] ]
}
}
_ => quote! {
#type_ident::#rule_ident(_) => vec![]
} }
} }
_ => quote! {
#type_ident::#rule_ident(_) => vec![]
},
}, },
None => { None => {
quote! { quote! {
@ -33,7 +32,35 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut_match_arms = enum_spec
.rules()
.map(|rule| {
let rule_ident = format_ident!("{}", rule.rule());
match rule.child() {
Some(child) => match child.kind() {
EnumRuleChildKind::Node(node_child) => {
let child_ident =
format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
quote! {
#type_ident::#rule_ident(#child_ident) => {
f(#child_ident as &'a mut dyn AstNode<'a>)
}
}
}
_ => quote! {
#type_ident::#rule_ident(_) => {}
},
},
None => {
quote! {
#type_ident::#rule_ident => {}
}
}
}
})
.collect::<Vec<_>>();
quote! { quote! {
impl<'a> AstNode<'a> for #type_ident { impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> { fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
@ -42,9 +69,19 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
} }
} }
fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {
match self {
#(#mut_match_arms,)*
}
}
fn as_node_ref(&'a self) -> AstNodeRef<'a> { fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -10,9 +10,15 @@ pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
vec![] vec![]
} }
fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {}
fn as_node_ref(&'a self) -> AstNodeRef<'a> { fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -10,9 +10,15 @@ pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream
vec![] vec![]
} }
fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {}
fn as_node_ref(&'a self) -> AstNodeRef<'a> { fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -1,63 +1,47 @@
mod enum_ast_node; mod enum_ast_node;
mod leaf_enum_ast_node; mod leaf_enum_ast_node;
mod struct_ast_node;
mod leaf_struct_ast_node; mod leaf_struct_ast_node;
mod polymorphic_type_ast_node;
mod polymorphic_enum_loop_ast_node; mod polymorphic_enum_loop_ast_node;
mod polymorphic_type_ast_node;
mod struct_ast_node;
use crate::spec::BuildSpec;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::ast_node::enum_ast_node::make_enum_ast_node_impl; use crate::ast_node::enum_ast_node::make_enum_ast_node_impl;
use crate::ast_node::leaf_enum_ast_node::make_leaf_enum_ast_node_impl; use crate::ast_node::leaf_enum_ast_node::make_leaf_enum_ast_node_impl;
use crate::ast_node::leaf_struct_ast_node::make_leaf_struct_ast_node_impl; use crate::ast_node::leaf_struct_ast_node::make_leaf_struct_ast_node_impl;
use crate::ast_node::polymorphic_enum_loop_ast_node::make_polymorphic_enum_loop_ast_node_impl; use crate::ast_node::polymorphic_enum_loop_ast_node::make_polymorphic_enum_loop_ast_node_impl;
use crate::ast_node::polymorphic_type_ast_node::make_polymorphic_type_ast_node_impl; use crate::ast_node::polymorphic_type_ast_node::make_polymorphic_type_ast_node_impl;
use crate::ast_node::struct_ast_node::make_struct_ast_node_impl; use crate::ast_node::struct_ast_node::make_struct_ast_node_impl;
use crate::spec::BuildSpec;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
pub fn make_ast_node_impl(build_spec: &BuildSpec) -> Option<TokenStream> { pub fn make_ast_node_impl(build_spec: &BuildSpec) -> Option<TokenStream> {
match build_spec { match build_spec {
BuildSpec::Enum(enum_spec) => { BuildSpec::Enum(enum_spec) => Some(make_enum_ast_node_impl(enum_spec)),
Some(make_enum_ast_node_impl(enum_spec)) BuildSpec::LeafEnum(leaf_enum) => Some(make_leaf_enum_ast_node_impl(leaf_enum)),
} BuildSpec::Struct(struct_spec) => Some(make_struct_ast_node_impl(struct_spec)),
BuildSpec::LeafEnum(leaf_enum) => { BuildSpec::LeafStruct(leaf_struct) => Some(make_leaf_struct_ast_node_impl(leaf_struct)),
Some(make_leaf_enum_ast_node_impl(leaf_enum))
}
BuildSpec::Struct(struct_spec) => {
Some(make_struct_ast_node_impl(struct_spec))
}
BuildSpec::LeafStruct(leaf_struct) => {
Some(make_leaf_struct_ast_node_impl(leaf_struct))
}
BuildSpec::Production(_) => None, BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None, BuildSpec::NodeProduction(_) => None,
BuildSpec::PolymorphicType(polymorphic_type) => { BuildSpec::PolymorphicType(polymorphic_type) => {
Some(make_polymorphic_type_ast_node_impl(polymorphic_type)) Some(make_polymorphic_type_ast_node_impl(polymorphic_type))
} }
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => { BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => Some(
Some(make_polymorphic_enum_loop_ast_node_impl(polymorphic_enum_loop)) make_polymorphic_enum_loop_ast_node_impl(polymorphic_enum_loop),
} ),
BuildSpec::PolymorphicPassThrough(_) => None, BuildSpec::PolymorphicPassThrough(_) => None,
} }
} }
pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option<TokenStream> { fn make_type_ident(build_spec: &BuildSpec) -> Option<Ident> {
match build_spec { match build_spec {
BuildSpec::Struct(struct_spec) => { BuildSpec::Struct(struct_spec) => Some(format_ident!("{}", struct_spec.build())),
Some(format_ident!("{}", struct_spec.build())) BuildSpec::LeafStruct(leaf_struct) => Some(format_ident!("{}", leaf_struct.build())),
} BuildSpec::Enum(enum_spec) => Some(format_ident!("{}", enum_spec.build())),
BuildSpec::LeafStruct(leaf_struct) => { BuildSpec::LeafEnum(leaf_enum) => Some(format_ident!("{}", leaf_enum.build())),
Some(format_ident!("{}", leaf_struct.build()))
}
BuildSpec::Enum(enum_spec) => {
Some(format_ident!("{}", enum_spec.build()))
}
BuildSpec::LeafEnum(leaf_enum) => {
Some(format_ident!("{}", leaf_enum.build()))
}
BuildSpec::PolymorphicType(polymorphic_type) => { BuildSpec::PolymorphicType(polymorphic_type) => {
Some(format_ident!("{}", polymorphic_type.name())) Some(format_ident!("{}", polymorphic_type.name()))
}, }
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => { BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => {
Some(format_ident!("{}", polymorphic_enum_loop.name())) Some(format_ident!("{}", polymorphic_enum_loop.name()))
} }
@ -65,40 +49,36 @@ pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option<TokenStream> {
BuildSpec::Production(_) => None, BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None, BuildSpec::NodeProduction(_) => None,
} }
.map(|type_ident| { }
quote! {
#type_ident(&'a #type_ident) pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option<TokenStream> {
} make_type_ident(build_spec).map(|type_ident| {
}) quote! {
#type_ident(&'a #type_ident)
}
})
}
pub fn make_ast_enum_mut_member(build_spec: &BuildSpec) -> Option<TokenStream> {
make_type_ident(build_spec).map(|type_ident| {
quote! {
#type_ident(&'a mut #type_ident)
}
})
} }
pub fn make_ast_node_ref_unwrapper(build_spec: &BuildSpec) -> Option<TokenStream> { pub fn make_ast_node_ref_unwrapper(build_spec: &BuildSpec) -> Option<TokenStream> {
match build_spec { make_type_ident(build_spec).map(|type_ident| {
BuildSpec::Enum(enum_spec) => { quote! {
Some(format_ident!("{}", enum_spec.build())) AstNodeRef::#type_ident(inner) => *inner
} }
BuildSpec::LeafEnum(leaf_enum) => { })
Some(format_ident!("{}", leaf_enum.build())) }
pub fn make_ast_node_ref_mut_unwrapper(build_spec: &BuildSpec) -> Option<TokenStream> {
make_type_ident(build_spec).map(|type_ident| {
quote! {
AstNodeRefMut::#type_ident(inner) => *inner
} }
BuildSpec::Struct(struct_spec) => { })
Some(format_ident!("{}", struct_spec.build()))
}
BuildSpec::LeafStruct(leaf_struct) => {
Some(format_ident!("{}", leaf_struct.build()))
}
BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None,
BuildSpec::PolymorphicType(polymorphic_type) => {
Some(format_ident!("{}", polymorphic_type.name()))
}
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => {
Some(format_ident!("{}", polymorphic_enum_loop.name()))
}
BuildSpec::PolymorphicPassThrough(_) => None
}
.map(|type_ident| {
quote! {
AstNodeRef::#type_ident(inner) => *inner
}
})
} }

View File

@ -41,9 +41,17 @@ pub fn make_polymorphic_enum_loop_ast_node_impl(
children children
} }
fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {
todo!()
}
fn as_node_ref(&'a self) -> AstNodeRef<'a> { fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -16,6 +16,19 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let match_arms_mut = spec
.variants()
.map(|variant| {
let variant_ident = format_ident!("{}", variant.name());
let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake));
quote! {
#type_ident::#variant_ident(#child_ident) => {
f(#child_ident as &'a mut dyn AstNode)
}
}
})
.collect::<Vec<_>>();
quote! { quote! {
impl<'a> AstNode<'a> for #type_ident { impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> { fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
@ -24,9 +37,19 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T
} }
} }
fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {
match self {
#(#match_arms_mut,)*
}
}
fn as_node_ref(&'a self) -> AstNodeRef<'a> { fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -2,19 +2,27 @@ use crate::spec::struct_spec::{MemberChildBuild, StructChild, StructSpec, VecChi
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { fn make_child_adders(spec: &StructSpec, is_mut: bool) -> Vec<TokenStream> {
let type_ident = format_ident!("{}", spec.build()); let as_clause = if is_mut {
let child_adders = spec quote! { as &mut dyn AstNode }
.children() } else {
quote! { as &dyn AstNode }
};
spec.children()
.map(|child| match child { .map(|child| match child {
StructChild::SkipChild(_) => None, StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => match vec_child.build() { StructChild::VecChild(vec_child) => match vec_child.build() {
VecChildBuild::String(_) => None, VecChildBuild::String(_) => None,
VecChildBuild::Node(_) => { VecChildBuild::Node(_) => {
let child_ident = format_ident!("{}", vec_child.name()); let child_ident = if is_mut {
format_ident!("{}_mut", vec_child.name())
} else {
format_ident!("{}", vec_child.name())
};
let children_stream = quote! { let children_stream = quote! {
for child in self.#child_ident() { for child in self.#child_ident() {
children.push(child as &dyn AstNode); children.push(child #as_clause);
} }
}; };
Some(children_stream) Some(children_stream)
@ -22,16 +30,21 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
}, },
StructChild::MemberChild(member_child) => match member_child.build() { StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(_) => { MemberChildBuild::Node(_) => {
let child_ident = format_ident!("{}", member_child.name()); let child_ident = if is_mut {
format_ident!("{}_mut", member_child.name())
} else {
format_ident!("{}", member_child.name())
};
if member_child.optional() { if member_child.optional() {
Some(quote! { Some(quote! {
if let Some(#child_ident) = self.#child_ident() { if let Some(#child_ident) = self.#child_ident() {
children.push(#child_ident as &dyn AstNode); children.push(#child_ident #as_clause);
} }
}) })
} else { } else {
Some(quote! { Some(quote! {
children.push(self.#child_ident() as &dyn AstNode) children.push(self.#child_ident() #as_clause)
}) })
} }
} }
@ -41,7 +54,13 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
}) })
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>()
}
pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.build());
let child_adders = make_child_adders(spec, false);
let child_adders_mut = make_child_adders(spec, true);
quote! { quote! {
impl<'a> AstNode<'a> for #type_ident { impl<'a> AstNode<'a> for #type_ident {
@ -51,9 +70,17 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
children children
} }
fn for_each_child_mut(&'a mut self, mut f: &mut dyn FnMut(&'a mut dyn AstNode<'a>)) {
todo!()
}
fn as_node_ref(&'a self) -> AstNodeRef<'a> { fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a> {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -5,6 +5,22 @@ use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_me
use crate::spec::struct_spec::*; use crate::spec::struct_spec::*;
use yaml_rust2::Yaml; use yaml_rust2::Yaml;
fn deserialize_field(field_yaml: &Yaml) -> StructField {
let (name, props) = unwrap_single_member_hash(field_yaml);
let kind = props["kind"].as_str().unwrap();
let wrap = if let Some(wrap) = props["wrap"].as_str() {
match wrap {
"rc_ref_cell" => {
Some(StructFieldWrap::RcRefCell)
}
_ => panic!()
}
} else {
None
};
StructField::new(&name, kind, wrap)
}
fn deserialize_skip_child(props: &Yaml) -> StructChild { fn deserialize_skip_child(props: &Yaml) -> StructChild {
let rule = props["rule"].as_str().unwrap(); let rule = props["rule"].as_str().unwrap();
StructChild::SkipChild(SkipChild::new(rule)) StructChild::SkipChild(SkipChild::new(rule))
@ -151,6 +167,18 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
} else { } else {
deserialize_error!("array", "children", name); deserialize_error!("array", "children", name);
}; };
let fields = if struct_yaml["fields"].is_array() {
struct_yaml["fields"].as_vec()
.unwrap()
.iter()
.map(|field| deserialize_field(field))
.map(Box::new)
.collect()
} else {
vec![]
};
let derive = if struct_yaml["derive"].is_array() { let derive = if struct_yaml["derive"].is_array() {
struct_yaml["derive"].as_vec() struct_yaml["derive"].as_vec()
.unwrap() .unwrap()
@ -161,5 +189,5 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
vec![] vec![]
}; };
StructSpec::new(name, children, derive) StructSpec::new(name, children, fields, derive)
} }

View File

@ -6,7 +6,10 @@ mod spec;
mod type_gen; mod type_gen;
mod walk; mod walk;
use crate::ast_node::{make_ast_enum_member, make_ast_node_impl, make_ast_node_ref_unwrapper}; use crate::ast_node::{
make_ast_enum_member, make_ast_enum_mut_member, make_ast_node_impl,
make_ast_node_ref_mut_unwrapper, make_ast_node_ref_unwrapper,
};
use crate::build_fn::make_build_fn; use crate::build_fn::make_build_fn;
use crate::deserialize::deserialize_yaml_spec; use crate::deserialize::deserialize_yaml_spec;
use crate::pretty_print::make_pretty_print_impl; use crate::pretty_print::make_pretty_print_impl;
@ -111,6 +114,9 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let combined = quote! { let combined = quote! {
use std::range::Range; use std::range::Range;
use std::rc::Rc;
use std::cell::RefCell;
use crate::name_analysis::symbol::use_symbol::UseSymbol;
#(#types)* #(#types)*
}; };
@ -165,6 +171,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let ast_enum_mut_members = build_specs
.iter()
.map(|build_spec| make_ast_enum_mut_member(build_spec))
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let inner_unwrappers = build_specs let inner_unwrappers = build_specs
.iter() .iter()
.map(|build_spec| make_ast_node_ref_unwrapper(build_spec)) .map(|build_spec| make_ast_node_ref_unwrapper(build_spec))
@ -172,6 +185,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let inner_mut_unwrappers = build_specs
.iter()
.map(|build_spec| make_ast_node_ref_mut_unwrapper(build_spec))
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let combined = quote! { let combined = quote! {
use crate::ast::node::*; use crate::ast::node::*;
@ -187,10 +207,26 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
} }
} }
pub enum AstNodeRefMut<'a> {
#(#ast_enum_mut_members,)*
}
impl<'a> AstNodeRefMut<'a> {
pub fn inner(&mut self) -> &mut dyn AstNode<'a> {
match self {
#(#inner_mut_unwrappers,)*
}
}
}
pub trait AstNode<'a> { pub trait AstNode<'a> {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>>; fn children(&'a self) -> Vec<&'a dyn AstNode<'a>>;
fn for_each_child_mut(&'a mut self, f: &mut dyn FnMut(&'a mut dyn AstNode<'a>));
fn as_node_ref(&'a self) -> AstNodeRef<'a>; fn as_node_ref(&'a self) -> AstNodeRef<'a>;
fn as_node_ref_mut(&'a mut self) -> AstNodeRefMut<'a>;
} }
#(#impls)* #(#impls)*

View File

@ -1,14 +1,16 @@
pub struct StructSpec { pub struct StructSpec {
build: String, build: String,
children: Vec<Box<StructChild>>, children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
derive: Vec<String>, derive: Vec<String>,
} }
impl StructSpec { impl StructSpec {
pub fn new(build: &str, children: Vec<Box<StructChild>>, derive: Vec<String>) -> Self { pub fn new(build: &str, children: Vec<Box<StructChild>>, fields: Vec<Box<StructField>>, derive: Vec<String>) -> Self {
Self { Self {
build: build.to_string(), build: build.to_string(),
children, children,
fields,
derive, derive,
} }
} }
@ -23,6 +25,10 @@ impl StructSpec {
self.children.iter().map(Box::as_ref) self.children.iter().map(Box::as_ref)
} }
pub fn fields(&self) -> impl Iterator<Item = &StructField> {
self.fields.iter().map(Box::as_ref)
}
pub fn derive(&self) -> &[String] { pub fn derive(&self) -> &[String] {
&self.derive &self.derive
} }
@ -266,3 +272,37 @@ pub enum SpecialChildKind {
FileId, FileId,
Range, Range,
} }
#[derive(Debug)]
pub struct StructField {
name: String,
kind: String,
wrap: Option<StructFieldWrap>,
}
impl StructField {
pub fn new(name: &str, kind: &str, wrap: Option<StructFieldWrap>) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
wrap,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn wrap(&self) -> Option<&StructFieldWrap> {
self.wrap.as_ref()
}
}
#[derive(Debug)]
pub enum StructFieldWrap {
RcRefCell
}

View File

@ -1,10 +1,66 @@
use crate::spec::struct_spec::{ use crate::spec::struct_spec::{
MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec, MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructField,
VecChild, VecChildBuild, StructFieldWrap, StructSpec, VecChild, VecChildBuild,
}; };
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
fn make_field_accessors(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
let field_type = {
let inner = format_ident!("{}", field.kind());
if let Some(wrap) = field.wrap() {
match wrap {
StructFieldWrap::RcRefCell => {
quote! { Rc<RefCell<#inner>> }
}
}
} else {
quote! { #inner }
}
};
let set_field_ident = format_ident!("set_{}", field.name());
let field_ident_mut = format_ident!("{}_mut", field.name());
quote! {
pub fn #field_ident(&self) -> Option<&#field_type> {
self.#field_ident.as_ref()
}
pub fn #field_ident_mut(&mut self) -> Option<&mut #field_type> {
self.#field_ident.as_mut()
}
pub fn #set_field_ident(&mut self, #field_ident: #field_type) {
self.#field_ident = Some(#field_ident);
}
}
}
fn make_field_initializer(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
quote! { #field_ident: None }
}
fn make_annotated_field(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
let field_type = if let Some(wrap) = field.wrap() {
match wrap {
StructFieldWrap::RcRefCell => {
let inner = format_ident!("{}", field.kind());
quote! { Rc<RefCell<#inner>> }
}
}
} else {
let inner = format_ident!("{}", field.kind());
quote! { #inner }
};
quote! {
#field_ident: Option<#field_type>
}
}
fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream { fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream {
let child_ident = format_ident!("{}", vec_child.name()); let child_ident = format_ident!("{}", vec_child.name());
match vec_child.build() { match vec_child.build() {
@ -184,13 +240,18 @@ fn make_annotated_member(child: &StructChild) -> Option<TokenStream> {
pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream { pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build()); let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec let annotated_children_members = build_spec
.children() .children()
.map(|child| make_annotated_member(child)) .map(|child| make_annotated_member(child))
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let annotated_fields = build_spec
.fields()
.map(|field| make_annotated_field(field))
.collect::<Vec<_>>();
let member_names = build_spec let member_names = build_spec
.children() .children()
.map(|child| make_member_ident(child)) .map(|child| make_member_ident(child))
@ -198,17 +259,28 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let accessors = build_spec let field_initializers = build_spec
.fields()
.map(|field| make_field_initializer(field))
.collect::<Vec<_>>();
let child_accessors = build_spec
.children() .children()
.map(|child| make_accessors(child)) .map(|child| make_accessors(child))
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let field_accessors = build_spec
.fields()
.map(|field| make_field_accessors(field))
.collect::<Vec<_>>();
let struct_stream = { let struct_stream = {
let base = quote! { let base = quote! {
pub struct #type_ident { pub struct #type_ident {
#(#annotated_members),* #(#annotated_children_members,)*
#(#annotated_fields,)*
} }
}; };
if !build_spec.derive().is_empty() { if !build_spec.derive().is_empty() {
@ -231,13 +303,15 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
#struct_stream #struct_stream
impl #type_ident { impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self { pub fn new(#(#annotated_children_members),*) -> Self {
Self { Self {
#(#member_names),* #(#member_names,)*
#(#field_initializers,)*
} }
} }
#(#accessors)* #(#child_accessors)*
#(#field_accessors)*
} }
} }
} }

View File

@ -31,7 +31,7 @@ pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Err
let mut symbol_table = SymbolTable::new(); let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols."); add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
let diagnostics = analyze_names(&compilation_units, &files, &mut symbol_table); let diagnostics = analyze_names(&mut compilation_units, &files, &mut symbol_table);
if diagnostics.is_empty() { if diagnostics.is_empty() {
println!("Name analysis complete."); println!("Name analysis complete.");
println!("{}", symbol_table); println!("{}", symbol_table);

View File

@ -0,0 +1,178 @@
use std::cell::RefCell;
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::fqn_context::FqnContext;
use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
use crate::name_analysis::util::use_statement_base_fqn;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use std::range::Range;
use std::rc::Rc;
fn handle_insert_error(
err: SymbolInsertError,
error_symbol_name: &str,
error_file_id: usize,
error_range: Range<usize>,
symbol_types: &str,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match err {
SymbolInsertError::SymbolAlreadyDefined(s) => {
let mut diagnostic = Diagnostic::error()
.with_message(format!(
"{} symbol '{}' already defined in the current scope.",
symbol_types, error_symbol_name,
))
.with_label(
Label::primary(error_file_id, error_range)
.with_message("Symbol duplicated here."),
);
if let Some(source_definition) = s.definition() {
diagnostic = diagnostic.with_label(
Label::secondary(source_definition.file_id(), source_definition.range())
.with_message("Symbol defined here."),
);
}
diagnostics.push(diagnostic);
}
}
}
macro_rules! insert_symbol {
($insert_method:ident, $symbol:expr, $symbol_table:ident, $name:expr, $node:ident, $symbol_kinds:literal, $diagnostics:ident) => {
if let Err(insert_error) = $symbol_table.$insert_method($symbol) {
handle_insert_error(
insert_error,
$name,
$node.file_id(),
$node.range(),
$symbol_kinds,
$diagnostics,
)
}
};
}
macro_rules! insert_concrete_use_symbol {
($symbol:expr, $symbol_table:ident, $symbol_name:expr, $source_node:ident, $symbol_kinds:literal, $diagnostics:ident) => {
insert_symbol!(
insert_concrete_use_symbol,
$symbol,
$symbol_table,
$symbol_name,
$source_node,
$symbol_kinds,
$diagnostics
)
};
}
pub fn nap1_compilation_unit(
file_name: &str,
compilation_unit: &mut CompilationUnit,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let mut fqn_context = FqnContext::new();
symbol_table.push_scope(&format!("FileScope {}", file_name));
if let Some(namespace) = compilation_unit.namespace() {
for identifier in namespace.fqn().identifiers() {
fqn_context.push(identifier.name());
}
}
for use_statement in compilation_unit.use_statements_mut() {
nap1_use_statement(use_statement, symbol_table, diagnostics);
}
symbol_table.pop_scope();
}
fn handle_concrete_use_statement(
use_statement: &mut UseStatement,
identifier: &Identifier,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let base_fqn = use_statement_base_fqn(use_statement);
let to_insert = ConcreteUseSymbol::new(
&base_fqn,
identifier.name(),
Some(SourceDefinition::from_identifier(identifier))
);
match symbol_table.insert_concrete_use_symbol(to_insert) {
Ok(inserted) => {
use_statement.set_use_symbol(Rc::new(RefCell::new(UseSymbol::Concrete(inserted))));
}
Err(insert_error) => {
handle_insert_error(
insert_error,
identifier.name(),
identifier.file_id(),
identifier.range(),
"Use Symbol",
diagnostics
);
}
}
}
fn nap1_use_statement(
use_statement: &mut UseStatement,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let base_fqn = use_statement_base_fqn(use_statement);
match use_statement.suffix() {
UseStatementSuffix::Identifier(identifier) => {
insert_concrete_use_symbol!(
ConcreteUseSymbol::new(
&base_fqn,
identifier.name(),
Some(SourceDefinition::from_identifier(identifier))
),
symbol_table,
&base_fqn,
identifier,
"Use Statement",
diagnostics
)
}
UseStatementSuffix::Star => {
insert_symbol!(
insert_star_use_symbol,
StarUseSymbol::new(
&base_fqn,
Some(SourceDefinition::from_use_statement(use_statement))
),
symbol_table,
&base_fqn,
use_statement,
"Use Statement",
diagnostics
);
}
UseStatementSuffix::UseList(use_list) => {
for identifier in use_list.identifiers() {
insert_concrete_use_symbol!(
ConcreteUseSymbol::new(
&base_fqn,
identifier.name(),
Some(SourceDefinition::from_identifier(identifier))
),
symbol_table,
&base_fqn,
identifier,
"Use Statement",
diagnostics
);
}
}
}
}

View File

@ -23,43 +23,37 @@ The resolve phase has one main responsibility: resolve all references based on t
use crate::ast::ast_node::AstNode; use crate::ast::ast_node::AstNode;
use crate::ast::node::CompilationUnit; use crate::ast::node::CompilationUnit;
use crate::diagnostic::DmDiagnostic; use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::gather::gather_compilation_unit; use crate::name_analysis::first_pass::nap1_compilation_unit;
use crate::name_analysis::second_pass::nap2_compilation_unit;
use crate::name_analysis::symbol_table::SymbolTable; use crate::name_analysis::symbol_table::SymbolTable;
use codespan_reporting::files::Files; use codespan_reporting::files::Files;
use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use crate::name_analysis::scope_table::ScopeTable;
pub(self) mod fqn_context; pub(self) mod fqn_context;
mod gather;
// mod resolve; // mod resolve;
mod first_pass;
mod scope_table;
mod second_pass;
pub mod symbol; pub mod symbol;
pub mod symbol_table; pub mod symbol_table;
mod scope_table; mod util;
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>( pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
compilation_units: &[Box<CompilationUnit>], compilation_units: &mut Vec<Box<CompilationUnit>>,
files: &'a F, files: &'a F,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
) -> Vec<DmDiagnostic> { ) -> Vec<DmDiagnostic> {
let mut diagnostics = vec![]; let mut diagnostics = vec![];
let mut scope_table = ScopeTable::new();
// gather symbols // gather symbols
for compilation_unit in compilation_units { for compilation_unit in compilation_units.iter_mut() {
let file_name = files.name(compilation_unit.file_id()).unwrap(); let file_name = files.name(compilation_unit.file_id()).unwrap();
gather_compilation_unit( nap1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics);
compilation_unit,
&file_name,
symbol_table,
&mut scope_table,
&mut diagnostics,
);
} }
// resolve symbols // resolve symbols
for compilation_unit in compilation_units { for compilation_unit in compilation_units {
// resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); nap2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
} }
diagnostics.into() diagnostics.into()

View File

@ -0,0 +1,98 @@
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::use_symbol::UseSymbol;
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
use crate::name_analysis::util::use_statement_base_fqn;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use std::range::Range;
fn handle_lookup_error(
err: SymbolLookupError,
error_symbol_name: &str,
error_file_id: usize,
error_range: Range<usize>,
symbol_types: &str,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match err {
SymbolLookupError::NoDefinition => {
let diagnostic = Diagnostic::error()
.with_message(format!(
"No such {} symbol '{}' in scope.",
symbol_types, error_symbol_name,
))
.with_label(
Label::primary(error_file_id, error_range).with_message("Symbol used here."),
);
diagnostics.push(diagnostic);
}
}
}
pub fn nap2_compilation_unit(
compilation_unit: &mut CompilationUnit,
symbol_table: &SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// TODO: check namespace for proper file name
for use_statement in compilation_unit.use_statements_mut() {
nap2_use_statement(use_statement, symbol_table, diagnostics);
}
// TODO: declarations
}
fn nap2_use_statement(
use_statement: &mut UseStatement,
symbol_table: &SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let base_fqn = use_statement_base_fqn(use_statement);
let mut handle_concrete_use_symbol = |identifier: &Identifier| {
let fqn = format!("{}::{}", base_fqn, identifier.name());
match symbol_table.resolve_concrete_usable_by_fqn(&fqn) {
Ok(resolved_symbol) => match *use_statement.use_symbol().unwrap().borrow() {
UseSymbol::Concrete(ref concrete_use_symbol) => {
concrete_use_symbol
.borrow_mut()
.set_resolved_symbol(resolved_symbol);
}
_ => panic!("Unexpected symbol type"),
},
Err(lookup_error) => {
handle_lookup_error(
lookup_error,
&fqn,
use_statement.file_id(),
use_statement.range(),
"Usable Symbol",
diagnostics,
);
}
}
};
match use_statement.suffix() {
UseStatementSuffix::Identifier(identifier) => {
handle_concrete_use_symbol(identifier);
}
UseStatementSuffix::Star => {
if let Err(error) = symbol_table.resolve_usable_star(&base_fqn) {
handle_lookup_error(
error,
&base_fqn,
use_statement.file_id(),
use_statement.range(),
"Star Usable Symbol",
diagnostics,
);
}
}
UseStatementSuffix::UseList(use_list) => {
for identifier in use_list.identifiers() {
handle_concrete_use_symbol(identifier);
}
}
}
}

View File

@ -4,26 +4,30 @@ pub(crate) mod module_symbol;
pub(crate) mod parameter_symbol; pub(crate) mod parameter_symbol;
pub(crate) mod source_definition; pub(crate) mod source_definition;
pub(crate) mod type_symbol; pub(crate) mod type_symbol;
pub(crate) mod usable_symbol;
pub(crate) mod use_symbol; pub(crate) mod use_symbol;
pub(crate) mod variable_symbol; pub(crate) mod variable_symbol;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol;
use crate::name_analysis::symbol::use_symbol::UseSymbol;
use class_member_symbol::ClassMemberSymbol; use class_member_symbol::ClassMemberSymbol;
use function_symbol::FunctionSymbol; use function_symbol::FunctionSymbol;
use module_symbol::ModuleSymbol; use module_symbol::ModuleSymbol;
use parameter_symbol::ParameterSymbol; use parameter_symbol::ParameterSymbol;
use source_definition::SourceDefinition; use source_definition::SourceDefinition;
use std::cell::RefCell;
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc;
use type_symbol::TypeSymbol; use type_symbol::TypeSymbol;
use variable_symbol::VariableSymbol; use variable_symbol::VariableSymbol;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Symbol { pub enum Symbol {
ConcreteUse(ConcreteUseSymbol), Use(UseSymbol),
StarUse(StarUseSymbol),
Module(ModuleSymbol), Module(ModuleSymbol),
Type(TypeSymbol), Type(TypeSymbol),
ConcreteType(Rc<RefCell<ConcreteTypeSymbol>>),
Function(FunctionSymbol), Function(FunctionSymbol),
Parameter(ParameterSymbol), Parameter(ParameterSymbol),
Variable(VariableSymbol), Variable(VariableSymbol),
@ -31,16 +35,18 @@ pub enum Symbol {
} }
impl Symbol { impl Symbol {
pub fn definition(&self) -> Option<&SourceDefinition> { pub fn definition(&self) -> Option<SourceDefinition> {
match self { match self {
Symbol::ConcreteUse(concrete) => concrete.source_definition(), Symbol::Use(use_symbol) => use_symbol.source_definition(),
Symbol::StarUse(star) => star.source_definition(), Symbol::Module(module) => module.source_definition().cloned(),
Symbol::Module(module) => module.source_definition(), Symbol::Type(type_symbol) => type_symbol.source_definition().cloned(),
Symbol::Type(type_symbol) => type_symbol.source_definition(), Symbol::ConcreteType(concrete_type_symbol) => concrete_type_symbol.borrow().source_definition().cloned(),
Symbol::Function(function_symbol) => function_symbol.source_definition(), Symbol::Function(function_symbol) => function_symbol.source_definition().cloned(),
Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition(), Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition().cloned(),
Symbol::Variable(variable_symbol) => variable_symbol.source_definition(), Symbol::Variable(variable_symbol) => variable_symbol.source_definition().cloned(),
Symbol::ClassMember(class_member_symbol) => class_member_symbol.source_definition(), Symbol::ClassMember(class_member_symbol) => {
class_member_symbol.source_definition().cloned()
}
} }
} }
} }

View File

@ -0,0 +1,10 @@
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::type_symbol::{ConcreteTypeSymbol, TypeSymbol};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Clone, Debug)]
pub enum ConcreteUsableSymbol {
Type(Rc<RefCell<ConcreteTypeSymbol>>),
Function(Rc<RefCell<FunctionSymbol>>),
}

View File

@ -1,11 +1,30 @@
use crate::name_analysis::symbol::source_definition::SourceDefinition; use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol;
use std::cell::RefCell;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::rc::Rc;
#[derive(Debug, Clone)]
pub enum UseSymbol {
Concrete(Rc<RefCell<ConcreteUseSymbol>>),
Star(StarUseSymbol),
}
impl UseSymbol {
pub fn source_definition(&self) -> Option<SourceDefinition> {
match self {
UseSymbol::Concrete(concrete) => concrete.borrow().source_definition().cloned(),
UseSymbol::Star(star) => star.source_definition().cloned(),
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct ConcreteUseSymbol { pub struct ConcreteUseSymbol {
base_fqn: String, base_fqn: String,
declared_name: String, declared_name: String,
source_definition: Option<SourceDefinition>, source_definition: Option<SourceDefinition>,
resolved_symbol: Option<ConcreteUsableSymbol>,
} }
impl ConcreteUseSymbol { impl ConcreteUseSymbol {
@ -18,6 +37,7 @@ impl ConcreteUseSymbol {
base_fqn: base_fqn.to_string(), base_fqn: base_fqn.to_string(),
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
source_definition, source_definition,
resolved_symbol: None,
} }
} }
@ -32,6 +52,14 @@ impl ConcreteUseSymbol {
pub fn source_definition(&self) -> Option<&SourceDefinition> { pub fn source_definition(&self) -> Option<&SourceDefinition> {
self.source_definition.as_ref() self.source_definition.as_ref()
} }
pub fn resolved_symbol(&self) -> Option<&ConcreteUsableSymbol> {
self.resolved_symbol.as_ref()
}
pub fn set_resolved_symbol(&mut self, symbol: ConcreteUsableSymbol) {
self.resolved_symbol = Some(symbol);
}
} }
impl Debug for ConcreteUseSymbol { impl Debug for ConcreteUseSymbol {

View File

@ -2,15 +2,19 @@ use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol;
use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
use crate::name_analysis::symbol::type_symbol::TypeSymbol; use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol;
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
use crate::name_analysis::symbol::variable_symbol::VariableSymbol; use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
use crate::name_analysis::symbol::*; use crate::name_analysis::symbol::*;
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
use scope::Scope; use scope::Scope;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::fmt::Display; use std::fmt::Display;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc;
mod scope; mod scope;
@ -44,13 +48,14 @@ impl SymbolTable {
} }
pub fn push_scope(&mut self, debug_name: &str) { pub fn push_scope(&mut self, debug_name: &str) {
let id = self.scopes.len(); let id_to_push = self.scopes.len();
self.scopes.push(Scope::new( self.scopes.push(Scope::new(
Some(self.current_scope_id), Some(self.current_scope_id),
id, id_to_push,
debug_name.to_string(), debug_name.to_string(),
)); ));
self.current_scope_id = id; self.current_scope_mut().add_child(id_to_push);
self.current_scope_id = id_to_push;
} }
pub fn pop_scope(&mut self) { pub fn pop_scope(&mut self) {
@ -70,20 +75,17 @@ impl SymbolTable {
fn find_current_scope_concrete_use_symbol( fn find_current_scope_concrete_use_symbol(
&self, &self,
declared_name: &str, declared_name: &str,
) -> Option<&ConcreteUseSymbol> { ) -> Option<Rc<RefCell<ConcreteUseSymbol>>> {
self.current_scope() self.current_scope()
.concrete_use_symbols() .concrete_use_symbols()
.get(declared_name) .get(declared_name)
.cloned()
} }
fn find_current_scope_star_use_symbol(&self, base_fqn: &str) -> Option<&StarUseSymbol> { fn find_current_scope_star_use_symbol(&self, base_fqn: &str) -> Option<&StarUseSymbol> {
self.current_scope().star_use_symbols().get(base_fqn) self.current_scope().star_use_symbols().get(base_fqn)
} }
fn find_current_scope_type_symbol(&self, declared_name: &str) -> Option<&TypeSymbol> {
self.current_scope().type_symbols().get(declared_name)
}
fn find_current_scope_module_symbol(&self, declared_name: &str) -> Option<&ModuleSymbol> { fn find_current_scope_module_symbol(&self, declared_name: &str) -> Option<&ModuleSymbol> {
self.current_scope().module_symbols().get(declared_name) self.current_scope().module_symbols().get(declared_name)
} }
@ -119,11 +121,13 @@ impl SymbolTable {
fn find_current_scope_usable_symbol(&self, declared_name: &str) -> Option<Symbol> { fn find_current_scope_usable_symbol(&self, declared_name: &str) -> Option<Symbol> {
self.find_current_scope_concrete_use_symbol(declared_name) self.find_current_scope_concrete_use_symbol(declared_name)
.map(|concrete_use_symbol| Symbol::ConcreteUse(concrete_use_symbol.clone())) .map(|concrete_use_symbol| {
.or_else(|| { Symbol::Use(UseSymbol::Concrete(concrete_use_symbol.clone()))
self.find_current_scope_type_symbol(declared_name)
.map(|type_symbol| Symbol::Type(type_symbol.clone()))
}) })
// .or_else(|| {
// self.find_current_scope_type_symbol(declared_name)
// .map(|type_symbol| Symbol::Type(type_symbol.clone()))
// })
.or_else(|| { .or_else(|| {
self.find_current_scope_module_symbol(declared_name) self.find_current_scope_module_symbol(declared_name)
.map(|module_symbol| Symbol::Module(module_symbol.clone())) .map(|module_symbol| Symbol::Module(module_symbol.clone()))
@ -133,17 +137,22 @@ impl SymbolTable {
pub fn insert_concrete_use_symbol( pub fn insert_concrete_use_symbol(
&mut self, &mut self,
concrete_use_symbol: ConcreteUseSymbol, concrete_use_symbol: ConcreteUseSymbol,
) -> Result<(), SymbolInsertError> { ) -> Result<Rc<RefCell<ConcreteUseSymbol>>, SymbolInsertError> {
if let Some(defined_symbol) = if let Some(defined_symbol) =
self.find_current_scope_usable_symbol(concrete_use_symbol.declared_name()) self.find_current_scope_usable_symbol(concrete_use_symbol.declared_name())
{ {
Err(SymbolAlreadyDefined(defined_symbol)) Err(SymbolAlreadyDefined(defined_symbol))
} else { } else {
self.current_scope_mut().concrete_use_symbols_mut().insert( let name = concrete_use_symbol.declared_name().to_string();
concrete_use_symbol.declared_name().to_string(), self.current_scope_mut()
concrete_use_symbol, .concrete_use_symbols_mut()
); .insert(name.clone(), Rc::new(RefCell::new(concrete_use_symbol)));
Ok(()) Ok(self
.current_scope()
.concrete_use_symbols()
.get(&name)
.cloned()
.unwrap())
} }
} }
@ -154,9 +163,9 @@ impl SymbolTable {
if let Some(defined_symbol) = if let Some(defined_symbol) =
self.find_current_scope_star_use_symbol(star_use_symbol.base_fqn()) self.find_current_scope_star_use_symbol(star_use_symbol.base_fqn())
{ {
Err(SymbolAlreadyDefined(Symbol::StarUse( Err(SymbolAlreadyDefined(Symbol::Use(UseSymbol::Star(
defined_symbol.clone(), defined_symbol.clone(),
))) ))))
} else { } else {
self.current_scope_mut() self.current_scope_mut()
.star_use_symbols_mut() .star_use_symbols_mut()
@ -181,15 +190,23 @@ impl SymbolTable {
} }
} }
pub fn insert_type_symbol(&mut self, type_symbol: TypeSymbol) -> Result<(), SymbolInsertError> { fn find_current_scope_concrete_type_symbol(
if let Some(defined_symbol) = &self,
self.find_current_scope_usable_symbol(type_symbol.declared_name()) declared_name: &str,
) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
self.current_scope().get_concrete_type_symbol(declared_name)
}
pub fn insert_concrete_type_symbol(
&mut self,
symbol: ConcreteTypeSymbol,
) -> Result<(), SymbolInsertError> {
if let Some(defined_type) =
self.find_current_scope_concrete_type_symbol(symbol.declared_name())
{ {
Err(SymbolAlreadyDefined(defined_symbol)) Err(SymbolAlreadyDefined(Symbol::ConcreteType(defined_type)))
} else { } else {
self.current_scope_mut() self.current_scope_mut().insert_concrete_type_symbol(symbol);
.type_symbols_mut()
.insert(type_symbol.declared_name().to_string(), type_symbol);
Ok(()) Ok(())
} }
} }
@ -264,66 +281,6 @@ impl SymbolTable {
} }
} }
fn lookup_type_in_scope_by_declared_name<'a>(
scope: &'a Scope,
declared_name: &str,
) -> Option<&'a TypeSymbol> {
scope.type_symbols().get(declared_name)
}
pub fn lookup_type_by_declared_name(
&self,
declared_name: &str,
scope_id: usize,
) -> Result<&TypeSymbol, SymbolLookupError> {
let mut scope_opt = Some(&self.scopes[scope_id]);
while let Some(scope) = scope_opt {
if let Some(symbol) = Self::lookup_type_in_scope_by_declared_name(scope, declared_name)
{
return Ok(symbol);
}
scope_opt = if let Some(parent_id) = scope.parent() {
Some(&self.scopes[parent_id])
} else {
None
}
}
Err(NoDefinition)
}
fn lookup_type_in_scope_by_fqn<'a>(scope: &'a Scope, fqn: &str) -> Option<&'a TypeSymbol> {
for type_symbol in scope.type_symbols().values() {
match type_symbol {
TypeSymbol::Concrete(concrete_type_symbol) => {
if concrete_type_symbol.fqn() == fqn {
return Some(type_symbol);
}
}
TypeSymbol::Generic(_) => {}
}
}
None
}
pub fn lookup_type_by_fqn(
&self,
fqn: &str,
scope_id: usize,
) -> Result<&TypeSymbol, SymbolLookupError> {
let mut scope_opt = Some(&self.scopes[scope_id]);
while let Some(scope) = scope_opt {
if let Some(type_symbol) = Self::lookup_type_in_scope_by_fqn(scope, fqn) {
return Ok(type_symbol);
}
scope_opt = if let Some(parent_id) = scope.parent() {
Some(&self.scopes[parent_id])
} else {
None
};
}
Err(NoDefinition)
}
fn lookup_addressable_in_scope_by_identifier( fn lookup_addressable_in_scope_by_identifier(
scope: &Scope, scope: &Scope,
identifier: &str, identifier: &str,
@ -350,12 +307,12 @@ impl SymbolTable {
.get(identifier) .get(identifier)
.map(|function_symbol| Symbol::Function(function_symbol.clone())) .map(|function_symbol| Symbol::Function(function_symbol.clone()))
}) })
.or_else(|| { // .or_else(|| {
scope // scope
.type_symbols() // .type_symbols()
.get(identifier) // .get(identifier)
.map(|type_symbol| Symbol::Type(type_symbol.clone())) // .map(|type_symbol| Symbol::Type(type_symbol.clone()))
}) // })
} }
pub fn lookup_addressable_by_identifier( pub fn lookup_addressable_by_identifier(
@ -377,6 +334,39 @@ impl SymbolTable {
} }
Err(NoDefinition) Err(NoDefinition)
} }
pub fn resolve_concrete_usable_by_fqn(
&self,
fqn: &str,
) -> Result<ConcreteUsableSymbol, SymbolLookupError> {
// breadth-first search, use a queue
let mut search_stack: VecDeque<usize> = VecDeque::new();
search_stack.push_back(0); // global scope
while let Some(scope_id) = search_stack.pop_front() {
let scope = &self.scopes[scope_id];
for child_id in scope.children() {
search_stack.push_back(child_id);
}
if let Some(concrete_type_symbol) = scope.get_concrete_type_symbol_by_fqn(fqn) {
return Ok(ConcreteUsableSymbol::Type(concrete_type_symbol));
}
// TODO: this is inefficient. Use a (cached) hash table of Fqn => Rc<RefCell<symbol>>
for function_symbol in scope.function_symbols().values() {
if function_symbol.fqn() == fqn {
return Ok(ConcreteUsableSymbol::Function(todo!()));
}
}
}
Err(NoDefinition)
}
pub fn resolve_usable_star(&self, base_fqn: &str) -> Result<(), SymbolLookupError> {
todo!()
}
} }
impl Display for SymbolTable { impl Display for SymbolTable {

View File

@ -2,20 +2,24 @@ use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol;
use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
use crate::name_analysis::symbol::type_symbol::TypeSymbol; use crate::name_analysis::symbol::type_symbol::{ConcreteTypeSymbol, TypeSymbol};
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol}; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
use crate::name_analysis::symbol::variable_symbol::VariableSymbol; use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub struct Scope { pub struct Scope {
parent: Option<usize>, parent: Option<usize>,
id: usize, id: usize,
concrete_use_symbols: HashMap<String, ConcreteUseSymbol>, children: Vec<usize>,
concrete_use_symbols: HashMap<String, Rc<RefCell<ConcreteUseSymbol>>>,
star_use_symbols: HashMap<String, StarUseSymbol>, star_use_symbols: HashMap<String, StarUseSymbol>,
module_symbols: HashMap<String, ModuleSymbol>, module_symbols: HashMap<String, ModuleSymbol>,
type_symbols: HashMap<String, TypeSymbol>, concrete_type_symbols: HashMap<String, Rc<RefCell<ConcreteTypeSymbol>>>,
concrete_type_symbols_by_fqn: HashMap<String, Rc<RefCell<ConcreteTypeSymbol>>>,
function_symbols: HashMap<String, FunctionSymbol>, function_symbols: HashMap<String, FunctionSymbol>,
parameter_symbols: HashMap<String, ParameterSymbol>, parameter_symbols: HashMap<String, ParameterSymbol>,
variable_symbols: HashMap<String, VariableSymbol>, variable_symbols: HashMap<String, VariableSymbol>,
@ -28,10 +32,12 @@ impl Scope {
Self { Self {
parent, parent,
id, id,
children: vec![],
concrete_use_symbols: HashMap::new(), concrete_use_symbols: HashMap::new(),
star_use_symbols: HashMap::new(), star_use_symbols: HashMap::new(),
module_symbols: HashMap::new(), module_symbols: HashMap::new(),
type_symbols: HashMap::new(), concrete_type_symbols: HashMap::new(),
concrete_type_symbols_by_fqn: HashMap::new(),
function_symbols: HashMap::new(), function_symbols: HashMap::new(),
parameter_symbols: HashMap::new(), parameter_symbols: HashMap::new(),
variable_symbols: HashMap::new(), variable_symbols: HashMap::new(),
@ -48,11 +54,21 @@ impl Scope {
self.id self.id
} }
pub fn concrete_use_symbols(&self) -> &HashMap<String, ConcreteUseSymbol> { pub fn add_child(&mut self, child_id: usize) {
self.children.push(child_id);
}
pub fn children(&self) -> Vec<usize> {
self.children.clone()
}
pub fn concrete_use_symbols(&self) -> &HashMap<String, Rc<RefCell<ConcreteUseSymbol>>> {
&self.concrete_use_symbols &self.concrete_use_symbols
} }
pub fn concrete_use_symbols_mut(&mut self) -> &mut HashMap<String, ConcreteUseSymbol> { pub fn concrete_use_symbols_mut(
&mut self,
) -> &mut HashMap<String, Rc<RefCell<ConcreteUseSymbol>>> {
&mut self.concrete_use_symbols &mut self.concrete_use_symbols
} }
@ -72,12 +88,24 @@ impl Scope {
&mut self.module_symbols &mut self.module_symbols
} }
pub fn type_symbols(&self) -> &HashMap<String, TypeSymbol> { pub fn insert_concrete_type_symbol(&mut self, symbol: ConcreteTypeSymbol) {
&self.type_symbols let as_rc = Rc::new(RefCell::new(symbol));
self.concrete_type_symbols.insert(
as_rc.borrow().declared_name().to_string(),
as_rc.clone(),
);
self.concrete_type_symbols_by_fqn.insert(
as_rc.borrow().fqn().to_string(),
as_rc.clone(),
);
} }
pub fn type_symbols_mut(&mut self) -> &mut HashMap<String, TypeSymbol> { pub fn get_concrete_type_symbol(&self, declared_name: &str) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
&mut self.type_symbols self.concrete_type_symbols.get(declared_name).cloned()
}
pub fn get_concrete_type_symbol_by_fqn(&self, fqn: &str) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
self.concrete_type_symbols_by_fqn.get(fqn).cloned()
} }
pub fn function_symbols(&self) -> &HashMap<String, FunctionSymbol> { pub fn function_symbols(&self) -> &HashMap<String, FunctionSymbol> {
@ -131,13 +159,15 @@ impl Display for Scope {
f, f,
"----Scope {} (p: {}) {}----", "----Scope {} (p: {}) {}----",
self.id(), self.id(),
self.parent().map(|parent_id| format!("{}", parent_id)).unwrap_or_else(|| "None".to_string()), self.parent()
.map(|parent_id| format!("{}", parent_id))
.unwrap_or_else(|| "None".to_string()),
self.debug_name() self.debug_name()
)?; )?;
write_symbols!(f, self.concrete_use_symbols()); write_symbols!(f, self.concrete_use_symbols());
write_symbols!(f, self.star_use_symbols()); write_symbols!(f, self.star_use_symbols());
write_symbols!(f, self.module_symbols()); write_symbols!(f, self.module_symbols());
write_symbols!(f, self.type_symbols()); todo!("self.concrete_type_symbols");
write_symbols!(f, self.function_symbols()); write_symbols!(f, self.function_symbols());
write_symbols!(f, self.parameter_symbols()); write_symbols!(f, self.parameter_symbols());
write_symbols!(f, self.variable_symbols()); write_symbols!(f, self.variable_symbols());

11
src/name_analysis/util.rs Normal file
View File

@ -0,0 +1,11 @@
use crate::ast::node::UseStatement;
pub fn use_statement_base_fqn(
use_statement: &UseStatement
) -> String {
use_statement
.prefixes()
.map(|prefix| prefix.identifier().name())
.collect::<Vec<_>>()
.join("::")
}

View File

@ -248,6 +248,10 @@ UseStatement:
- range: - range:
special: special:
kind: range kind: range
fields:
- use_symbol:
kind: UseSymbol
wrap: rc_ref_cell
UseStatementPrefix: UseStatementPrefix:
struct: struct:
children: children: