Compare commits

...

3 Commits

Author SHA1 Message Date
Jesse Brault
eda25307b0 Attempt to add AstNodeRefMut, but failure. 2025-10-08 19:55:38 -05:00
Jesse Brault
542d5f6c80 WIP name gather, add fields for struct nodes. 2025-10-08 17:23:56 -05:00
Jesse Brault
3ab59961dd WIP on name-analysis gather, up to statements. 2025-10-06 13:43:38 -05:00
20 changed files with 1189 additions and 274 deletions

View File

@ -1,37 +1,48 @@
use crate::spec::tree_enum_spec::{
EnumRuleChildKind, TreeEnumBuildSpec, TreeEnumRule,
};
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec}; use proc_macro2::{Ident, TokenStream};
use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
fn make_match_arm(rule: &TreeEnumRule, type_ident: &Ident, is_mut: bool) -> TokenStream {
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));
let as_node_ref_ident = if is_mut {
quote! { as_node_ref_mut }
} else {
quote! { as_node_ref }
};
quote! {
#type_ident::#rule_ident(#child_ident) => vec![
#child_ident.#as_node_ref_ident()
]
}
}
_ => quote! {
#type_ident::#rule_ident(_) => vec![]
},
},
None => {
quote! {
#type_ident::#rule_ident => vec![]
}
}
}
}
pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream { pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", enum_spec.build()); let type_ident = format_ident!("{}", enum_spec.build());
let match_arms = enum_spec let match_arms = enum_spec
.rules() .rules()
.map(|rule| { .map(|rule| make_match_arm(rule, &type_ident, false))
let rule_ident = format_ident!("{}", rule.rule()); .collect::<Vec<_>>();
match rule.child() { let match_arms_mut = enum_spec
Some(child) => { .rules()
match child.kind() { .map(|rule| make_match_arm(rule, &type_ident, true))
EnumRuleChildKind::Node(node_child) => {
let child_ident = format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
quote! {
#type_ident::#rule_ident(#child_ident) => vec![
#child_ident.as_node_ref()
]
}
}
_ => quote! {
#type_ident::#rule_ident(_) => vec![]
}
}
},
None => {
quote! {
#type_ident::#rule_ident => vec![]
}
}
}
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
quote! { quote! {
@ -42,9 +53,19 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
} }
} }
fn children_mut(&mut self) -> Vec<AstNodeRefMut> {
match self {
#(#match_arms_mut,)*
}
}
fn as_node_ref(&self) -> AstNodeRef { fn as_node_ref(&self) -> AstNodeRef {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&mut self) -> AstNodeRefMut {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -1,6 +1,6 @@
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream { pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.build()); let type_ident = format_ident!("{}", spec.build());
@ -10,9 +10,17 @@ pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
vec![] vec![]
} }
fn children_mut(&mut self) -> Vec<AstNodeRefMut> {
vec![]
}
fn as_node_ref(&self) -> AstNodeRef { fn as_node_ref(&self) -> AstNodeRef {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&mut self) -> AstNodeRefMut {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -10,9 +10,17 @@ pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream
vec![] vec![]
} }
fn children_mut(&mut self) -> Vec<AstNodeRefMut> {
vec![]
}
fn as_node_ref(&self) -> AstNodeRef { fn as_node_ref(&self) -> AstNodeRef {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&mut self) -> AstNodeRefMut {
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_ast_enum_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,9 +49,20 @@ 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_ast_enum_ident(build_spec).map(|type_ident| {
}) quote! {
#type_ident(&'a #type_ident)
}
})
}
pub fn make_ast_enum_member_mut(build_spec: &BuildSpec) -> Option<TokenStream> {
make_ast_enum_ident(build_spec).map(|type_ident| {
quote! {
#type_ident(&'a mut #type_ident)
}
})
} }

View File

