WIP polymorphic building.
This commit is contained in:
parent
c94a698a52
commit
a7eabae3e3
@ -1,4 +1,4 @@
|
|||||||
use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind, EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind, MemberChild, MemberChildToBuild, NodeChildToBuild, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild};
|
use crate::spec::{BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRule, EnumRuleChild, EnumRuleChildKind, EnumRuleNodeChild, LeafEnumBuildSpec, LeafEnumRule, LeafStructBuildSpec, LeafStructMember, LeafStructMemberKind, MemberChild, MemberChildToBuild, NodeChildToBuild, PolymorphicBuildSpec, PolymorphicEnumMember, ProductionBuildSpec, ProductionKind, ProductionStringFrom, SkipChild, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild, VecNodeChildToBuild};
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use yaml_rust2::{Yaml, YamlLoader};
|
use yaml_rust2::{Yaml, YamlLoader};
|
||||||
|
|
||||||
@ -18,6 +18,26 @@ fn unwrap_single_member_hash(hash: &Yaml) -> (String, &Yaml) {
|
|||||||
(key_as_string, member_value)
|
(key_as_string, member_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_polymorphic_enum_members(enum_members_yaml: &Yaml) -> Vec<Box<PolymorphicEnumMember>> {
|
||||||
|
enum_members_yaml
|
||||||
|
.as_vec()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|enum_member_yaml| {
|
||||||
|
let (member_name, member_hash) = unwrap_single_member_hash(enum_member_yaml);
|
||||||
|
let inner_kind = member_hash["inner"]["kind"].as_str().unwrap();
|
||||||
|
PolymorphicEnumMember::new(&member_name, inner_kind)
|
||||||
|
})
|
||||||
|
.map(Box::new)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_polymorphic_spec(name: &str, spec_props: &Yaml) -> PolymorphicBuildSpec {
|
||||||
|
let enum_members = deserialize_polymorphic_enum_members(&spec_props["enum_members"]);
|
||||||
|
let build_kind = spec_props["build"]["kind"].as_str().unwrap();
|
||||||
|
PolymorphicBuildSpec::new(name, enum_members, build_kind)
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
|
fn deserialize_production_spec(rule: &str, production_yaml: &Yaml) -> ProductionBuildSpec {
|
||||||
let kind = match production_yaml["kind"].as_str().unwrap() {
|
let kind = match production_yaml["kind"].as_str().unwrap() {
|
||||||
"int" => ProductionKind::Int,
|
"int" => ProductionKind::Int,
|
||||||
@ -278,6 +298,8 @@ fn deserialize_build_spec(build_spec_name: &str, build_spec: &Yaml) -> BuildSpec
|
|||||||
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
|
BuildSpec::LeafEnum(LeafEnumBuildSpec::new(build_spec_name, leaf_rules))
|
||||||
} else if build_spec["produce"].is_hash() {
|
} else if build_spec["produce"].is_hash() {
|
||||||
BuildSpec::Production(deserialize_production_spec(build_spec_name, &build_spec["produce"]))
|
BuildSpec::Production(deserialize_production_spec(build_spec_name, &build_spec["produce"]))
|
||||||
|
} else if build_spec["polymorphic_type"].is_hash() {
|
||||||
|
BuildSpec::Polymorphic(deserialize_polymorphic_spec(build_spec_name, &build_spec["polymorphic_type"]))
|
||||||
} else {
|
} else {
|
||||||
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type.");
|
panic!("Expected a node spec for either a struct, leaf_struct, enum, leaf_enum node type, or a production type.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ pub mod deserialize;
|
|||||||
mod enum_build_fn;
|
mod enum_build_fn;
|
||||||
mod leaf_enum_build_fn;
|
mod leaf_enum_build_fn;
|
||||||
mod leaf_struct_build_fn;
|
mod leaf_struct_build_fn;
|
||||||
|
mod polymorphic_build_fn;
|
||||||
mod production_build_fn;
|
mod production_build_fn;
|
||||||
mod spec;
|
mod spec;
|
||||||
mod struct_build_fn;
|
mod struct_build_fn;
|
||||||
@ -18,6 +19,7 @@ use proc_macro2::TokenStream;
|
|||||||
use quote::quote;
|
use quote::quote;
|
||||||
use spec::BuildSpec;
|
use spec::BuildSpec;
|
||||||
use syn::File;
|
use syn::File;
|
||||||
|
use crate::polymorphic_build_fn::make_polymorphic_build_fn;
|
||||||
|
|
||||||
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
||||||
println!("*** BuildSpec ***");
|
println!("*** BuildSpec ***");
|
||||||
@ -38,7 +40,10 @@ fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
BuildSpec::Production(production_build_spec) => {
|
BuildSpec::Production(production_build_spec) => {
|
||||||
println!("Production Spec - rule: {}", production_build_spec.rule())
|
println!("Production Spec - rule: {}", production_build_spec.rule());
|
||||||
|
}
|
||||||
|
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
||||||
|
println!("Polymorphic Spec - name: {}", polymorphic_build_spec.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{:#?}", token_stream);
|
println!("{:#?}", token_stream);
|
||||||
@ -85,6 +90,11 @@ fn generate_build_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
|
|||||||
debug_built_spec(build_spec, &stream);
|
debug_built_spec(build_spec, &stream);
|
||||||
stream
|
stream
|
||||||
}
|
}
|
||||||
|
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
||||||
|
let stream = make_polymorphic_build_fn(polymorphic_build_spec);
|
||||||
|
debug_built_spec(build_spec, &stream);
|
||||||
|
stream
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let combined = quote! {
|
let combined = quote! {
|
||||||
|
|||||||
19
ast-generator/src/polymorphic_build_fn.rs
Normal file
19
ast-generator/src/polymorphic_build_fn.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use crate::spec::PolymorphicBuildSpec;
|
||||||
|
use crate::token_stream_to_string;
|
||||||
|
use crate::util::{make_build_fn_name, make_build_pair};
|
||||||
|
|
||||||
|
pub fn make_polymorphic_build_fn(build_spec: &PolymorphicBuildSpec) -> TokenStream {
|
||||||
|
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.name()));
|
||||||
|
let pair_ident = format_ident!("{}", make_build_pair(&build_spec.name()));
|
||||||
|
let return_type_ident = format_ident!("{}", build_spec.name());
|
||||||
|
let inner_build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build_kind()));
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
|
||||||
|
let inner_pair = #pair_ident.into_inner().next().unwrap();
|
||||||
|
#inner_build_fn_ident(inner_pair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ pub enum BuildSpec {
|
|||||||
Struct(StructBuildSpec),
|
Struct(StructBuildSpec),
|
||||||
LeafStruct(LeafStructBuildSpec),
|
LeafStruct(LeafStructBuildSpec),
|
||||||
Production(ProductionBuildSpec),
|
Production(ProductionBuildSpec),
|
||||||
|
Polymorphic(PolymorphicBuildSpec),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enum build spec
|
// Enum build spec
|
||||||
@ -423,3 +424,55 @@ pub enum ProductionStringFrom {
|
|||||||
StringInner,
|
StringInner,
|
||||||
WholePair
|
WholePair
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Polymorphic build spec
|
||||||
|
|
||||||
|
pub struct PolymorphicBuildSpec {
|
||||||
|
name: String,
|
||||||
|
enum_members: Vec<Box<PolymorphicEnumMember>>,
|
||||||
|
build_kind: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicBuildSpec {
|
||||||
|
pub fn new(name: &str, enum_members: Vec<Box<PolymorphicEnumMember>>, build_kind: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
enum_members,
|
||||||
|
build_kind: build_kind.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enum_members(&self) -> impl Iterator<Item = &PolymorphicEnumMember> {
|
||||||
|
self.enum_members.iter().map(Box::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_kind(&self) -> &str {
|
||||||
|
self.build_kind.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PolymorphicEnumMember {
|
||||||
|
name: String,
|
||||||
|
inner_kind: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PolymorphicEnumMember {
|
||||||
|
pub fn new(name: &str, inner_kind: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
inner_kind: inner_kind.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_kind(&self) -> &str {
|
||||||
|
&self.inner_kind
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,30 @@
|
|||||||
use crate::spec::{
|
use crate::spec::{
|
||||||
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec,
|
BooleanChildToBuild, BuildSpec, EnumBuildSpec, EnumRuleChildKind, LeafEnumBuildSpec,
|
||||||
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild,
|
LeafStructBuildSpec, LeafStructMemberKind, MemberChildToBuild, NodeChildToBuild,
|
||||||
StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
|
PolymorphicBuildSpec, StructBuildSpec, StructChildSpec, VecChild, VecChildToBuild,
|
||||||
};
|
};
|
||||||
use proc_macro2::{Ident, TokenStream};
|
use proc_macro2::{Ident, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
|
fn make_polymorphic_type(build_spec: &PolymorphicBuildSpec) -> 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 {
|
fn make_enum_type(build_spec: &EnumBuildSpec) -> TokenStream {
|
||||||
let children: Vec<TokenStream> = build_spec
|
let children: Vec<TokenStream> = build_spec
|
||||||
.rules()
|
.rules()
|
||||||
@ -348,5 +367,8 @@ pub fn make_type(build_spec: &BuildSpec) -> Option<TokenStream> {
|
|||||||
Some(make_leaf_struct_type(leaf_struct_build_spec))
|
Some(make_leaf_struct_type(leaf_struct_build_spec))
|
||||||
}
|
}
|
||||||
BuildSpec::Production(_) => None,
|
BuildSpec::Production(_) => None,
|
||||||
|
BuildSpec::Polymorphic(polymorphic_build_spec) => {
|
||||||
|
Some(make_polymorphic_type(polymorphic_build_spec))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,31 +42,6 @@ pub mod node {
|
|||||||
Self::new(vec![])
|
Self::new(vec![])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
|
||||||
pub fn unwrap_identifier(&self) -> &Identifier {
|
|
||||||
let primary = self.ternary_expression()
|
|
||||||
.or_expression()
|
|
||||||
.left()
|
|
||||||
.left()
|
|
||||||
.left()
|
|
||||||
.left()
|
|
||||||
.left()
|
|
||||||
.left()
|
|
||||||
.right()
|
|
||||||
.left();
|
|
||||||
match primary {
|
|
||||||
PrimaryExpression::FullyQualifiedName(fqn) => {
|
|
||||||
if fqn.identifiers().count() == 1 {
|
|
||||||
fqn.identifiers().next().unwrap()
|
|
||||||
} else {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod build {
|
pub mod build {
|
||||||
@ -133,8 +108,6 @@ pub mod build {
|
|||||||
fn d_string_expression_simple() {
|
fn d_string_expression_simple() {
|
||||||
let pair = parse(Rule::DStringExpression, "${thing}");
|
let pair = parse(Rule::DStringExpression, "${thing}");
|
||||||
let d_string_expression = build_d_string_expression(pair);
|
let d_string_expression = build_d_string_expression(pair);
|
||||||
let identifier = d_string_expression.expression().unwrap_identifier();
|
|
||||||
assert_eq!("thing", identifier.name());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -564,8 +564,46 @@ ForStatement:
|
|||||||
|
|
||||||
# Expressions
|
# Expressions
|
||||||
Expression:
|
Expression:
|
||||||
children:
|
polymorphic_type:
|
||||||
- ternary_expression
|
enum_members:
|
||||||
|
- Ternary:
|
||||||
|
inner:
|
||||||
|
kind: TernaryExpression
|
||||||
|
- Or:
|
||||||
|
inner:
|
||||||
|
kind: OrExpression
|
||||||
|
- And:
|
||||||
|
inner:
|
||||||
|
kind: AndExpression
|
||||||
|
- Comparison:
|
||||||
|
inner:
|
||||||
|
kind: ComparisonExpression
|
||||||
|
- Shift:
|
||||||
|
inner:
|
||||||
|
kind: ShiftExpression
|
||||||
|
- Additive:
|
||||||
|
inner:
|
||||||
|
kind: AdditiveExpression
|
||||||
|
- Multiplicative:
|
||||||
|
inner:
|
||||||
|
kind: MultiplicativeExpression
|
||||||
|
- Prefix:
|
||||||
|
inner:
|
||||||
|
kind: PrefixExpression
|
||||||
|
- Suffix:
|
||||||
|
inner:
|
||||||
|
kind: SuffixExpression
|
||||||
|
- Literal:
|
||||||
|
inner:
|
||||||
|
kind: Literal
|
||||||
|
- Fqn:
|
||||||
|
inner:
|
||||||
|
kind: FullyQualifiedName
|
||||||
|
- Closure:
|
||||||
|
inner:
|
||||||
|
kind: Closure
|
||||||
|
build:
|
||||||
|
kind: TernaryExpression
|
||||||
TernaryExpression:
|
TernaryExpression:
|
||||||
children:
|
children:
|
||||||
- or_expression
|
- or_expression
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user