Add fields and special children for Polymorphic enum loop specs.

This commit is contained in:
Jesse Brault 2025-11-23 14:22:33 -06:00
parent 734a00ea92
commit 7ffa516c03
16 changed files with 524 additions and 223 deletions

View File

@ -21,16 +21,21 @@ pub fn make_polymorphic_enum_loop_ast_node_impl(
.map(|child| {
let child_ident = match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
format_ident!("{}", use_current.name())
Some(format_ident!("{}", use_current.name()))
}
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
format_ident!("{}", on_each.name())
Some(format_ident!("{}", on_each.name()))
}
PolymorphicEnumLoopRuleBuildChild::Special(_) => None,
};
quote! {
children.push(self.#child_ident() as &dyn AstNode);
}
child_ident.map(|child_ident| {
quote! {
children.push(self.#child_ident() as &dyn AstNode);
}
})
})
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
quote! {

View File

@ -4,7 +4,8 @@ use crate::spec::polymorphic_enum_loop_spec::{
PolymorphicEnumLoopRuleBuildChild, PolymorphicEnumLoopRuleChildOnEach,
PolymorphicEnumLoopRulePassThrough,
};
use proc_macro2::TokenStream;
use crate::spec::SpecialChildKind;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
fn make_pass_through(pass_through: &PolymorphicEnumLoopRulePassThrough) -> TokenStream {
@ -54,6 +55,16 @@ fn make_build(
quote! { Box::new(result.unwrap()) }
}
PolymorphicEnumLoopRuleBuildChild::OnEach(_) => quote! { on_each_child },
PolymorphicEnumLoopRuleBuildChild::Special(special_child) => {
match special_child.kind() {
SpecialChildKind::FileId => {
quote! { file_id }
}
SpecialChildKind::Range => {
quote! { Range { start: as_span.start(), end: as_span.end() } }
}
}
}
})
.collect::<Vec<_>>();
@ -76,11 +87,27 @@ fn make_match_arm(
}
}
fn make_preamble(spec: &PolymorphicEnumLoopBuildSpec, pair_ident: &Ident) -> TokenStream {
if spec.rules().any(|rule| match rule {
PolymorphicEnumLoopRule::Build(build) => build.children().any(|child| match child {
PolymorphicEnumLoopRuleBuildChild::Special(_) => true,
_ => false,
}),
_ => false,
}) {
quote! { let as_span = #pair_ident.as_span(); }
} else {
quote! {}
}
}
pub fn make_polymorphic_enum_loop_build_fn(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(spec.name()));
let pair_ident = format_ident!("{}", make_build_pair(spec.name()));
let return_type_ident = format_ident!("{}", spec.kind());
let preamble = make_preamble(spec, &pair_ident);
let iter_expr = if spec.reverse() {
quote! { #pair_ident.into_inner().rev() }
} else {
@ -94,6 +121,7 @@ pub fn make_polymorphic_enum_loop_build_fn(spec: &PolymorphicEnumLoopBuildSpec)
quote! {
fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident {
#preamble
let mut result: Option<#return_type_ident> = None;
for inner_pair in #iter_expr {
match inner_pair.as_rule() {

View File

@ -1,5 +1,8 @@
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, StructChild, StructSpec, VecChild, VecChildBuild,
};
use crate::spec::{SpecialChild, SpecialChildKind};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
@ -118,14 +121,14 @@ fn make_boolean_member_child_match_action(name: &str) -> TokenStream {
}
}
fn make_rule_matcher(child_spec: &StructChild) -> Option<TokenStream> {
fn make_rule_matcher(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec {
StructChild::SkipChild(skip_child) => {
let rule_ident = format_ident!("{}", skip_child.rule());
Some(quote! {
Rule::#rule_ident => {}
})
},
}
StructChild::VecChild(vec_child) => {
let rule_ident = format_ident!("{}", vec_child.rule());
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 }
})
}
StructChild::MemberChild(member_child) => {
match member_child.build() {
MemberChildBuild::Node(node_member_build) => {
let rule_ident = format_ident!("{}", member_child.rule());
let action = make_node_member_child_match_action(
member_child.name(),
node_member_build
);
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());
Some(quote! {
Rule::#rule_ident => { #action }
})
}
StructChild::MemberChild(member_child) => match member_child.build() {
MemberChildBuild::Node(node_member_build) => {
let rule_ident = format_ident!("{}", member_child.rule());
let action =
make_node_member_child_match_action(member_child.name(), node_member_build);
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());
Some(quote! {
Rule::#rule_ident => { #action }
})
}
},
StructChild::Special(_) => None
StructChild::Special(_) => None,
}
}
@ -204,7 +203,7 @@ fn make_child_arg(child_spec: &StructChild, pair_ident: &Ident) -> Option<TokenS
)),
MemberChildBuild::Boolean(_) => {
Some(make_boolean_member_child_arg(member_child.name()))
},
}
},
StructChild::Special(special_child) => Some(make_special_child_arg(special_child)),
}
@ -230,9 +229,9 @@ pub fn make_struct_build_fn(build_spec: &StructSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build()));
let pair_ident = format_ident!("{}", make_build_pair(build_spec.build()));
let return_type_ident = format_ident!("{}", build_spec.build());
let preamble = make_preamble(build_spec, &pair_ident);
let special_children = make_special_children(build_spec);
let child_holders = build_spec
@ -261,9 +260,9 @@ pub fn make_struct_build_fn(build_spec: &StructSpec) -> TokenStream {
quote! {
fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident {
#preamble
#(#special_children;)*
#(#child_holders;)*
#iter_stream

View File

@ -4,6 +4,7 @@ use crate::spec::polymorphic_enum_loop_spec::{
PolymorphicEnumLoopRuleBuild, PolymorphicEnumLoopRuleBuildChild,
PolymorphicEnumLoopRuleChildOnEach, PolymorphicEnumLoopRulePassThrough,
};
use crate::spec::{SpecialChild, SpecialChildKind, StructField};
use yaml_rust2::Yaml;
fn deserialize_build_child(child_name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuildChild {
@ -17,6 +18,13 @@ fn deserialize_build_child(child_name: &str, props: &Yaml) -> PolymorphicEnumLoo
PolymorphicEnumLoopRuleBuildChild::OnEach(PolymorphicEnumLoopRuleChildOnEach::new(
child_name, rule,
))
} else if props["special"].is_hash() {
let kind = match props["special"]["kind"].as_str().unwrap() {
"range" => SpecialChildKind::Range,
"file_id" => SpecialChildKind::FileId,
_ => panic!("Unknown special child kind"),
};
PolymorphicEnumLoopRuleBuildChild::Special(SpecialChild::new(child_name, kind))
} else {
panic!("Expected 'use_current' or 'on_each' hash for polymorphic enum loop build child");
}
@ -35,15 +43,30 @@ fn deserialize_build(name: &str, props: &Yaml) -> PolymorphicEnumLoopRuleBuild {
.map(Box::new)
.collect();
PolymorphicEnumLoopRuleBuild::new(name, variant, children)
let fields = props["fields"]
.as_vec()
.map(|fields| {
fields.iter()
.map(|field_yaml| {
let (field_name, field_props) = unwrap_single_member_hash(field_yaml);
let kind = field_props["kind"].as_str().unwrap();
StructField::new(
&field_name,
kind,
None,
false
)
})
.collect::<Vec<_>>()
})
.unwrap_or_else(|| vec![]);
PolymorphicEnumLoopRuleBuild::new(name, variant, children, fields)
}
fn deserialize_pass_through(name: &str, props: &Yaml) -> PolymorphicEnumLoopRulePassThrough {
let kind = props["kind"].as_str().unwrap();
let with = make_build_fn_name(
props["with"].as_str()
.unwrap_or(kind)
);
let with = make_build_fn_name(props["with"].as_str().unwrap_or(kind));
PolymorphicEnumLoopRulePassThrough::new(name, kind, &with)
}
@ -63,7 +86,7 @@ fn deserialize_rule(rule_name: &str, props: &Yaml) -> PolymorphicEnumLoopRule {
pub fn deserialize_polymorphic_enum_loop(name: &str, props: &Yaml) -> PolymorphicEnumLoopBuildSpec {
let kind = props["kind"].as_str().unwrap();
let reverse = get_as_bool(&props["reverse"]);
let rules = props["rules"]
.as_vec()
.unwrap()

View File

@ -3,6 +3,7 @@ use convert_case::{Case, Casing};
use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_member_hash};
use crate::spec::struct_spec::*;
use crate::spec::{SpecialChild, SpecialChildKind, StructField, StructFieldWrap};
use yaml_rust2::Yaml;
fn deserialize_field(field_yaml: &Yaml) -> StructField {

View File

@ -1,5 +1,8 @@
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
use crate::spec::leaf_struct_spec::{LeafStructBuildSpec, LeafStructMemberKind};
use crate::spec::polymorphic_enum_inner_build::{
PolymorphicEnumInnerBuild, PolymorphicEnumInnerBuildMemberKind,
};
use crate::spec::polymorphic_enum_loop_spec::{
PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopRule, PolymorphicEnumLoopRuleBuildChild,
};
@ -10,7 +13,6 @@ use crate::spec::BuildSpec;
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::spec::polymorphic_enum_inner_build::{PolymorphicEnumInnerBuild, PolymorphicEnumInnerBuildMember, PolymorphicEnumInnerBuildMemberKind};
fn make_result() -> TokenStream {
quote! { std::fmt::Result }
@ -19,10 +21,11 @@ fn make_result() -> TokenStream {
fn make_polymorphic_enum_inner_build_p2_impl(spec: &PolymorphicEnumInnerBuild) -> TokenStream {
let type_ident = format_ident!("{}", spec.name());
let result = make_result();
let type_string = spec.name();
let child_matchers = spec.members()
let child_matchers = spec
.members()
.map(|member| {
let variant_ident = format_ident!("{}", member.name());
match member.kind() {
@ -43,7 +46,7 @@ fn make_polymorphic_enum_inner_build_p2_impl(spec: &PolymorphicEnumInnerBuild) -
}
})
.collect::<Vec<_>>();
quote! {
impl PrettyPrint for #type_ident {
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
@ -78,6 +81,10 @@ fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> To
let child_print_statements = build
.children()
.filter(|child| match child {
PolymorphicEnumLoopRuleBuildChild::Special(_) => false,
_ => true,
})
.map(|child| {
let child_ident = match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
@ -86,6 +93,7 @@ fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> To
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
format_ident!("{}", on_each.name())
}
_ => unreachable!(),
};
quote! {
self.#child_ident().pretty_print(writer)?;
@ -330,9 +338,9 @@ pub fn make_pretty_print_impl(build_spec: &BuildSpec) -> Option<TokenStream> {
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => {
Some(make_polymorphic_enum_loop_p2_impl(polymorphic_enum_loop))
}
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build) => {
Some(make_polymorphic_enum_inner_build_p2_impl(polymorphic_enum_inner_build))
}
BuildSpec::PolymorphicEnumInnerBuild(polymorphic_enum_inner_build) => Some(
make_polymorphic_enum_inner_build_p2_impl(polymorphic_enum_inner_build),
),
BuildSpec::PolymorphicLeafEnum(_) => None,
BuildSpec::PolymorphicTreeEnum(_) => None,
}

View File

@ -1,15 +1,15 @@
use polymorphic_leaf_enum::PolymorphicLeafEnum;
use leaf_enum_spec::LeafEnumBuildSpec;
use leaf_struct_spec::LeafStructBuildSpec;
use node_production_spec::NodeProductionBuildSpec;
use polymorphic_enum_inner_build::PolymorphicEnumInnerBuild;
use polymorphic_enum_loop_spec::PolymorphicEnumLoopBuildSpec;
use polymorphic_leaf_enum::PolymorphicLeafEnum;
use polymorphic_pass_through_spec::PolymorphicPassThroughBuildSpec;
use polymorphic_tree_enum_spec::PolymorphicTreeEnumSpec;
use polymorphic_type_spec::PolymorphicTypeBuildSpec;
use production_spec::ProductionBuildSpec;
use struct_spec::StructSpec;
use tree_enum_spec::TreeEnumBuildSpec;
use polymorphic_tree_enum_spec::PolymorphicTreeEnumSpec;
pub(crate) mod leaf_enum_spec;
pub(crate) mod leaf_struct_spec;
@ -38,3 +38,72 @@ pub enum BuildSpec {
PolymorphicLeafEnum(PolymorphicLeafEnum),
PolymorphicTreeEnum(PolymorphicTreeEnumSpec),
}
#[derive(Debug)]
pub struct SpecialChild {
name: String,
kind: SpecialChildKind,
}
impl SpecialChild {
pub fn new(name: &str, kind: SpecialChildKind) -> Self {
Self {
name: name.to_string(),
kind,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &SpecialChildKind {
&self.kind
}
}
#[derive(Debug)]
pub enum SpecialChildKind {
FileId,
Range,
}
#[derive(Debug)]
pub struct StructField {
name: String,
kind: String,
wrap: Option<StructFieldWrap>,
vec: bool,
}
impl StructField {
pub fn new(name: &str, kind: &str, wrap: Option<StructFieldWrap>, vec: bool) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
wrap,
vec,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn wrap(&self) -> Option<&StructFieldWrap> {
self.wrap.as_ref()
}
pub fn vec(&self) -> bool {
self.vec
}
}
#[derive(Debug)]
pub enum StructFieldWrap {
RcRefCell,
}

View File

@ -1,3 +1,5 @@
use crate::spec::{SpecialChild, StructField};
pub struct PolymorphicEnumLoopBuildSpec {
name: String,
kind: String,
@ -6,7 +8,12 @@ pub struct PolymorphicEnumLoopBuildSpec {
}
impl PolymorphicEnumLoopBuildSpec {
pub fn new(name: &str, kind: &str, reverse: bool, rules: Vec<Box<PolymorphicEnumLoopRule>>) -> Self {
pub fn new(
name: &str,
kind: &str,
reverse: bool,
rules: Vec<Box<PolymorphicEnumLoopRule>>,
) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
@ -22,7 +29,7 @@ impl PolymorphicEnumLoopBuildSpec {
pub fn kind(&self) -> &str {
&self.kind
}
pub fn reverse(&self) -> bool {
self.reverse
}
@ -51,15 +58,15 @@ impl PolymorphicEnumLoopRulePassThrough {
with: with.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn with(&self) -> &str {
&self.with
}
@ -69,17 +76,24 @@ pub struct PolymorphicEnumLoopRuleBuild {
name: String,
variant: String,
children: Vec<Box<PolymorphicEnumLoopRuleBuildChild>>,
fields: Vec<StructField>,
}
impl PolymorphicEnumLoopRuleBuild {
pub fn new(name: &str, variant: &str, children: Vec<Box<PolymorphicEnumLoopRuleBuildChild>>) -> Self {
pub fn new(
name: &str,
variant: &str,
children: Vec<Box<PolymorphicEnumLoopRuleBuildChild>>,
fields: Vec<StructField>,
) -> Self {
Self {
name: name.to_string(),
variant: variant.to_string(),
children,
fields,
}
}
pub fn name(&self) -> &str {
&self.name
}
@ -91,11 +105,16 @@ impl PolymorphicEnumLoopRuleBuild {
pub fn children(&self) -> impl Iterator<Item = &PolymorphicEnumLoopRuleBuildChild> {
self.children.iter().map(Box::as_ref)
}
pub fn fields(&self) -> &[StructField] {
&self.fields
}
}
pub enum PolymorphicEnumLoopRuleBuildChild {
UseCurrent(PolymorphicEnumLoopChildUseCurrent),
OnEach(PolymorphicEnumLoopRuleChildOnEach),
Special(SpecialChild),
}
pub struct PolymorphicEnumLoopChildUseCurrent {
@ -110,7 +129,7 @@ impl PolymorphicEnumLoopChildUseCurrent {
kind: kind.to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
@ -136,7 +155,7 @@ impl PolymorphicEnumLoopRuleChildOnEach {
pub fn name(&self) -> &str {
&self.name
}
pub fn rule(&self) -> &str {
&self.rule
}

View File

@ -1,3 +1,5 @@
use crate::spec::{SpecialChild, StructField};
pub struct StructSpec {
build: String,
children: Vec<Box<StructChild>>,
@ -246,72 +248,3 @@ impl BooleanMemberBuild {
pub enum BooleanMemberBuildOn {
RulePresent,
}
#[derive(Debug)]
pub struct SpecialChild {
name: String,
kind: SpecialChildKind,
}
impl SpecialChild {
pub fn new(name: &str, kind: SpecialChildKind) -> Self {
Self {
name: name.to_string(),
kind,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &SpecialChildKind {
&self.kind
}
}
#[derive(Debug)]
pub enum SpecialChildKind {
FileId,
Range,
}
#[derive(Debug)]
pub struct StructField {
name: String,
kind: String,
wrap: Option<StructFieldWrap>,
vec: bool,
}
impl StructField {
pub fn new(name: &str, kind: &str, wrap: Option<StructFieldWrap>, vec: bool) -> Self {
Self {
name: name.to_string(),
kind: kind.to_string(),
wrap,
vec,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &str {
&self.kind
}
pub fn wrap(&self) -> Option<&StructFieldWrap> {
self.wrap.as_ref()
}
pub fn vec(&self) -> bool {
self.vec
}
}
#[derive(Debug)]
pub enum StructFieldWrap {
RcRefCell,
}

View File

@ -1,96 +1,193 @@
use crate::spec::polymorphic_enum_loop_spec::{PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopRule, PolymorphicEnumLoopRuleBuildChild};
use crate::spec::polymorphic_enum_loop_spec::{
PolymorphicEnumLoopBuildSpec, PolymorphicEnumLoopRule, PolymorphicEnumLoopRuleBuildChild,
};
use crate::spec::SpecialChildKind;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
pub fn make_polymorphic_enum_loop_type(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.name());
let build = spec.rules()
.find(|rule| {
match rule {
PolymorphicEnumLoopRule::Build(_) => true,
_ => false
}
let build = spec
.rules()
.find(|rule| match rule {
PolymorphicEnumLoopRule::Build(_) => true,
_ => false,
})
.map(|rule| {
match rule {
PolymorphicEnumLoopRule::Build(build) => build,
_ => unreachable!()
}
.map(|rule| match rule {
PolymorphicEnumLoopRule::Build(build) => build,
_ => unreachable!(),
})
.unwrap();
let annotated_members = build.children()
let annotated_members = build
.children()
.map(|child| match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
let child_ident = format_ident!("{}", use_current.name());
let child_type_ident = format_ident!("{}", use_current.kind());
quote! {
#child_ident: Box<#child_type_ident>
}
}
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
let child_ident = format_ident!("{}", on_each.name());
let child_type_ident = format_ident!("{}", on_each.rule());
quote! {
#child_ident: Box<#child_type_ident>
}
}
PolymorphicEnumLoopRuleBuildChild::Special(special_child) => {
let child_ident = format_ident!("{}", special_child.name());
let child_type_ident = match special_child.kind() {
SpecialChildKind::FileId => {
quote! { usize }
}
SpecialChildKind::Range => {
quote! { Range<usize> }
}
};
quote! {
#child_ident: #child_type_ident
}
}
})
.collect::<Vec<_>>();
let annotated_fields = build
.fields()
.iter()
.map(|field| {
let field_ident = format_ident!("{}", field.name());
let field_type = format_ident!("{}", field.kind());
quote! {
#field_ident: Option<#field_type>
}
})
.collect::<Vec<_>>();
let member_names = build
.children()
.map(|child| match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
format_ident!("{}", use_current.name())
}
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
format_ident!("{}", on_each.name())
}
PolymorphicEnumLoopRuleBuildChild::Special(special_child) => {
format_ident!("{}", special_child.name())
}
})
.collect::<Vec<_>>();
let field_initializers = build
.fields()
.iter()
.map(|field| {
let field_ident = format_ident!("{}", field.name());
quote! { #field_ident: None }
})
.collect::<Vec<_>>();
let accessors = build
.children()
.map(|child| {
match child {
let (child_ident, child_type_ident) = match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
let child_ident = format_ident!("{}", use_current.name());
let child_type_ident = format_ident!("{}", use_current.kind());
quote! {
#child_ident: Box<#child_type_ident>
}
(child_ident, quote! { #child_type_ident })
}
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
let child_ident = format_ident!("{}", on_each.name());
let child_type_ident = format_ident!("{}", on_each.rule());
quote! {
#child_ident: Box<#child_type_ident>
}
(child_ident, quote! { #child_type_ident })
}
}
})
.collect::<Vec<_>>();
let member_names = build.children()
.map(|child| {
match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
format_ident!("{}", use_current.name())
}
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
format_ident!("{}", on_each.name())
}
}
})
.collect::<Vec<_>>();
let accessors = build.children()
.map(|child| {
let (child_ident, child_type_ident) = match child {
PolymorphicEnumLoopRuleBuildChild::UseCurrent(use_current) => {
(format_ident!("{}", use_current.name()), format_ident!("{}", use_current.kind()))
}
PolymorphicEnumLoopRuleBuildChild::OnEach(on_each) => {
(format_ident!("{}", on_each.name()), format_ident!("{}", on_each.rule()))
PolymorphicEnumLoopRuleBuildChild::Special(special_child) => {
let child_ident = format_ident!("{}", special_child.name());
let child_type_ident = match special_child.kind() {
SpecialChildKind::FileId => {
quote! { usize }
}
SpecialChildKind::Range => {
quote! { Range<usize> }
}
};
(child_ident, child_type_ident)
}
};
let child_mut_ident = format_ident!("{}_mut", child_ident);
let as_ref = match child {
PolymorphicEnumLoopRuleBuildChild::Special(_) => {
quote! { &self.#child_ident }
}
_ => quote! { self.#child_ident.as_ref() },
};
let as_mut = match child {
PolymorphicEnumLoopRuleBuildChild::Special(_) => {
quote! { &mut self.#child_ident }
}
_ => quote! { self.#child_ident.as_mut() },
};
quote! {
pub fn #child_ident(&self) -> &#child_type_ident {
self.#child_ident.as_ref()
#as_ref
}
pub fn #child_mut_ident(&mut self) -> &mut #child_type_ident {
self.#child_ident.as_mut()
#as_mut
}
}
})
.collect::<Vec<_>>();
let field_accessors = build
.fields()
.iter()
.map(|field| {
let field_ident = format_ident!("{}", field.name());
let field_ident_mut = format_ident!("{}_mut", field.name());
let field_type = format_ident!("{}", field.kind());
let set_ident = format_ident!("set_{}", field.name());
quote! {
pub fn #field_ident(&self) -> Option<&#field_type> {
self.#field_ident.as_ref()
}
pub fn #field_ident_mut(&mut self) -> Option<&mut #field_type> {
self.#field_ident.as_mut()
}
pub fn #set_ident(&mut self, #field_ident: #field_type) {
self.#field_ident = Some(#field_ident);
}
}
})
.collect::<Vec<_>>();
quote! {
pub struct #type_ident {
#(#annotated_members),*
#(#annotated_members,)*
#(#annotated_fields,)*
}
impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self {
Self {
#(#member_names),*
#(#member_names,)*
#(#field_initializers,)*
}
}
#(#accessors)*
#(#field_accessors)*
}
}
}

View File

@ -1,7 +1,7 @@
use crate::spec::struct_spec::{
MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructField,
StructFieldWrap, StructSpec, VecChild, VecChildBuild,
MemberChild, MemberChildBuild, StructChild, StructSpec, VecChild, VecChildBuild,
};
use crate::spec::{SpecialChild, SpecialChildKind, StructField, StructFieldWrap};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};

3
examples/incompat.dm Normal file
View File

@ -0,0 +1,3 @@
fn main()
let x = 1 + 2L
end

View File

@ -30,14 +30,16 @@ pub mod node {
}
}
}
impl Expression {
pub fn analyzed_kind(&self) -> Kind {
match self {
Expression::Ternary(ternary_expression) => {
todo!()
}
Expression::Or(or_expression) => {todo!()}
Expression::Or(or_expression) => {
todo!()
}
Expression::And(and_expression) => {
todo!()
}
@ -47,9 +49,10 @@ pub mod node {
Expression::Shift(shift_expression) => {
todo!()
}
Expression::Additive(additive_expression) => {
todo!()
}
Expression::Additive(additive_expression) => additive_expression
.analyzed_kind()
.expect("AdditiveExpression's analyzed_kind not set.")
.clone(),
Expression::Multiplicative(multiplicative_expression) => {
todo!()
}
@ -59,12 +62,11 @@ pub mod node {
Expression::Suffix(suffix_expression) => {
todo!()
}
Expression::Literal(literal) => {
literal.analyzed_kind()
}
Expression::Identifier(identifier) => {
identifier.analyzed_kind().expect("IdentifierExpression's analyzed_kind not set.").clone()
}
Expression::Literal(literal) => literal.analyzed_kind(),
Expression::Identifier(identifier) => identifier
.analyzed_kind()
.expect("IdentifierExpression's analyzed_kind not set.")
.clone(),
Expression::Fqn(fqn) => {
todo!()
}
@ -77,31 +79,21 @@ pub mod node {
}
}
}
impl Literal {
pub fn analyzed_kind(&self) -> Kind {
match self {
Literal::IntLiteral(_) => {
Kind::Primitive(PrimitiveKind::Int.into())
}
Literal::LongLiteral(_) => {
Kind::Primitive(PrimitiveKind::Long.into())
}
Literal::DoubleLiteral(_) => {
Kind::Primitive(PrimitiveKind::Double.into())
}
Literal::SingleQuoteString(_) => {
Kind::Primitive(PrimitiveKind::String.into())
}
Literal::IntLiteral(_) => Kind::Primitive(PrimitiveKind::Int.into()),
Literal::LongLiteral(_) => Kind::Primitive(PrimitiveKind::Long.into()),
Literal::DoubleLiteral(_) => Kind::Primitive(PrimitiveKind::Double.into()),
Literal::SingleQuoteString(_) => Kind::Primitive(PrimitiveKind::String.into()),
Literal::DString(_) => {
todo!()
}
Literal::BacktickString(_) => {
todo!()
}
Literal::BooleanLiteral(_) => {
Kind::Primitive(PrimitiveKind::Boolean.into())
}
Literal::BooleanLiteral(_) => Kind::Primitive(PrimitiveKind::Boolean.into()),
}
}
}

View File

@ -1,20 +1,128 @@
use crate::name_analysis::name_analysis;
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use deimos::asm::assemble_ir::assemble_ir_function;
use deimos::ast::build::build_ast;
use deimos::ast::node::CompilationUnit;
use deimos::ir::lower_ast::lower_compilation_unit;
use deimos::ir::Ir;
use deimos::name_analysis::analyze_names;
use deimos::name_analysis::symbol_table::SymbolTable;
use deimos::parser::{DeimosParser, Rule};
use deimos::std_core::add_std_core_symbols;
use deimos::type_analysis::analyze_types;
use pest::Parser;
use std::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};
use std::path::PathBuf;
struct ParseErrors {
errors: Vec<pest::error::Error<Rule>>,
}
impl Debug for ParseErrors {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self, f)
}
}
impl Display for ParseErrors {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "There were errors during parsing.")?;
for parse_error in &self.errors {
writeln!(f, "{}", parse_error)?;
}
Ok(())
}
}
impl std::error::Error for ParseErrors {}
#[derive(Debug)]
struct CompilationErrors {
count: usize,
}
impl Display for CompilationErrors {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.count == 1 {
writeln!(f, "There was 1 error during compilation. See above.")
} else {
writeln!(
f,
"There were {} errors during compilation. See above.",
self.count
)
}
}
}
impl std::error::Error for CompilationErrors {}
pub fn compile_to_ir(
paths: &[PathBuf],
) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> {
let mut compilation_units = name_analysis(&paths)?;
let mut paths_and_sources: HashMap<String, String> = HashMap::new();
for path in paths {
let src = std::fs::read_to_string(path).unwrap();
paths_and_sources.insert(path.display().to_string(), src);
}
let mut compilation_units = vec![];
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
let mut parse_errors = vec![];
for (path, source) in &paths_and_sources {
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
match parse_result {
Ok(mut pairs) => {
let file_id = files.add(path, source);
let compilation_unit = build_ast(file_id, &mut pairs);
compilation_units.push(compilation_unit);
}
Err(error) => {
parse_errors.push(error);
}
}
}
if !parse_errors.is_empty() {
return Err(Box::new(ParseErrors {
errors: parse_errors,
}));
}
let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
let name_diagnostics = analyze_names(&mut compilation_units, &files, &mut symbol_table);
if name_diagnostics.is_empty() {
println!("Name analysis complete.");
} else {
let writer = StandardStream::stderr(ColorChoice::Always);
let config = term::Config::default();
for diagnostic in &name_diagnostics {
term::emit(&mut writer.lock(), &config, &files, diagnostic)?;
}
return Err(Box::new(CompilationErrors {
count: name_diagnostics.len(),
}));
}
let type_diagnostics = analyze_types(&mut compilation_units);
if !type_diagnostics.is_empty() {
eprintln!("There were type diagnostics")
if type_diagnostics.is_empty() {
println!("Type analysis complete.");
} else {
let writer = StandardStream::stderr(ColorChoice::Always);
let config = term::Config::default();
for diagnostic in &type_diagnostics {
term::emit(&mut writer.lock(), &config, &files, &diagnostic)?;
}
return Err(Box::new(CompilationErrors {
count: type_diagnostics.len(),
}));
}
for compilation_unit in &compilation_units {

View File

@ -1057,6 +1057,15 @@ AdditiveExpression:
- rhs:
on_each:
rule: AdditiveRhs
- file_id:
special:
kind: file_id
- range:
special:
kind: range
fields:
- analyzed_kind:
kind: Kind
AdditiveRhs:
struct:
children:

View File

@ -10,6 +10,7 @@ use crate::name_analysis::symbol::ExpressibleSymbol;
use crate::type_analysis::kinds::class_kind::ClassKind;
use crate::type_analysis::kinds::function_kind::FunctionKind;
use crate::type_analysis::kinds::Kind;
use codespan_reporting::diagnostic::Label;
use codespan_reporting::files::Files;
pub fn analyze_types(compilation_units: &mut [CompilationUnit]) -> Vec<DmDiagnostic> {
@ -193,14 +194,20 @@ fn ta_additive_expression(
let right_kind = additive_expression.rhs().expression().analyzed_kind();
if left_kind != right_kind {
diagnostics.push(DmDiagnostic::error().with_message(&format!(
"Incompatible types for additive expression: {} vs. {}",
left_kind, right_kind
)));
todo!("Error file_id and range; set Error type on additive expression")
} else {
todo!("set analyzed type for additive expression")
diagnostics.push(
DmDiagnostic::error()
.with_message(&format!(
"Incompatible types for additive expression: {} vs. {}",
left_kind, right_kind
))
.with_label(Label::primary(
*additive_expression.file_id(),
*additive_expression.range(),
)
.with_message("Incompatible types here.")),
);
}
additive_expression.set_analyzed_kind(left_kind);
}
fn ta_identifier_expression(identifier_expression: &mut IdentifierExpression) {