@ -4,6 +4,33 @@ use crate::spec::polymorphic_enum_loop_spec::{
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
fn make_child_adder(child: &PolymorphicEnumLoopRuleBuildChild, is_mut: bool) -> TokenStream {
let child_ident = {
let base = match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
format_ident!("{}", use_current.name())
}
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
format_ident!("{}", on_each.name())
}
};
if is_mut {
format_ident!("{}_mut", base)
} else {
base
}
};
let as_node_ref_ident = if is_mut {
quote! { as_node_ref_mut }
} else {
quote! { as_node_ref }
};
quote! {
children.push(self.#child_ident().#as_node_ref_ident());
}
}
pub fn make_polymorphic_enum_loop_ast_node_impl( pub fn make_polymorphic_enum_loop_ast_node_impl(
spec: &PolymorphicEnumLoopBuildSpec, spec: &PolymorphicEnumLoopBuildSpec,
) -> TokenStream { ) -> TokenStream {
@ -18,19 +45,12 @@ pub fn make_polymorphic_enum_loop_ast_node_impl(
.unwrap(); .unwrap();
let child_adders = build_rule let child_adders = build_rule
.children() .children()
.map(|child| { .map(|child| make_child_adder(child, false))
let child_ident = match child { .collect::<Vec<_>>();
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
format_ident!("{}", use_current.name()) let child_adders_mut = build_rule
} .children()
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => { .map(|child| make_child_adder(child, true))
format_ident!("{}", on_each.name())
}
};
quote! {
children.push(self.#child_ident().as_node_ref())
}
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
quote! { quote! {
@ -41,9 +61,19 @@ pub fn make_polymorphic_enum_loop_ast_node_impl(
children children
} }
fn children_mut(&mut self) -> Vec<AstNodeRefMut> {
let mut children: Vec<AstNodeRefMut> = vec![];
#(#child_adders_mut;)*
children
}
fn as_node_ref(&self) -> AstNodeRef { fn as_node_ref(&self) -> AstNodeRef {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&mut self) -> AstNodeRefMut {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -1,19 +1,36 @@
use crate::spec::polymorphic_type_spec::PolymorphicTypeBuildSpec; use crate::spec::polymorphic_type_spec::{PolymorphicTypeBuildSpec, PolymorphicTypeVariant};
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use proc_macro2::TokenStream; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
fn make_match_arm(
variant: &PolymorphicTypeVariant,
type_ident: &Ident,
is_mut: bool,
) -> TokenStream {
let variant_ident = format_ident!("{}", variant.name());
let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake));
let as_node_ref_ident = if is_mut {
quote! { as_node_ref_mut }
} else {
quote! { as_node_ref }
};
quote! {
#type_ident::#variant_ident(#child_ident) => vec![#child_ident.#as_node_ref_ident()]
}
}
pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> TokenStream { pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.name()); let type_ident = format_ident!("{}", spec.name());
let match_arms = spec let match_arms = spec
.variants() .variants()
.map(|variant| { .map(|variant| make_match_arm(variant, &type_ident, false))
let variant_ident = format_ident!("{}", variant.name()); .collect::<Vec<_>>();
let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake));
quote! { let match_arms_mut = spec
#type_ident::#variant_ident(#child_ident) => vec![#child_ident.as_node_ref()] .variants()
} .map(|variant| make_match_arm(variant, &type_ident, true))
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
quote! { quote! {
@ -24,9 +41,19 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T
} }
} }
fn children_mut(&mut self) -> Vec<AstNodeRefMut> {
match self {
#(#match_arms_mut,)*
}
}
fn as_node_ref(&self) -> AstNodeRef { fn as_node_ref(&self) -> AstNodeRef {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&mut self) -> AstNodeRefMut {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -2,43 +2,69 @@ 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};
fn make_child_adder(child: &StructChild, is_mut: bool) -> Option<TokenStream> {
let as_node_ref_ident = if is_mut {
format_ident!("as_node_ref_mut")
} else {
format_ident!("as_node_ref")
};
match child {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => match vec_child.build() {
VecChildBuild::String(_) => None,
VecChildBuild::Node(_) => {
let child_ident = if is_mut {
format_ident!("{}_mut", vec_child.name())
} else {
format_ident!("{}", vec_child.name())
};
let children_stream = quote! {
for child in self.#child_ident().map(AstNode::#as_node_ref_ident) {
children.push(child);
}
};
Some(children_stream)
}
},
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(_) => {
let child_ident = if is_mut {
format_ident!("{}_mut", member_child.name())
} else {
format_ident!("{}", member_child.name())
};
if member_child.optional() {
Some(quote! {
if let Some(#child_ident) = self.#child_ident() {
children.push(#child_ident.#as_node_ref_ident());
}
})
} else {
Some(quote! {
children.push(self.#child_ident().#as_node_ref_ident());
})
}
}
MemberChildBuild::Boolean(_) => None,
},
StructChild::Special(_) => None,
}
}
pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.build()); let type_ident = format_ident!("{}", spec.build());
let child_adders = spec let child_adders = spec
.children() .children()
.map(|child| match child { .map(|child| make_child_adder(child, false))
StructChild::SkipChild(_) => None, .filter(Option::is_some)
StructChild::VecChild(vec_child) => match vec_child.build() { .map(Option::unwrap)
VecChildBuild::String(_) => None, .collect::<Vec<_>>();
VecChildBuild::Node(_) => {
let child_ident = format_ident!("{}", vec_child.name()); let child_adders_mut = spec
let children_stream = quote! { .children()
for child in self.#child_ident().map(AstNode::as_node_ref) { .map(|child| make_child_adder(child, true))
children.push(child);
}
};
Some(children_stream)
}
},
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(_) => {
let child_ident = format_ident!("{}", member_child.name());
if member_child.optional() {
Some(quote! {
if let Some(#child_ident) = self.#child_ident() {
children.push(#child_ident.as_node_ref());
}
})
} else {
Some(quote! {
children.push(self.#child_ident().as_node_ref())
})
}
}
MemberChildBuild::Boolean(_) => None,
},
StructChild::Special(_) => None,
})
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -51,9 +77,19 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
children children
} }
fn children_mut(&mut self) -> Vec<AstNodeRefMut> {
let mut children: Vec<AstNodeRefMut> = vec![];
#(#child_adders_mut;)*
children
}
fn as_node_ref(&self) -> AstNodeRef { fn as_node_ref(&self) -> AstNodeRef {
AstNodeRef::#type_ident(&self) AstNodeRef::#type_ident(&self)
} }
fn as_node_ref_mut(&mut self) -> AstNodeRefMut {
AstNodeRefMut::#type_ident(self)
}
} }
} }
} }

View File

