diff --git a/ast-generator/src/ast_node/enum_ast_node.rs b/ast-generator/src/ast_node/enum_ast_node.rs index 7bf3ca7..f9fccc9 100644 --- a/ast-generator/src/ast_node/enum_ast_node.rs +++ b/ast-generator/src/ast_node/enum_ast_node.rs @@ -1,39 +1,50 @@ +use crate::spec::tree_enum_spec::{ + EnumRuleChildKind, TreeEnumBuildSpec, TreeEnumRule, +}; use convert_case::{Case, Casing}; -use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec}; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; 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 { let type_ident = format_ident!("{}", enum_spec.build()); let 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) => vec![ - #child_ident.as_node_ref() - ] - } - } - _ => quote! { - #type_ident::#rule_ident(_) => vec![] - } - } - }, - None => { - quote! { - #type_ident::#rule_ident => vec![] - } - } - } - }) + .map(|rule| make_match_arm(rule, &type_ident, false)) .collect::>(); - + let match_arms_mut = enum_spec + .rules() + .map(|rule| make_match_arm(rule, &type_ident, true)) + .collect::>(); + quote! { impl AstNode for #type_ident { fn children(&self) -> Vec { @@ -42,9 +53,19 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream { } } + fn children_mut(&mut self) -> Vec { + match self { + #(#match_arms_mut,)* + } + } + fn as_node_ref(&self) -> AstNodeRef { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&mut self) -> AstNodeRefMut { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/leaf_enum_ast_node.rs b/ast-generator/src/ast_node/leaf_enum_ast_node.rs index cdb0f02..324e8ec 100644 --- a/ast-generator/src/ast_node/leaf_enum_ast_node.rs +++ b/ast-generator/src/ast_node/leaf_enum_ast_node.rs @@ -1,6 +1,6 @@ +use crate::spec::leaf_enum_spec::LeafEnumBuildSpec; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use crate::spec::leaf_enum_spec::LeafEnumBuildSpec; pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream { let type_ident = format_ident!("{}", spec.build()); @@ -9,10 +9,18 @@ pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream { fn children(&self) -> Vec { vec![] } - + + fn children_mut(&mut self) -> Vec { + vec![] + } + fn as_node_ref(&self) -> AstNodeRef { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&mut self) -> AstNodeRefMut { + AstNodeRefMut::#type_ident(self) + } } } -} \ No newline at end of file +} diff --git a/ast-generator/src/ast_node/leaf_struct_ast_node.rs b/ast-generator/src/ast_node/leaf_struct_ast_node.rs index 20440b4..b6dee1f 100644 --- a/ast-generator/src/ast_node/leaf_struct_ast_node.rs +++ b/ast-generator/src/ast_node/leaf_struct_ast_node.rs @@ -9,10 +9,18 @@ pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream fn children(&self) -> Vec { vec![] } - + + fn children_mut(&mut self) -> Vec { + vec![] + } + fn as_node_ref(&self) -> AstNodeRef { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&mut self) -> AstNodeRefMut { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/mod.rs b/ast-generator/src/ast_node/mod.rs index b6d5264..1a6ea81 100644 --- a/ast-generator/src/ast_node/mod.rs +++ b/ast-generator/src/ast_node/mod.rs @@ -1,63 +1,47 @@ mod enum_ast_node; mod leaf_enum_ast_node; -mod struct_ast_node; mod leaf_struct_ast_node; -mod polymorphic_type_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::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::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::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 { match build_spec { - BuildSpec::Enum(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::LeafStruct(leaf_struct) => { - Some(make_leaf_struct_ast_node_impl(leaf_struct)) - } + BuildSpec::Enum(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::LeafStruct(leaf_struct) => Some(make_leaf_struct_ast_node_impl(leaf_struct)), BuildSpec::Production(_) => None, BuildSpec::NodeProduction(_) => None, BuildSpec::PolymorphicType(polymorphic_type) => { Some(make_polymorphic_type_ast_node_impl(polymorphic_type)) } - BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => { - Some(make_polymorphic_enum_loop_ast_node_impl(polymorphic_enum_loop)) - } + BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => Some( + make_polymorphic_enum_loop_ast_node_impl(polymorphic_enum_loop), + ), BuildSpec::PolymorphicPassThrough(_) => None, } } -pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option { +fn make_ast_enum_ident(build_spec: &BuildSpec) -> Option { match build_spec { - BuildSpec::Struct(struct_spec) => { - 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::LeafEnum(leaf_enum) => { - Some(format_ident!("{}", leaf_enum.build())) - } + BuildSpec::Struct(struct_spec) => 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::LeafEnum(leaf_enum) => Some(format_ident!("{}", leaf_enum.build())), BuildSpec::PolymorphicType(polymorphic_type) => { Some(format_ident!("{}", polymorphic_type.name())) - }, + } BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => { Some(format_ident!("{}", polymorphic_enum_loop.name())) } @@ -65,9 +49,20 @@ pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option { BuildSpec::Production(_) => None, BuildSpec::NodeProduction(_) => None, } - .map(|type_ident| { - quote! { - #type_ident(&'a #type_ident) - } - }) -} \ No newline at end of file +} + +pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option { + 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 { + make_ast_enum_ident(build_spec).map(|type_ident| { + quote! { + #type_ident(&'a mut #type_ident) + } + }) +} diff --git a/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs b/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs index 01e8fde..efeeaec 100644 --- a/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs +++ b/ast-generator/src/ast_node/polymorphic_enum_loop_ast_node.rs @@ -4,6 +4,33 @@ use crate::spec::polymorphic_enum_loop_spec::{ use proc_macro2::TokenStream; 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( spec: &PolymorphicEnumLoopBuildSpec, ) -> TokenStream { @@ -18,19 +45,12 @@ pub fn make_polymorphic_enum_loop_ast_node_impl( .unwrap(); let child_adders = build_rule .children() - .map(|child| { - let child_ident = match child { - PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => { - format_ident!("{}", use_current.name()) - } - PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => { - format_ident!("{}", on_each.name()) - } - }; - quote! { - children.push(self.#child_ident().as_node_ref()) - } - }) + .map(|child| make_child_adder(child, false)) + .collect::>(); + + let child_adders_mut = build_rule + .children() + .map(|child| make_child_adder(child, true)) .collect::>(); quote! { @@ -41,9 +61,19 @@ pub fn make_polymorphic_enum_loop_ast_node_impl( children } + fn children_mut(&mut self) -> Vec { + let mut children: Vec = vec![]; + #(#child_adders_mut;)* + children + } + fn as_node_ref(&self) -> AstNodeRef { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&mut self) -> AstNodeRefMut { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/polymorphic_type_ast_node.rs b/ast-generator/src/ast_node/polymorphic_type_ast_node.rs index d698160..95e129a 100644 --- a/ast-generator/src/ast_node/polymorphic_type_ast_node.rs +++ b/ast-generator/src/ast_node/polymorphic_type_ast_node.rs @@ -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 proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; 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 { let type_ident = format_ident!("{}", spec.name()); let match_arms = 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) => vec![#child_ident.as_node_ref()] - } - }) + .map(|variant| make_match_arm(variant, &type_ident, false)) + .collect::>(); + + let match_arms_mut = spec + .variants() + .map(|variant| make_match_arm(variant, &type_ident, true)) .collect::>(); quote! { @@ -24,9 +41,19 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T } } + fn children_mut(&mut self) -> Vec { + match self { + #(#match_arms_mut,)* + } + } + fn as_node_ref(&self) -> AstNodeRef { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&mut self) -> AstNodeRefMut { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/ast_node/struct_ast_node.rs b/ast-generator/src/ast_node/struct_ast_node.rs index a6d9aae..fddd742 100644 --- a/ast-generator/src/ast_node/struct_ast_node.rs +++ b/ast-generator/src/ast_node/struct_ast_node.rs @@ -2,43 +2,69 @@ use crate::spec::struct_spec::{MemberChildBuild, StructChild, StructSpec, VecChi use proc_macro2::TokenStream; use quote::{format_ident, quote}; +fn make_child_adder(child: &StructChild, is_mut: bool) -> Option { + 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 { let type_ident = format_ident!("{}", spec.build()); let child_adders = spec .children() - .map(|child| match child { - StructChild::SkipChild(_) => None, - StructChild::VecChild(vec_child) => match vec_child.build() { - VecChildBuild::String(_) => None, - VecChildBuild::Node(_) => { - let child_ident = format_ident!("{}", vec_child.name()); - let children_stream = quote! { - for child in self.#child_ident().map(AstNode::as_node_ref) { - 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, - }) + .map(|child| make_child_adder(child, false)) + .filter(Option::is_some) + .map(Option::unwrap) + .collect::>(); + + let child_adders_mut = spec + .children() + .map(|child| make_child_adder(child, true)) .filter(Option::is_some) .map(Option::unwrap) .collect::>(); @@ -51,9 +77,19 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream { children } + fn children_mut(&mut self) -> Vec { + let mut children: Vec = vec![]; + #(#child_adders_mut;)* + children + } + fn as_node_ref(&self) -> AstNodeRef { AstNodeRef::#type_ident(&self) } + + fn as_node_ref_mut(&mut self) -> AstNodeRefMut { + AstNodeRefMut::#type_ident(self) + } } } } diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index b013867..860f169 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -6,7 +6,7 @@ mod spec; mod type_gen; 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::deserialize::deserialize_yaml_spec; use crate::pretty_print::make_pretty_print_impl; @@ -165,6 +165,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { .map(Option::unwrap) .collect::>(); + 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::>(); + let combined = quote! { use crate::ast::node::*; @@ -172,10 +179,18 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { #(#ast_enum_members,)* } + pub enum AstNodeRefMut<'a> { + #(#ast_enum_members_mut,)* + } + pub trait AstNode { fn children(&self) -> Vec; + fn children_mut(&mut self) -> Vec; + fn as_node_ref(&self) -> AstNodeRef; + + fn as_node_ref_mut(&mut self) -> AstNodeRefMut; } #(#impls)* diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index 8b90cc9..2ae6ee1 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -3,7 +3,7 @@ use crate::ast::node::{ Class, CompilationUnit, Function, FunctionBody, Identifier, Interface, InterfaceDefaultFunction, InterfaceDefaultOperatorFunction, InterfaceFunction, InterfaceOperatorFunction, Member, Module, Namespace, OperatorFunction, PlatformFunction, - PlatformOperatorFunction, Statement, UseStatement, UseStatementSuffix, VariableDeclaration, + PlatformOperatorFunction, UseStatement, UseStatementSuffix, VariableDeclaration, VariableUse, }; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::fqn_context::FqnContext; @@ -211,7 +211,7 @@ fn gather_node( } AstNodeRef::Statement(statement) => { gather_node_children(statement, symbol_table, fqn_context, diagnostics); - }, + } AstNodeRef::VariableDeclaration(variable_declaration) => { gather_variable_declaration( variable_declaration, @@ -228,9 +228,11 @@ fn gather_node( AstNodeRef::IfElse(_) => {} AstNodeRef::WhileStatement(_) => {} AstNodeRef::ForStatement(_) => {} - AstNodeRef::LValue(_) => {}, - AstNodeRef::LValueSuffix(_) => {}, - AstNodeRef::VariableUse(_) => {}, + AstNodeRef::LValue(_) => {} + AstNodeRef::LValueSuffix(_) => {} + AstNodeRef::VariableUse(variable_use) => { + gather_variable_use(variable_use, symbol_table, fqn_context, diagnostics); + } AstNodeRef::Expression(_) => {} AstNodeRef::TernaryExpression(_) => {} AstNodeRef::TernaryRhs(_) => {} @@ -1024,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, +) { + variable_use.set_scope_id(symbol_table.current_scope_id()); +}