290 lines
10 KiB
Rust
290 lines
10 KiB
Rust
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
|
|
use crate::spec::leaf_struct_spec::{LeafStructBuildSpec, LeafStructMemberKind};
|
|
use crate::spec::polymorphic_enum_loop_spec::{
|
|
PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopRule, PolymorphicEnumLoopRuleBuildChild,
|
|
};
|
|
use crate::spec::polymorphic_type_spec::PolymorphicTypeBuildSpec;
|
|
use crate::spec::struct_spec::{MemberChildBuild, StructChild, StructSpec, VecChildBuild};
|
|
use crate::spec::tree_enum_spec::{EnumRuleChildKind, TreeEnumBuildSpec};
|
|
use crate::spec::BuildSpec;
|
|
use convert_case::{Case, Casing};
|
|
use proc_macro2::TokenStream;
|
|
use quote::{format_ident, quote};
|
|
|
|
fn make_result() -> TokenStream {
|
|
quote! { std::fmt::Result }
|
|
}
|
|
|
|
fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
|
|
let type_ident = format_ident!("{}", spec.name());
|
|
let type_string = spec.name();
|
|
|
|
let build = spec
|
|
.rules()
|
|
.find(|rule| match rule {
|
|
PolymorphicEnumLoopRule::Build(_) => true,
|
|
_ => false,
|
|
})
|
|
.map(|rule| match rule {
|
|
PolymorphicEnumLoopRule::Build(build) => build,
|
|
_ => unreachable!(),
|
|
})
|
|
.unwrap();
|
|
|
|
let child_print_statements = build
|
|
.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! {
|
|
self.#child_ident().pretty_print(writer)?;
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let result = make_result();
|
|
|
|
quote! {
|
|
impl PrettyPrint for #type_ident {
|
|
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
|
writer.writeln_indented(#type_string)?;
|
|
writer.increase_indent();
|
|
#(#child_print_statements)*
|
|
writer.decrease_indent();
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn make_polymorphic_type_p2_impl(spec: &PolymorphicTypeBuildSpec) -> TokenStream {
|
|
let type_ident = format_ident!("{}", spec.name());
|
|
let child_matchers = spec
|
|
.variants()
|
|
.map(|member| {
|
|
let enum_member_ident = format_ident!("{}", member.name());
|
|
let inner_name = format_ident!("{}", member.inner_kind().to_case(Case::Snake));
|
|
quote! {
|
|
#type_ident::#enum_member_ident(#inner_name) => #inner_name.pretty_print(writer)
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let result = make_result();
|
|
|
|
quote! {
|
|
impl PrettyPrint for #type_ident {
|
|
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
|
match self {
|
|
#(#child_matchers,)*
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn make_leaf_enum_p2_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
|
|
let type_ident = format_ident!("{}", spec.build());
|
|
let child_matchers = spec
|
|
.rules()
|
|
.map(|rule| {
|
|
let enum_variant_ident = format_ident!("{}", rule);
|
|
let name_str = rule;
|
|
quote! {
|
|
#type_ident::#enum_variant_ident => writer.writeln_indented(#name_str)
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let result = make_result();
|
|
|
|
quote! {
|
|
impl PrettyPrint for #type_ident {
|
|
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
|
match self {
|
|
#(#child_matchers,)*
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn make_tree_enum_p2_impl(spec: &TreeEnumBuildSpec) -> TokenStream {
|
|
let type_ident = format_ident!("{}", spec.build());
|
|
let type_str = spec.build();
|
|
|
|
let child_matchers = spec
|
|
.rules()
|
|
.map(|rule| {
|
|
let enum_variant_ident = format_ident!("{}", rule.rule());
|
|
if let Some(child) = rule.child() {
|
|
match child.kind() {
|
|
EnumRuleChildKind::Node(node_child) => {
|
|
let child_name_ident =
|
|
format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
|
|
Some(quote! {
|
|
#type_ident::#enum_variant_ident(#child_name_ident) => {
|
|
#child_name_ident.pretty_print(writer)?;
|
|
}
|
|
})
|
|
}
|
|
_ => None,
|
|
}
|
|
} else {
|
|
let variant_str = rule.rule();
|
|
Some(quote! {
|
|
#type_ident::#enum_variant_ident => writer.writeln_indented(#variant_str)?
|
|
})
|
|
}
|
|
})
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let result = make_result();
|
|
|
|
quote! {
|
|
impl PrettyPrint for #type_ident {
|
|
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
|
writer.writeln_indented(#type_str)?;
|
|
writer.increase_indent();
|
|
match self {
|
|
#(#child_matchers,)*
|
|
_ => {}
|
|
}
|
|
writer.decrease_indent();
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn make_leaf_struct_p2_impl(leaf_struct_build_spec: &LeafStructBuildSpec) -> TokenStream {
|
|
let type_ident = format_ident!("{}", leaf_struct_build_spec.build());
|
|
let member_formatters = leaf_struct_build_spec
|
|
.members()
|
|
.map(|member| match member.kind() {
|
|
LeafStructMemberKind::String => Some("{}"),
|
|
LeafStructMemberKind::FileId => None,
|
|
LeafStructMemberKind::Range => None,
|
|
})
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>()
|
|
.join(", ");
|
|
|
|
let format_string = format!("{}({})", leaf_struct_build_spec.build(), member_formatters);
|
|
|
|
let members = leaf_struct_build_spec
|
|
.members()
|
|
.map(|member| match member.kind() {
|
|
LeafStructMemberKind::String => {
|
|
let member_ident = format_ident!("{}", member.name());
|
|
Some(quote! {
|
|
self.#member_ident()
|
|
})
|
|
}
|
|
_ => None,
|
|
})
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let result = make_result();
|
|
|
|
quote! {
|
|
impl PrettyPrint for #type_ident {
|
|
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
|
writer.writeln_indented(&format!(#format_string, #(#members),*))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn make_struct_p2_impl(struct_build_spec: &StructSpec) -> TokenStream {
|
|
let child_print_statements = struct_build_spec
|
|
.children()
|
|
.map(|child| match child {
|
|
StructChild::SkipChild(_) => None,
|
|
StructChild::VecChild(vec_child) => match vec_child.build() {
|
|
VecChildBuild::Node(_) => {
|
|
let child_ident = format_ident!("{}", vec_child.name());
|
|
Some(quote! {
|
|
for child in self.#child_ident() {
|
|
child.pretty_print(writer)?;
|
|
}
|
|
})
|
|
}
|
|
VecChildBuild::String(_) => None,
|
|
},
|
|
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) = self.#child_ident() {
|
|
child.pretty_print(writer)?;
|
|
}
|
|
})
|
|
} else {
|
|
Some(quote! {
|
|
self.#child_ident().pretty_print(writer)?;
|
|
})
|
|
}
|
|
}
|
|
MemberChildBuild::Boolean(_) => {
|
|
let format_string = format!("{}({})", member_child.name(), "{}");
|
|
let child_ident = format_ident!("{}", member_child.name());
|
|
Some(quote! {
|
|
writer.writeln_indented(&format!(#format_string, self.#child_ident()))?;
|
|
})
|
|
}
|
|
},
|
|
StructChild::Special(_) => None,
|
|
})
|
|
.filter(Option::is_some)
|
|
.map(Option::unwrap)
|
|
.collect::<Vec<_>>();
|
|
|
|
let type_ident = format_ident!("{}", struct_build_spec.build());
|
|
let type_string = struct_build_spec.build();
|
|
|
|
let result = make_result();
|
|
|
|
quote! {
|
|
impl PrettyPrint for #type_ident {
|
|
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
|
writer.writeln_indented(#type_string)?;
|
|
writer.increase_indent();
|
|
#(#child_print_statements)*
|
|
writer.decrease_indent();
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn make_pretty_print_impl(build_spec: &BuildSpec) -> Option<TokenStream> {
|
|
match build_spec {
|
|
BuildSpec::Struct(struct_spec) => Some(make_struct_p2_impl(struct_spec)),
|
|
BuildSpec::LeafStruct(leaf_struct) => Some(make_leaf_struct_p2_impl(leaf_struct)),
|
|
BuildSpec::Enum(enum_spec) => Some(make_tree_enum_p2_impl(enum_spec)),
|
|
BuildSpec::LeafEnum(leaf_enum) => Some(make_leaf_enum_p2_impl(leaf_enum)),
|
|
BuildSpec::Production(_) => None,
|
|
BuildSpec::NodeProduction(_) => None,
|
|
BuildSpec::PolymorphicType(polymorphic_type) => {
|
|
Some(make_polymorphic_type_p2_impl(polymorphic_type))
|
|
}
|
|
BuildSpec::PolymorphicPassThrough(_) => None,
|
|
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => {
|
|
Some(make_polymorphic_enum_loop_p2_impl(polymorphic_enum_loop))
|
|
}
|
|
}
|
|
}
|