@ -1,5 +1,8 @@
use crate::deserialize::util::{make_build_fn_name, make_build_pair}; use crate::deserialize::util::{make_build_fn_name, make_build_pair};
use crate::spec::struct_spec::{MemberChildBuild, NodeMemberBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec, VecChild, VecChildBuild}; use crate::spec::struct_spec::{
MemberChildBuild, NodeMemberBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec,
VecChild, VecChildBuild,
};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -125,7 +128,7 @@ fn make_rule_matcher(child_spec: &StructChild) -> Option<TokenStream> {
Some(quote! { Some(quote! {
Rule::#rule_ident => {} Rule::#rule_ident => {}
}) })
}, }
StructChild::VecChild(vec_child) => { StructChild::VecChild(vec_child) => {
let rule_ident = format_ident!("{}", vec_child.rule()); let rule_ident = format_ident!("{}", vec_child.rule());
let action = make_vec_child_match_action(vec_child); let action = make_vec_child_match_action(vec_child);
@ -133,28 +136,24 @@ fn make_rule_matcher(child_spec: &StructChild) -> Option<TokenStream> {
Rule::#rule_ident => { #action } Rule::#rule_ident => { #action }
}) })
} }
StructChild::MemberChild(member_child) => { StructChild::MemberChild(member_child) => match member_child.build() {
match member_child.build() { MemberChildBuild::Node(node_member_build) => {
MemberChildBuild::Node(node_member_build) => { let rule_ident = format_ident!("{}", member_child.rule());
let rule_ident = format_ident!("{}", member_child.rule()); let action =
let action = make_node_member_child_match_action( make_node_member_child_match_action(member_child.name(), node_member_build);
member_child.name(), Some(quote! {
node_member_build Rule::#rule_ident => { #action }
); })
Some(quote! { }
Rule::#rule_ident => { #action } MemberChildBuild::Boolean(_) => {
}) let rule_ident = format_ident!("{}", member_child.rule());
} let action = make_boolean_member_child_match_action(member_child.name());
MemberChildBuild::Boolean(_) => { Some(quote! {
let rule_ident = format_ident!("{}", member_child.rule()); Rule::#rule_ident => { #action }
let action = make_boolean_member_child_match_action(member_child.name()); })
Some(quote! {
Rule::#rule_ident => { #action }
})
}
} }
}, },
StructChild::Special(_) => None StructChild::Special(_) => None,
} }
} }
@ -192,7 +191,7 @@ fn make_special_child_arg(special_child: &SpecialChild) -> TokenStream {
quote! { #child_ident } quote! { #child_ident }
} }
fn make_child_arg(child_spec: &StructChild, pair_ident: &Ident) -> Option<TokenStream> { fn make_child_arg(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec { match child_spec {
StructChild::SkipChild(_) => None, StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)), StructChild::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)),
@ -204,7 +203,7 @@ fn make_child_arg(child_spec: &StructChild, pair_ident: &Ident) -> Option<TokenS
)), )),
MemberChildBuild::Boolean(_) => { MemberChildBuild::Boolean(_) => {
Some(make_boolean_member_child_arg(member_child.name())) Some(make_boolean_member_child_arg(member_child.name()))
}, }
}, },
StructChild::Special(special_child) => Some(make_special_child_arg(special_child)), StructChild::Special(special_child) => Some(make_special_child_arg(special_child)),
} }
@ -214,7 +213,7 @@ fn make_return_value_stream(build_spec: &StructSpec, pair_ident: &Ident) -> Toke
let type_ident = format_ident!("{}", build_spec.build()); let type_ident = format_ident!("{}", build_spec.build());
let child_args = build_spec let child_args = build_spec
.children() .children()
.map(|child| make_child_arg(child, pair_ident)) .map(|child| make_child_arg(child))
.filter(|child_arg| child_arg.is_some()) .filter(|child_arg| child_arg.is_some())
.map(|child_arg| child_arg.unwrap()) .map(|child_arg| child_arg.unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@ -5,6 +5,23 @@ 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_fields(fields: &Yaml) -> Vec<Box<StructField>> {
fields
.as_vec()
.unwrap()
.iter()
.map(|field| unwrap_single_member_hash(field))
.map(|(name, props)| {
let kind = match props["kind"].as_str().unwrap() {
"usize" => StructFieldKind::USize,
_ => panic!()
};
StructField::new(&name, kind, get_as_bool(&props["optional"]))
})
.map(Box::new)
.collect()
}
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))
@ -96,7 +113,11 @@ fn deserialize_special_child(name: &str, props: &Yaml) -> StructChild {
match props["kind"].as_str().unwrap() { match props["kind"].as_str().unwrap() {
"file_id" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::FileId)), "file_id" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::FileId)),
"range" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::Range)), "range" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::Range)),
_ => panic!("Invalid special child kind {} in {}", props["kind"].as_str().unwrap(), name), _ => panic!(
"Invalid special child kind {} in {}",
props["kind"].as_str().unwrap(),
name
),
} }
} }
@ -151,5 +172,11 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
} else { } else {
deserialize_error!("array", "children", name); deserialize_error!("array", "children", name);
}; };
StructSpec::new(name, children) let fields = if struct_yaml["fields"].is_array() {
deserialize_fields(&struct_yaml["fields"])
} else {
vec![]
};
StructSpec::new(name, children, fields)
} }

View File

@ -6,7 +6,7 @@ mod spec;
mod type_gen; mod type_gen;
mod walk; mod walk;
use crate::ast_node::{make_ast_enum_member, make_ast_node_impl}; use crate::ast_node::{make_ast_enum_member, make_ast_enum_member_mut, make_ast_node_impl};
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;
@ -165,6 +165,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let ast_enum_members_mut = build_specs
.iter()
.map(|build_spec| make_ast_enum_member_mut(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::*;
@ -172,10 +179,18 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
#(#ast_enum_members,)* #(#ast_enum_members,)*
} }
pub enum AstNodeRefMut<'a> {
#(#ast_enum_members_mut,)*
}
pub trait AstNode { pub trait AstNode {
fn children(&self) -> Vec<AstNodeRef>; fn children(&self) -> Vec<AstNodeRef>;
fn children_mut(&mut self) -> Vec<AstNodeRefMut>;
fn as_node_ref(&self) -> AstNodeRef; fn as_node_ref(&self) -> AstNodeRef;
fn as_node_ref_mut(&mut self) -> AstNodeRefMut;
} }
#(#impls)* #(#impls)*

View File

