Refactor struct type.
This commit is contained in:
parent
1565abace5
commit
2986bbe37e
@ -1,464 +1,33 @@
|
|||||||
use crate::spec::{
|
mod enum_type;
|
||||||
AlternativeAction, AlternativeChild, BooleanChildToBuild, BuildSpec, EnumBuildSpec,
|
mod leaf_enum_type;
|
||||||
EnumRuleChildKind, LeafEnumBuildSpec, LeafStructBuildSpec, LeafStructMemberKind,
|
mod leaf_struct_type;
|
||||||
MemberChildToBuild, NodeChildToBuild, PolymorphicBuildBuildSpec, PolymorphicTypeBuildSpec,
|
mod polymorphic_type_type;
|
||||||
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
|
mod struct_type;
|
||||||
};
|
|
||||||
use proc_macro2::{Ident, TokenStream};
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
|
|
||||||
fn make_polymorphic_build_type(build_spec: &PolymorphicBuildBuildSpec) -> TokenStream {
|
use crate::spec::BuildSpec;
|
||||||
let alternative_action = build_spec
|
use crate::type_gen::enum_type::make_enum_type;
|
||||||
.alternatives()
|
use crate::type_gen::leaf_enum_type::make_leaf_enum_type;
|
||||||
.find(|alternative| {
|
use crate::type_gen::leaf_struct_type::make_leaf_struct_type;
|
||||||
if let AlternativeAction::Build(_) = alternative.action() {
|
use crate::type_gen::polymorphic_type_type::make_polymorphic_type_type;
|
||||||
true
|
use crate::type_gen::struct_type::make_struct_type;
|
||||||
} else {
|
use proc_macro2::TokenStream;
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let alternative_build =
|
|
||||||
if let AlternativeAction::Build(alternative_build) = alternative_action.action() {
|
|
||||||
alternative_build
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let annotated_members = alternative_build
|
|
||||||
.children()
|
|
||||||
.map(|child| match child {
|
|
||||||
AlternativeChild::Skip => None,
|
|
||||||
AlternativeChild::Build(build_child) => {
|
|
||||||
let child_name_ident = format_ident!("{}", build_child.name());
|
|
||||||
let type_ident = format_ident!("{}", build_child.kind());
|
|
||||||
Some(quote! {
|
|
||||||
#child_name_ident: Box<#type_ident>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(Option::is_some)
|
|
||||||
.map(Option::unwrap)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let initializers = alternative_build
|
|
||||||
.children()
|
|
||||||
.map(|child| match child {
|
|
||||||
AlternativeChild::Skip => None,
|
|
||||||
AlternativeChild::Build(build_child) => Some(format_ident!("{}", build_child.name())),
|
|
||||||
})
|
|
||||||
.filter(Option::is_some)
|
|
||||||
.map(Option::unwrap)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let accessors = alternative_build
|
|
||||||
.children()
|
|
||||||
.map(|child| match child {
|
|
||||||
AlternativeChild::Skip => None,
|
|
||||||
AlternativeChild::Build(build_child) => {
|
|
||||||
let child_ident = format_ident!("{}", build_child.name());
|
|
||||||
let child_ident_mut = format_ident!("{}_mut", build_child.name());
|
|
||||||
let child_type_ident = format_ident!("{}", build_child.kind());
|
|
||||||
Some(quote! {
|
|
||||||
pub fn #child_ident(&self) -> &#child_type_ident {
|
|
||||||
&self.#child_ident
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn #child_ident_mut(&mut self) -> &mut #child_type_ident {
|
|
||||||
&mut self.#child_ident
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let type_ident = format_ident!("{}", build_spec.name());
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
pub struct #type_ident {
|
|
||||||
#(#annotated_members),*
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #type_ident {
|
|
||||||
pub fn new(#(#annotated_members),*) -> Self {
|
|
||||||
Self {
|
|
||||||
#(#initializers),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#(#accessors)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_polymorphic_type_type(build_spec: &PolymorphicTypeBuildSpec) -> TokenStream {
|
|
||||||
let members = build_spec
|
|
||||||
.enum_members()
|
|
||||||
.map(|enum_member| {
|
|
||||||
let member_ident = format_ident!("{}", enum_member.name());
|
|
||||||
let inner_type_ident = format_ident!("{}", enum_member.inner_kind());
|
|
||||||
quote! {
|
|
||||||
#member_ident(#inner_type_ident)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let type_name_ident = format_ident!("{}", build_spec.name());
|
|
||||||
quote! {
|
|
||||||
pub enum #type_name_ident {
|
|
||||||
#(#members),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
|
|
||||||
let children: Vec<TokenStream> = build_spec
|
|
||||||
.rules()
|
|
||||||
.map(|enum_rule| {
|
|
||||||
let member_name_ident = format_ident!("{}", enum_rule.rule());
|
|
||||||
if let Some(enum_rule_child) = enum_rule.child() {
|
|
||||||
let child_type_ident = match enum_rule_child.kind() {
|
|
||||||
EnumRuleChildKind::Node(node_child) => {
|
|
||||||
format_ident!("{}", node_child.build())
|
|
||||||
}
|
|
||||||
EnumRuleChildKind::Int => format_ident!("i32"),
|
|
||||||
EnumRuleChildKind::Long => format_ident!("i64"),
|
|
||||||
EnumRuleChildKind::Double => format_ident!("f64"),
|
|
||||||
EnumRuleChildKind::USize => format_ident!("usize"),
|
|
||||||
EnumRuleChildKind::String => format_ident!("String"),
|
|
||||||
EnumRuleChildKind::Boolean => format_ident!("bool"),
|
|
||||||
};
|
|
||||||
quote! {
|
|
||||||
#member_name_ident(#child_type_ident)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
#member_name_ident
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let type_name_ident = format_ident!("{}", build_spec.build());
|
|
||||||
quote! {
|
|
||||||
pub enum #type_name_ident {
|
|
||||||
#(#children),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_leaf_enum_type(build_spec: &LeafEnumBuildSpec) -> TokenStream {
|
|
||||||
let type_name_ident = format_ident!("{}", build_spec.build());
|
|
||||||
let children = build_spec
|
|
||||||
.rules()
|
|
||||||
.map(|leaf_enum_rule| {
|
|
||||||
let rule_name_ident = format_ident!("{}", leaf_enum_rule.rule());
|
|
||||||
quote! {
|
|
||||||
#rule_name_ident
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
pub enum #type_name_ident {
|
|
||||||
#(#children),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_vec_child(
|
|
||||||
vec_child: &VecChild,
|
|
||||||
member_names: &mut Vec<Ident>,
|
|
||||||
annotated_members: &mut Vec<TokenStream>,
|
|
||||||
member_args: &mut Vec<TokenStream>,
|
|
||||||
accessors: &mut Vec<TokenStream>,
|
|
||||||
) {
|
|
||||||
let (child_ident, child_ident_mut) = (
|
|
||||||
format_ident!("{}", vec_child.name()),
|
|
||||||
format_ident!("{}_mut", vec_child.name()),
|
|
||||||
);
|
|
||||||
let child_type_ident = match vec_child.build() {
|
|
||||||
VecChildToBuild::Node(vec_node_child) => format_ident!("{}", vec_node_child.build()),
|
|
||||||
VecChildToBuild::String => format_ident!("{}", "String"),
|
|
||||||
};
|
|
||||||
|
|
||||||
member_names.push(child_ident.clone());
|
|
||||||
|
|
||||||
match vec_child.build() {
|
|
||||||
VecChildToBuild::Node(_) => {
|
|
||||||
annotated_members.push(quote! {
|
|
||||||
#child_ident: Vec<Box<#child_type_ident>>
|
|
||||||
});
|
|
||||||
member_args.push(quote! {
|
|
||||||
#child_ident: Vec<Box<#child_type_ident>>
|
|
||||||
});
|
|
||||||
}
|
|
||||||
VecChildToBuild::String => {
|
|
||||||
annotated_members.push(quote! {
|
|
||||||
#child_ident: Vec<String>
|
|
||||||
});
|
|
||||||
member_args.push(quote! {
|
|
||||||
#child_ident: Vec<String>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match vec_child.build() {
|
|
||||||
VecChildToBuild::Node(_) => {
|
|
||||||
accessors.push(quote! {
|
|
||||||
pub fn #child_ident(&self) -> impl Iterator<Item = &#child_type_ident> {
|
|
||||||
self.#child_ident.iter().map(Box::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn #child_ident_mut(&mut self) -> impl Iterator<Item = &mut #child_type_ident> {
|
|
||||||
self.#child_ident.iter_mut().map(Box::as_mut)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
VecChildToBuild::String => accessors.push(quote! {
|
|
||||||
pub fn #child_ident(&self) -> impl Iterator<Item = &str> {
|
|
||||||
self.#child_ident.iter().map(String::as_str)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_node_child(
|
|
||||||
name: &str,
|
|
||||||
node_child: &NodeChildToBuild,
|
|
||||||
member_names: &mut Vec<Ident>,
|
|
||||||
annotated_members: &mut Vec<TokenStream>,
|
|
||||||
member_args: &mut Vec<TokenStream>,
|
|
||||||
accessors: &mut Vec<TokenStream>,
|
|
||||||
) {
|
|
||||||
let child_ident = format_ident!("{}", name);
|
|
||||||
let child_ident_mut = format_ident!("{}_mut", name);
|
|
||||||
let child_type_ident = format_ident!("{}", node_child.kind());
|
|
||||||
|
|
||||||
member_names.push(child_ident.clone());
|
|
||||||
|
|
||||||
if node_child.optional() {
|
|
||||||
annotated_members.push(quote! {
|
|
||||||
#child_ident: Option<Box<#child_type_ident>>
|
|
||||||
});
|
|
||||||
member_args.push(quote! {
|
|
||||||
#child_ident: Option<Box<#child_type_ident>>
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
annotated_members.push(quote! {
|
|
||||||
#child_ident: Box<#child_type_ident>
|
|
||||||
});
|
|
||||||
member_args.push(quote! {
|
|
||||||
#child_ident: Box<#child_type_ident>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if node_child.optional() {
|
|
||||||
accessors.push(quote! {
|
|
||||||
pub fn #child_ident(&self) -> Option<&#child_type_ident> {
|
|
||||||
if let Some(#child_ident) = &self.#child_ident {
|
|
||||||
Some(#child_ident.as_ref())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn #child_ident_mut(&mut self) -> Option<&mut #child_type_ident> {
|
|
||||||
if let Some(#child_ident) = &mut self.#child_ident {
|
|
||||||
Some(#child_ident.as_mut())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
accessors.push(quote! {
|
|
||||||
pub fn #child_ident(&self) -> &#child_type_ident {
|
|
||||||
self.#child_ident.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn #child_ident_mut(&mut self) -> &mut #child_type_ident {
|
|
||||||
self.#child_ident.as_mut()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_boolean_child(
|
|
||||||
single_boolean_child: &BooleanChildToBuild,
|
|
||||||
member_names: &mut Vec<Ident>,
|
|
||||||
annotated_members: &mut Vec<TokenStream>,
|
|
||||||
member_args: &mut Vec<TokenStream>,
|
|
||||||
accessors: &mut Vec<TokenStream>,
|
|
||||||
) {
|
|
||||||
let child_ident = format_ident!("{}", single_boolean_child.name());
|
|
||||||
member_names.push(child_ident.clone());
|
|
||||||
annotated_members.push(quote! {
|
|
||||||
#child_ident: bool
|
|
||||||
});
|
|
||||||
member_args.push(quote! {
|
|
||||||
#child_ident: bool
|
|
||||||
});
|
|
||||||
accessors.push(quote! {
|
|
||||||
pub fn #child_ident(&self) -> bool {
|
|
||||||
self.#child_ident
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_struct_type(build_spec: &StructBuildSpec) -> TokenStream {
|
|
||||||
let mut member_names: Vec<Ident> = vec![];
|
|
||||||
let mut annotated_members: Vec<TokenStream> = vec![];
|
|
||||||
let mut member_args: Vec<TokenStream> = vec![];
|
|
||||||
let mut accessors: Vec<TokenStream> = vec![];
|
|
||||||
|
|
||||||
for child_spec in build_spec.children() {
|
|
||||||
match child_spec {
|
|
||||||
StructChildSpec::SkipChild(_) => {}
|
|
||||||
StructChildSpec::VecChild(vec_child) => {
|
|
||||||
handle_vec_child(
|
|
||||||
vec_child,
|
|
||||||
&mut member_names,
|
|
||||||
&mut annotated_members,
|
|
||||||
&mut member_args,
|
|
||||||
&mut accessors,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
StructChildSpec::MemberChild(member_child) => {
|
|
||||||
match member_child.build() {
|
|
||||||
MemberChildToBuild::Node(node_child) => {
|
|
||||||
handle_node_child(
|
|
||||||
member_child.name(),
|
|
||||||
node_child,
|
|
||||||
&mut member_names,
|
|
||||||
&mut annotated_members,
|
|
||||||
&mut member_args,
|
|
||||||
&mut accessors,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
MemberChildToBuild::Boolean(boolean_child) => {
|
|
||||||
handle_boolean_child(
|
|
||||||
boolean_child,
|
|
||||||
&mut member_names,
|
|
||||||
&mut annotated_members,
|
|
||||||
&mut member_args,
|
|
||||||
&mut accessors,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let type_ident = format_ident!("{}", build_spec.build());
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
pub struct #type_ident {
|
|
||||||
#(#annotated_members),*
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #type_ident {
|
|
||||||
pub fn new(#(#annotated_members),*) -> Self {
|
|
||||||
Self {
|
|
||||||
#(#member_names),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#(#accessors)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_leaf_struct_type(build_spec: &LeafStructBuildSpec) -> TokenStream {
|
|
||||||
let type_ident = format_ident!("{}", build_spec.build());
|
|
||||||
|
|
||||||
let annotated_members = build_spec
|
|
||||||
.members()
|
|
||||||
.map(|member| {
|
|
||||||
let name_ident = format_ident!("{}", member.name());
|
|
||||||
let type_ident = match member.kind() {
|
|
||||||
LeafStructMemberKind::String => format_ident!("{}", "String"),
|
|
||||||
};
|
|
||||||
quote! {
|
|
||||||
#name_ident: #type_ident
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let member_args = build_spec.members().map(|member| {
|
|
||||||
let name_ident = format_ident!("{}", member.name());
|
|
||||||
let type_stream = match member.kind() {
|
|
||||||
LeafStructMemberKind::String => {
|
|
||||||
quote! { &str }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
quote! {
|
|
||||||
#name_ident: #type_stream
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let initializers = build_spec
|
|
||||||
.members()
|
|
||||||
.map(|leaf_struct_member| {
|
|
||||||
let member_ident = format_ident!("{}", leaf_struct_member.name());
|
|
||||||
match leaf_struct_member.kind() {
|
|
||||||
LeafStructMemberKind::String => {
|
|
||||||
quote! {
|
|
||||||
#member_ident: #member_ident.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let accessors = build_spec
|
|
||||||
.members()
|
|
||||||
.map(|member| {
|
|
||||||
let name_ident = format_ident!("{}", member.name());
|
|
||||||
match member.kind() {
|
|
||||||
LeafStructMemberKind::String => {
|
|
||||||
quote! {
|
|
||||||
pub fn #name_ident(&self) -> &str {
|
|
||||||
&self.#name_ident
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
pub struct #type_ident {
|
|
||||||
#(#annotated_members),*
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #type_ident {
|
|
||||||
pub fn new(#(#member_args),*) -> Self {
|
|
||||||
Self {
|
|
||||||
#(#initializers),*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#(#accessors)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
|
pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
|
||||||
match build_spec {
|
match build_spec {
|
||||||
BuildSpec::Enum(enum_build_spec) => Some(make_enum_type(enum_build_spec)),
|
|
||||||
BuildSpec::LeafEnum(leaf_enum_build_spec) => {
|
|
||||||
Some(make_leaf_enum_type(leaf_enum_build_spec))
|
|
||||||
}
|
|
||||||
BuildSpec::Struct(struct_build_spec) => Some(make_struct_type(struct_build_spec)),
|
BuildSpec::Struct(struct_build_spec) => Some(make_struct_type(struct_build_spec)),
|
||||||
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
|
BuildSpec::LeafStruct(leaf_struct_build_spec) => {
|
||||||
Some(make_leaf_struct_type(leaf_struct_build_spec))
|
Some(make_leaf_struct_type(leaf_struct_build_spec))
|
||||||
}
|
}
|
||||||
|
BuildSpec::Enum(enum_build_spec) => Some(make_enum_type(enum_build_spec)),
|
||||||
|
BuildSpec::LeafEnum(leaf_enum_build_spec) => {
|
||||||
|
Some(make_leaf_enum_type(leaf_enum_build_spec))
|
||||||
|
}
|
||||||
BuildSpec::Production(_) => None,
|
BuildSpec::Production(_) => None,
|
||||||
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
BuildSpec::NodeProduction(_) => None,
|
||||||
|
BuildSpec::PolymorphicType(polymorphic_build_spec) => {
|
||||||
Some(make_polymorphic_type_type(polymorphic_build_spec))
|
Some(make_polymorphic_type_type(polymorphic_build_spec))
|
||||||
}
|
}
|
||||||
BuildSpec::PolymorphicBuild(polymorphic_build_build_spec) => {
|
BuildSpec::PolymorphicEnumLoop(_) => None,
|
||||||
Some(make_polymorphic_build_type(polymorphic_build_build_spec))
|
BuildSpec::PolymorphicPassThrough(_) => None,
|
||||||
}
|
|
||||||
BuildSpec::PolymorphicEnum(_) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
193
ast-generator/src/type_gen/struct_type.rs
Normal file
193
ast-generator/src/type_gen/struct_type.rs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
use crate::spec::struct_spec::{MemberChild, MemberChildBuild, StructChild, StructSpec, VecChild, VecChildBuild};
|
||||||
|
use proc_macro2::{Ident, TokenStream};
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
|
fn make_vec_child_accessors(vec_child: &VecChild) -> TokenStream {
|
||||||
|
let child_ident = format_ident!("{}", vec_child.name());
|
||||||
|
match vec_child.build() {
|
||||||
|
VecChildBuild::String(_) => {
|
||||||
|
quote! {
|
||||||
|
pub fn #child_ident(&self) -> impl Iterator<Item = &str> {
|
||||||
|
self.#child_ident.iter().map(String::as_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
VecChildBuild::Node(vec_child_node_build) => {
|
||||||
|
let child_type_ident = format_ident!("{}", vec_child_node_build.kind());
|
||||||
|
let child_ident_mut = format_ident!("{}_mut", vec_child.name());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
pub fn #child_ident(&self) -> impl Iterator<Item = &#child_type_ident> {
|
||||||
|
self.#child_ident.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn #child_ident_mut(&mut self) -> impl Iterator<Item = &mut child_type_ident> {
|
||||||
|
self.#child_ident.iter().map(Box::as_mut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_member_child_accessors(member_child: &MemberChild) -> TokenStream {
|
||||||
|
let child_ident = format_ident!("{}", member_child.name());
|
||||||
|
match member_child.build() {
|
||||||
|
MemberChildBuild::Node(node_member_build) => {
|
||||||
|
let return_type_ident = format_ident!("{}", node_member_build.kind());
|
||||||
|
let child_ident_mut = format_ident!("{}_mut", member_child.name());
|
||||||
|
|
||||||
|
if member_child.optional() {
|
||||||
|
quote! {
|
||||||
|
pub fn #child_ident(&self) -> Option<&#return_type_ident> {
|
||||||
|
if let Some(#child_ident) = &self.#child_ident {
|
||||||
|
Some(#child_ident.as_ref())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn #child_ident_mut(&mut self) -> Option<&mut #return_type_ident> {
|
||||||
|
if let Some(#child_ident) = &mut self.#child_ident {
|
||||||
|
Some(#child_ident.as_mut())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
pub fn #child_ident(&self) -> &#return_type_ident {
|
||||||
|
self.#child_ident.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn #child_ident_mut(&mut self) -> &mut #return_type_ident {
|
||||||
|
self.#child_ident.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MemberChildBuild::Boolean(_) => {
|
||||||
|
quote! {
|
||||||
|
pub fn #child_ident(&self) -> bool {
|
||||||
|
self.#child_ident
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_accessors(child: &StructChild) -> Option<TokenStream> {
|
||||||
|
match child {
|
||||||
|
StructChild::SkipChild(_) => None,
|
||||||
|
StructChild::VecChild(vec_child) => {
|
||||||
|
Some(make_vec_child_accessors(vec_child))
|
||||||
|
}
|
||||||
|
StructChild::MemberChild(member_child) => {
|
||||||
|
Some(make_member_child_accessors(member_child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_member_ident(child: &StructChild) -> Option<Ident> {
|
||||||
|
match child {
|
||||||
|
StructChild::SkipChild(_) => None,
|
||||||
|
StructChild::VecChild(vec_child) => {
|
||||||
|
Some(format_ident!("{}", vec_child.name()))
|
||||||
|
},
|
||||||
|
StructChild::MemberChild(member_child) => {
|
||||||
|
Some(format_ident!("{}", member_child.name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_vec_child_annotated_member(vec_child: &VecChild) -> TokenStream {
|
||||||
|
let child_ident = format_ident!("{}", vec_child.name());
|
||||||
|
let type_stream = match vec_child.build() {
|
||||||
|
VecChildBuild::String(_) => quote! { String },
|
||||||
|
VecChildBuild::Node(vec_child_node_build) => {
|
||||||
|
let type_ident = format_ident!("{}", vec_child_node_build.kind());
|
||||||
|
quote! { Box<#type_ident> }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#child_ident: Vec<#type_stream>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_member_child_type_ident(member_child: &MemberChild) -> TokenStream {
|
||||||
|
match member_child.build() {
|
||||||
|
MemberChildBuild::Node(node_member_build) => {
|
||||||
|
let type_ident = format_ident!("{}", node_member_build.kind());
|
||||||
|
quote! { #type_ident }
|
||||||
|
},
|
||||||
|
MemberChildBuild::Boolean(_) => {
|
||||||
|
quote! { bool }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_member_child_annotated_member(member_child: &MemberChild) -> TokenStream {
|
||||||
|
let child_name_ident = format_ident!("{}", member_child.name());
|
||||||
|
let type_ident = make_member_child_type_ident(member_child);
|
||||||
|
let type_stream = if member_child.optional() {
|
||||||
|
quote! { Option<#type_ident> }
|
||||||
|
} else {
|
||||||
|
type_ident
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#child_name_ident: #type_stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_annotated_member(child: &StructChild) -> Option<TokenStream> {
|
||||||
|
match child {
|
||||||
|
StructChild::SkipChild(_) => None,
|
||||||
|
StructChild::VecChild(vec_child) => Some(make_vec_child_annotated_member(vec_child)),
|
||||||
|
StructChild::MemberChild(member_child) => Some(make_member_child_annotated_member(member_child)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
|
||||||
|
let type_ident = format_ident!("{}", build_spec.build());
|
||||||
|
let annotated_members = build_spec.children()
|
||||||
|
.map(|child| {
|
||||||
|
make_annotated_member(child)
|
||||||
|
})
|
||||||
|
.filter(Option::is_some)
|
||||||
|
.map(Option::unwrap)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let member_names = build_spec.children()
|
||||||
|
.map(|child| {
|
||||||
|
make_member_ident(child)
|
||||||
|
})
|
||||||
|
.filter(Option::is_some)
|
||||||
|
.map(Option::unwrap)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let accessors = build_spec.children()
|
||||||
|
.map(|child| {
|
||||||
|
make_accessors(child)
|
||||||
|
})
|
||||||
|
.filter(Option::is_some)
|
||||||
|
.map(Option::unwrap)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
pub struct #type_ident {
|
||||||
|
#(#annotated_members),*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #type_ident {
|
||||||
|
pub fn new(#(#annotated_members),*) -> Self {
|
||||||
|
Self {
|
||||||
|
#(#member_names),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#(#accessors)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user