@ -1,13 +1,19 @@
pub struct StructSpec { pub struct StructSpec {
build: String, build: String,
children: Vec<Box<StructChild>>, children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
} }
impl StructSpec { impl StructSpec {
pub fn new(build: &str, children: Vec<Box<StructChild>>) -> Self { pub fn new(
build: &str,
children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
) -> Self {
Self { Self {
build: build.to_string(), build: build.to_string(),
children, children,
fields,
} }
} }
@ -20,6 +26,10 @@ impl StructSpec {
pub fn children(&self) -> impl Iterator<Item = &StructChild> { pub fn children(&self) -> impl Iterator<Item = &StructChild> {
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 enum StructChild { pub enum StructChild {
@ -39,10 +49,8 @@ impl StructChild {
pub fn unwrap_special(&self) -> Option<&SpecialChild> { pub fn unwrap_special(&self) -> Option<&SpecialChild> {
match self { match self {
StructChild::Special(special_child) => { StructChild::Special(special_child) => Some(special_child),
Some(special_child) _ => None,
},
_ => None
} }
} }
} }
@ -242,7 +250,7 @@ impl SpecialChild {
pub fn new(name: &str, kind: SpecialChildKind) -> Self { pub fn new(name: &str, kind: SpecialChildKind) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
kind kind,
} }
} }
@ -260,3 +268,35 @@ pub enum SpecialChildKind {
FileId, FileId,
Range, Range,
} }
pub struct StructField {
name: String,
kind: StructFieldKind,
optional: bool,
}
impl StructField {
pub fn new(name: &str, kind: StructFieldKind, optional: bool) -> Self {
Self {
name: name.to_string(),
kind,
optional,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &StructFieldKind {
&self.kind
}
pub fn optional(&self) -> bool {
self.optional
}
}
pub enum StructFieldKind {
USize,
}

View File

@ -1,6 +1,6 @@
use crate::spec::struct_spec::{ use crate::spec::struct_spec::{
MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec, MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructField,
VecChild, VecChildBuild, StructFieldKind, StructSpec, VecChild, VecChildBuild,
}; };
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -99,7 +99,7 @@ fn make_special_child_accessors(special_child: &SpecialChild) -> TokenStream {
} }
} }
fn make_accessors(child: &StructChild) -> Option<TokenStream> { fn make_child_accessors(child: &StructChild) -> Option<TokenStream> {
match child { match child {
StructChild::SkipChild(_) => None, StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_accessors(vec_child)), StructChild::VecChild(vec_child) => Some(make_vec_child_accessors(vec_child)),
@ -182,15 +182,68 @@ fn make_annotated_member(child: &StructChild) -> Option<TokenStream> {
} }
} }
fn make_annotated_field(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
let field_type_ident = match field.kind() {
StructFieldKind::USize => quote! { usize },
};
if field.optional() {
quote! {
#field_ident: Option<#field_type_ident>
}
} else {
quote! {
#field_ident: #field_type_ident
}
}
}
fn make_field_init(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
if field.optional() {
quote! {
#field_ident: None
}
} else {
todo!()
}
}
fn make_field_accessors(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
let field_type_ident = match field.kind() {
StructFieldKind::USize => quote! { usize },
};
if field.optional() {
let setter_ident = format_ident!("set_{}", field.name());
quote! {
pub fn #field_ident(&self) -> Option<#field_type_ident> {
self.#field_ident
}
pub fn #setter_ident(&mut self, #field_ident: #field_type_ident) {
self.#field_ident = Some(#field_ident);
}
}
} else {
todo!()
}
}
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 = 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,26 +251,39 @@ 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_inits = build_spec
.fields()
.map(|field| make_field_init(field))
.collect::<Vec<_>>();
let child_accessors = build_spec
.children() .children()
.map(|child| make_accessors(child)) .map(|child| make_child_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<_>>();
quote! { quote! {
pub struct #type_ident { pub struct #type_ident {
#(#annotated_members),* #(#annotated_children,)*
#(#annotated_fields,)*
} }
impl #type_ident { impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self { pub fn new(#(#annotated_children),*) -> Self {
Self { Self {
#(#member_names),* #(#member_names,)*
#(#field_inits,)*
} }
} }
#(#accessors)* #(#child_accessors)*
#(#field_accessors)*
} }
} }
} }

View File

@ -1,6 +1,36 @@
pub mod node { pub mod node {
include!(concat!(env!("OUT_DIR"), "/src/ast/node.rs")); include!(concat!(env!("OUT_DIR"), "/src/ast/node.rs"));
impl OperatorInner {
pub fn name(&self) -> &'static str {
match self {
OperatorInner::Or => "op_or",
OperatorInner::And => "op_and",
OperatorInner::EqualTo => "op_eq",
OperatorInner::NotEqualTo => "op_neq",
OperatorInner::Greater => "op_gt",
OperatorInner::Less => "op_lt",
OperatorInner::GreaterEqual => "op_ge",
OperatorInner::LessEqual => "op_le",
OperatorInner::Add => "op_add",
OperatorInner::Subtract => "op_sub",
OperatorInner::Multiply => "op_mul",
OperatorInner::Divide => "op_div",
OperatorInner::Modulo => "op_mod",
OperatorInner::LeftShift => "op_ls",
OperatorInner::RightShift => "op_rs",
OperatorInner::Spread => "op_spread",
OperatorInner::Star => "op_star",
OperatorInner::Not => "op_not",
OperatorInner::Negative => "op_neg",
OperatorInner::PlusPlus => "op_pp",
OperatorInner::MinusMinus => "op_mm",
OperatorInner::CallOp => "op_call",
OperatorInner::Index => "op_index",
}
}
}
impl Default for Parameters { impl Default for Parameters {
fn default() -> Self { fn default() -> Self {
Self::new(vec![]) Self::new(vec![])

View File

@ -1,10 +1,13 @@
use crate::ast::ast_node::{AstNode, AstNodeRef}; use crate::ast::ast_node::{AstNode, AstNodeRef};
use crate::ast::node::{ use crate::ast::node::{
Class, CompilationUnit, Function, FunctionBlockBody, FunctionBody, Identifier, Interface, Class, CompilationUnit, Function, FunctionBody, Identifier, Interface,
Module, Namespace, Statement, UseStatement, UseStatementSuffix, VariableDeclaration, InterfaceDefaultFunction, InterfaceDefaultOperatorFunction, InterfaceFunction,
InterfaceOperatorFunction, Member, Module, Namespace, OperatorFunction, PlatformFunction,
PlatformOperatorFunction, UseStatement, UseStatementSuffix, VariableDeclaration, VariableUse,
}; };
use crate::diagnostic::DmDiagnostic; use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::fqn_context::FqnContext;
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::source_definition::SourceDefinition; use crate::name_analysis::symbol::source_definition::SourceDefinition;
@ -67,9 +70,14 @@ fn gather_node(
diagnostics: &mut Vec<DmDiagnostic>, diagnostics: &mut Vec<DmDiagnostic>,
) { ) {
match node { match node {
AstNodeRef::Operator(_) => {} AstNodeRef::Operator(_) => {
unreachable!();
}
AstNodeRef::OperatorInner(_) => {
unreachable!();
}
AstNodeRef::Identifier(_) => { AstNodeRef::Identifier(_) => {
unreachable!() unreachable!();
} }
AstNodeRef::FullyQualifiedName(_) => {} AstNodeRef::FullyQualifiedName(_) => {}
AstNodeRef::TypeUseList(_) => {} AstNodeRef::TypeUseList(_) => {}
@ -98,13 +106,13 @@ fn gather_node(
gather_use_statement(use_statement, symbol_table, diagnostics); gather_use_statement(use_statement, symbol_table, diagnostics);
} }
AstNodeRef::UseStatementPrefix(_) => { AstNodeRef::UseStatementPrefix(_) => {
unreachable!() unreachable!();
} }
AstNodeRef::UseStatementSuffix(_) => { AstNodeRef::UseStatementSuffix(_) => {
unreachable!() unreachable!();
} }
AstNodeRef::UseList(_) => { AstNodeRef::UseList(_) => {
unreachable!() unreachable!();
} }
AstNodeRef::ModuleLevelDeclaration(module_level_declaration) => { AstNodeRef::ModuleLevelDeclaration(module_level_declaration) => {
gather_node_children( gather_node_children(
@ -142,62 +150,76 @@ fn gather_node(
AstNodeRef::Function(function) => { AstNodeRef::Function(function) => {
gather_function(function, symbol_table, fqn_context, diagnostics); gather_function(function, symbol_table, fqn_context, diagnostics);
} }
AstNodeRef::OperatorFunction(_) => {} AstNodeRef::OperatorFunction(operator_function) => {
AstNodeRef::PlatformFunction(_) => {} gather_operator_function(operator_function, symbol_table, fqn_context, diagnostics);
AstNodeRef::InterfaceFunction(_) => {} }
AstNodeRef::InterfaceDefaultFunction(_) => {} AstNodeRef::PlatformFunction(platform_function) => {
AstNodeRef::InterfaceOperatorFunction(_) => {} gather_platform_function(platform_function, symbol_table, fqn_context, diagnostics);
AstNodeRef::InterfaceDefaultOperatorFunction(_) => {} }
AstNodeRef::FunctionBody(function_body) => match function_body { AstNodeRef::PlatformOperatorFunction(platform_operator_function) => {
FunctionBody::FunctionAliasBody(alias_body) => { gather_platform_operator_function(
gather_node( platform_operator_function,
alias_body.as_node_ref(), symbol_table,
symbol_table, fqn_context,
fqn_context, diagnostics,
diagnostics, );
); }
} AstNodeRef::InterfaceFunction(interface_function) => {
FunctionBody::FunctionEqualsBody(equals_body) => { gather_interface_function(interface_function, symbol_table, fqn_context, diagnostics);
gather_node( }
equals_body.as_node_ref(), AstNodeRef::InterfaceDefaultFunction(interface_default_function) => {
symbol_table, gather_interface_default_function(
fqn_context, interface_default_function,
diagnostics, symbol_table,
); fqn_context,
} diagnostics,
FunctionBody::FunctionBlockBody(block_body) => { );
gather_node( }
block_body.as_node_ref(), AstNodeRef::InterfaceOperatorFunction(interface_operator_function) => {
symbol_table, gather_interface_operator_function(
fqn_context, interface_operator_function,
diagnostics, symbol_table,
); fqn_context,
} diagnostics,
}, );
AstNodeRef::FunctionEqualsBody(_) => {} }
AstNodeRef::FunctionAliasBody(_) => {} AstNodeRef::InterfaceDefaultOperatorFunction(interface_default_operator_function) => {
AstNodeRef::FunctionBlockBody(block_body) => { gather_interface_default_operator_function(
gather_function_block_body(block_body, symbol_table, fqn_context, diagnostics); interface_default_operator_function,
symbol_table,
fqn_context,
diagnostics,
);
}
AstNodeRef::FunctionBody(function_body) => {
gather_function_body(function_body, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::FunctionEqualsBody(function_equals_body) => {
gather_node_children(function_equals_body, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::FunctionAliasBody(_) => {
// no-op
}
AstNodeRef::FunctionBlockBody(function_block_body) => {
gather_node_children(function_block_body, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::ClassConstructor(class_constructor) => {
gather_node_children(class_constructor, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::Member(member) => {
gather_member(member, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::Statement(statement) => {
gather_node_children(statement, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::VariableDeclaration(variable_declaration) => {
gather_variable_declaration(
variable_declaration,
symbol_table,
fqn_context,
diagnostics,
);
} }
AstNodeRef::ClassConstructor(_) => {}
AstNodeRef::Member(_) => {}
AstNodeRef::Statement(statement) => match statement {
Statement::VariableDeclaration(variable_declaration) => {
gather_node(
variable_declaration.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
Statement::AssignmentStatement(_) => {}
Statement::ExpressionStatement(_) => {}
Statement::UseStatement(_) => {}
Statement::IfStatement(_) => {}
Statement::WhileStatement(_) => {}
Statement::ForStatement(_) => {}
},
AstNodeRef::VariableDeclaration(_) => {}
AstNodeRef::AssignmentStatement(_) => {} AstNodeRef::AssignmentStatement(_) => {}
AstNodeRef::ExpressionStatement(_) => {} AstNodeRef::ExpressionStatement(_) => {}
AstNodeRef::IfStatement(_) => {} AstNodeRef::IfStatement(_) => {}
@ -206,6 +228,11 @@ fn gather_node(
AstNodeRef::IfElse(_) => {} AstNodeRef::IfElse(_) => {}
AstNodeRef::WhileStatement(_) => {} AstNodeRef::WhileStatement(_) => {}
AstNodeRef::ForStatement(_) => {} AstNodeRef::ForStatement(_) => {}
AstNodeRef::LValue(_) => {}
AstNodeRef::LValueSuffix(_) => {}
AstNodeRef::VariableUse(variable_use) => {
gather_variable_use(variable_use, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::Expression(_) => {} AstNodeRef::Expression(_) => {}
AstNodeRef::TernaryExpression(_) => {} AstNodeRef::TernaryExpression(_) => {}
AstNodeRef::TernaryRhs(_) => {} AstNodeRef::TernaryRhs(_) => {}
@ -443,6 +470,12 @@ fn gather_class(
fqn_context.push(class.identifier().name()); fqn_context.push(class.identifier().name());
symbol_table.push_scope(&format!("ClassScope {}", class.identifier().name())); symbol_table.push_scope(&format!("ClassScope {}", class.identifier().name()));
gather_node(
class.class_constructor().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
for declaration in class.class_level_declarations() { for declaration in class.class_level_declarations() {
gather_node( gather_node(
declaration.as_node_ref(), declaration.as_node_ref(),
@ -479,25 +512,488 @@ fn gather_function(
diagnostics, diagnostics,
); );
} }
symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name()));
gather_node(
function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
function.parameters().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
function.return_type().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node( gather_node(
function.function_body().as_node_ref(), function.function_body().as_node_ref(),
symbol_table, symbol_table,
fqn_context, fqn_context,
diagnostics, diagnostics,
); );
symbol_table.pop_scope();
} }
fn gather_function_block_body( fn gather_operator_function(
function_block_body: &FunctionBlockBody, operator_function: &OperatorFunction,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext, fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>, diagnostics: &mut Vec<DmDiagnostic>,
) { ) {
symbol_table.push_scope("FunctionBlockBody"); let function_symbol = FunctionSymbol::without_parameters_or_return_type(
gather_node_children(function_block_body, symbol_table, fqn_context, diagnostics); &fqn_context.resolve(&operator_function.operator().inner().name()),
operator_function.operator().inner().name(),
operator_function.is_public(),
false,
Some(SourceDefinition::from_operator(
operator_function.operator(),
)),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
operator_function.operator().inner().name(),
operator_function.operator().file_id(),
operator_function.operator().range(),
"Operator",
diagnostics,
);
}
symbol_table.push_scope(&format!(
"FunctionScope {}",
operator_function.operator().inner().name()
));
gather_node(
operator_function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
operator_function.parameters().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
operator_function.return_type().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
operator_function.function_body().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
symbol_table.pop_scope(); symbol_table.pop_scope();
} }
fn gather_platform_function(
platform_function: &PlatformFunction,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
&fqn_context.resolve(platform_function.identifier().name()),
platform_function.identifier().name(),
platform_function.is_public(),
true,
Some(SourceDefinition::from_identifier(
platform_function.identifier(),
)),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
platform_function.identifier().name(),
platform_function.identifier().file_id(),
platform_function.identifier().range(),
"Function",
diagnostics,
);
}
symbol_table.push_scope(&format!(
"PlatformFunctionScope {}",
platform_function.identifier().name()
));
gather_node(
platform_function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
platform_function.parameters().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
platform_function.return_type().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
symbol_table.pop_scope();
}
fn gather_platform_operator_function(
platform_operator_function: &PlatformOperatorFunction,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
&fqn_context.resolve(platform_operator_function.operator().inner().name()),
platform_operator_function.operator().inner().name(),
platform_operator_function.is_public(),
true,
Some(SourceDefinition::from_operator(
platform_operator_function.operator(),
)),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
platform_operator_function.operator().inner().name(),
platform_operator_function.operator().file_id(),
platform_operator_function.operator().range(),
"Function",
diagnostics,
);
}
symbol_table.push_scope(&format!(
"PlatformOperatorFunctionScope {}",
platform_operator_function.operator().inner().name()
));
gather_node(
platform_operator_function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
platform_operator_function.parameters().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
platform_operator_function.return_type().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
symbol_table.pop_scope();
}
fn gather_interface_function(
interface_function: &InterfaceFunction,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
&fqn_context.resolve(interface_function.identifier().name()),
interface_function.identifier().name(),
true,
false,
Some(SourceDefinition::from_identifier(
interface_function.identifier(),
)),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
interface_function.identifier().name(),
interface_function.identifier().file_id(),
interface_function.identifier().range(),
"Type",
diagnostics,
);
}
symbol_table.push_scope(&format!(
"InterfaceFunctionScope {}",
interface_function.identifier().name()
));
gather_node(
interface_function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_function.parameters().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_function.return_type().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
symbol_table.pop_scope();
}
fn gather_interface_default_function(
interface_default_function: &InterfaceDefaultFunction,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
&fqn_context.resolve(interface_default_function.identifier().name()),
interface_default_function.identifier().name(),
true,
false,
Some(SourceDefinition::from_identifier(
interface_default_function.identifier(),
)),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
interface_default_function.identifier().name(),
interface_default_function.identifier().file_id(),
interface_default_function.identifier().range(),
"Function",
diagnostics,
);
}
symbol_table.push_scope(&format!(
"InterfaceDefaultFunctionScope {}",
interface_default_function.identifier().name()
));
gather_node(
interface_default_function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_default_function.parameters().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_default_function.return_type().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_default_function.function_body().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
symbol_table.pop_scope();
}
fn gather_interface_operator_function(
interface_operator_function: &InterfaceOperatorFunction,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
&fqn_context.resolve(interface_operator_function.operator().inner().name()),
interface_operator_function.operator().inner().name(),
true,
false,
Some(SourceDefinition::from_operator(
interface_operator_function.operator(),
)),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
interface_operator_function.operator().inner().name(),
interface_operator_function.operator().file_id(),
interface_operator_function.operator().range(),
"Function",
diagnostics,
);
}
symbol_table.push_scope(&format!(
"InterfaceOperatorFunctionScope {}",
interface_operator_function.operator().inner().name()
));
gather_node(
interface_operator_function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_operator_function.parameters().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_operator_function.return_type().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
symbol_table.pop_scope();
}
fn gather_interface_default_operator_function(
interface_default_operator_function: &InterfaceDefaultOperatorFunction,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let function_symbol = FunctionSymbol::without_parameters_or_return_type(
&fqn_context.resolve(
interface_default_operator_function
.operator()
.inner()
.name(),
),
interface_default_operator_function
.operator()
.inner()
.name(),
true,
false,
Some(SourceDefinition::from_operator(
interface_default_operator_function.operator(),
)),
);
if let Err(insert_error) = symbol_table.insert_function_symbol(function_symbol) {
handle_insert_error(
insert_error,
interface_default_operator_function
.operator()
.inner()
.name(),
interface_default_operator_function.operator().file_id(),
interface_default_operator_function.operator().range(),
"Function",
diagnostics,
);
}
symbol_table.push_scope(&format!(
"InterfaceDefaultOperatorFunctionScope {}",
interface_default_operator_function
.operator()
.inner()
.name()
));
gather_node(
interface_default_operator_function.generics().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_default_operator_function
.parameters()
.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_default_operator_function
.return_type()
.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
gather_node(
interface_default_operator_function
.function_body()
.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
symbol_table.pop_scope();
}
fn gather_function_body(
function_body: &FunctionBody,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
symbol_table.push_scope("FunctionBodyScope");
match function_body {
FunctionBody::FunctionAliasBody(alias_body) => {
gather_node(
alias_body.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
FunctionBody::FunctionEqualsBody(equals_body) => {
gather_node(
equals_body.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
FunctionBody::FunctionBlockBody(block_body) => {
gather_node(
block_body.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
}
symbol_table.pop_scope();
}
fn gather_member(
member: &Member,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
let member_symbol = ClassMemberSymbol::new(
member.is_public(),
member.is_mut(),
member.identifier().name(),
Some(SourceDefinition::from_identifier(member.identifier())),
);
if let Err(insert_error) = symbol_table.insert_class_member_symbol(member_symbol) {
handle_insert_error(
insert_error,
member.identifier().name(),
member.identifier().file_id(),
member.identifier().range(),
"Class Member",
diagnostics,
);
}
gather_node(
member.type_use().as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
fn gather_variable_declaration( fn gather_variable_declaration(
variable_declaration: &VariableDeclaration, variable_declaration: &VariableDeclaration,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
@ -530,3 +1026,12 @@ fn gather_variable_declaration(
); );
} }
} }
fn gather_variable_use(
variable_use: &mut VariableUse,
symbol_table: &mut SymbolTable,
fqn_context: &mut FqnContext,
diagnostics: &mut Vec<DmDiagnostic>,
) {
variable_use.set_scope_id(symbol_table.current_scope_id());
}

View File

@ -3,30 +3,37 @@ use std::fmt::{Debug, Formatter};
#[derive(Clone)] #[derive(Clone)]
pub struct ClassMemberSymbol { pub struct ClassMemberSymbol {
is_public: bool,
is_mut: bool,
declared_name: String, declared_name: String,
is_field: bool,
source_definition: Option<SourceDefinition>, source_definition: Option<SourceDefinition>,
} }
impl ClassMemberSymbol { impl ClassMemberSymbol {
pub fn new( pub fn new(
is_public: bool,
is_mut: bool,
declared_name: &str, declared_name: &str,
is_field: bool,
source_definition: Option<SourceDefinition>, source_definition: Option<SourceDefinition>,
) -> Self { ) -> Self {
Self { Self {
is_public,
is_mut,
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
is_field,
source_definition, source_definition,
} }
} }
pub fn declared_name(&self) -> &str { pub fn is_public(&self) -> bool {
&self.declared_name self.is_public
} }
pub fn is_field(&self) -> bool { pub fn is_mut(&self) -> bool {
self.is_field self.is_mut
}
pub fn declared_name(&self) -> &str {
&self.declared_name
} }
pub fn source_definition(&self) -> Option<&SourceDefinition> { pub fn source_definition(&self) -> Option<&SourceDefinition> {
@ -37,8 +44,9 @@ impl ClassMemberSymbol {
impl Debug for ClassMemberSymbol { impl Debug for ClassMemberSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ClassMemberSymbol") f.debug_struct("ClassMemberSymbol")
.field("is_public", &self.is_public)
.field("is_mut", &self.is_mut)
.field("declared_name", &self.declared_name) .field("declared_name", &self.declared_name)
.field("is_field", &self.is_field)
.field("source_definition", &self.source_definition) .field("source_definition", &self.source_definition)
.finish() .finish()
} }

View File

@ -1,7 +1,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::range::Range; use std::range::Range;
use std::rc::Rc; use std::rc::Rc;
use crate::ast::node::{Identifier, UseStatement}; use crate::ast::node::{Identifier, Operator, UseStatement};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SourceDefinition { pub struct SourceDefinition {
@ -17,14 +17,6 @@ impl SourceDefinition {
} }
} }
pub fn from_identifier_rc(identifier: Rc<RefCell<Identifier>>) -> Self {
let borrowed = identifier.borrow();
SourceDefinition {
file_id: borrowed.file_id(),
range: borrowed.range(),
}
}
pub fn from_use_statement(use_statement: &UseStatement) -> Self { pub fn from_use_statement(use_statement: &UseStatement) -> Self {
Self { Self {
file_id: use_statement.file_id(), file_id: use_statement.file_id(),
@ -32,6 +24,13 @@ impl SourceDefinition {
} }
} }
pub fn from_operator(operator: &Operator) -> Self {
Self {
file_id: operator.file_id(),
range: operator.range(),
}
}
pub fn file_id(&self) -> usize { pub fn file_id(&self) -> usize {
self.file_id self.file_id
} }

View File

@ -57,11 +57,11 @@ impl SymbolTable {
} }
fn current_scope(&self) -> &Scope { fn current_scope(&self) -> &Scope {
self.scopes.last().unwrap() &self.scopes[self.current_scope_id]
} }
fn current_scope_mut(&mut self) -> &mut Scope { fn current_scope_mut(&mut self) -> &mut Scope {
self.scopes.last_mut().unwrap() &mut self.scopes[self.current_scope_id]
} }
fn find_current_scope_concrete_use_symbol( fn find_current_scope_concrete_use_symbol(

View File

@ -127,7 +127,13 @@ macro_rules! write_symbols {
impl Display for Scope { impl Display for Scope {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "----Scope {} {}----", self.id(), self.debug_name())?; writeln!(
f,
"----Scope {} (p: {}) {}----",
self.id(),
self.parent().map(|parent_id| format!("{}", parent_id)).unwrap_or_else(|| "None".to_string()),
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());

View File

@ -1,6 +1,18 @@
# $schema: ./ast.schema.yaml # $schema: ./ast.schema.yaml
# Operators # Operators
Operator: Operator:
struct:
children:
- inner:
member:
rule: OperatorInner
- file_id:
special:
kind: file_id
- range:
special:
kind: range
OperatorInner:
leaf_enum: leaf_enum:
rules: rules:
- Or - Or
@ -429,6 +441,30 @@ PlatformFunction:
- identifier - identifier
- parameters - parameters
- return_type - return_type
PlatformOperatorFunction:
struct:
children:
- is_public:
member:
rule: Pub
build:
boolean:
on: rule_present
- platform_kw:
skip:
rule: Platform
- op_kw:
skip:
rule: Op
- generics:
member:
rule: GenericParameters
build:
node:
or_else_default: true
- operator
- parameters
- return_type
InterfaceFunction: InterfaceFunction:
struct: struct:
children: children:
@ -592,12 +628,8 @@ VariableDeclaration:
AssignmentStatement: AssignmentStatement:
struct: struct:
children: children:
- left: - l_value
member: - expression
rule: Expression
- right:
member:
rule: Expression
ExpressionStatement: ExpressionStatement:
struct: struct:
children: children:
@ -679,6 +711,30 @@ ForStatement:
skip: skip:
rule: End rule: End
# LValue
LValue:
struct:
children:
- variable_use
- suffixes:
vec:
rule: LValueSuffix
LValueSuffix:
tree_enum:
rules:
- ObjectProperty
- ObjectIndex
# VariableUse
VariableUse:
struct:
children:
- identifier
fields:
- scope_id:
kind: usize
optional: true
# Expressions # Expressions
Expression: Expression:
polymorphic_type: polymorphic_type:
@ -713,6 +769,9 @@ Expression:
- Literal: - Literal:
inner: inner:
kind: Literal kind: Literal
- VariableUse:
inner:
kind: VariableUse
- Fqn: - Fqn:
inner: inner:
kind: FullyQualifiedName kind: FullyQualifiedName
@ -1055,6 +1114,9 @@ PrimaryExpression:
- Literal: - Literal:
inner: inner:
kind: Literal kind: Literal
- VariableUse:
inner:
kind: VariableUse
- Fqn: - Fqn:
inner: inner:
kind: FullyQualifiedName kind: FullyQualifiedName

View File

@ -131,6 +131,10 @@ Index = { "[]" }
BorrowMut = { Borrow ~ Mut } BorrowMut = { Borrow ~ Mut }
Operator = { Operator = {
OperatorInner
}
OperatorInner = {
Or Or
| And | And
| EqualTo | EqualTo
@ -431,6 +435,16 @@ PlatformFunction = {
~ ReturnType ~ ReturnType
} }
PlatformOperatorFunction = {
Pub?
~ Platform
~ Op
~ GenericParameters?
~ Operator
~ Parameters
~ ReturnType
}
InterfaceFunction = { InterfaceFunction = {
Fn Fn
~ GenericParameters? ~ GenericParameters?
@ -528,7 +542,7 @@ VariableDeclaration = {
} }
AssignmentStatement = { AssignmentStatement = {
Expression LValue
~ "=" ~ "="
~ Expression ~ Expression
} }
@ -579,6 +593,24 @@ ForStatement = {
~ End ~ End
} }
// LValue
LValue = {
VariableUse
~ LValueSuffix*
}
LValueSuffix = {
ObjectProperty
| ObjectIndex
}
// Variable Use
VariableUse = {
Identifier
}
// Expressions // Expressions
Expression = { Expression = {
@ -727,6 +759,7 @@ ObjectIndex = {
PrimaryExpression = { PrimaryExpression = {
Literal Literal
| VariableUse
| FullyQualifiedName | FullyQualifiedName
| Closure | Closure
| ListExpression | ListExpression