WIP name gather, add fields for struct nodes.

This commit is contained in:
Jesse Brault 2025-10-08 17:23:56 -05:00
parent 3ab59961dd
commit 542d5f6c80
7 changed files with 253 additions and 124 deletions

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, SpecialChild, SpecialChildKind, StructChild, StructSpec,
VecChild, VecChildBuild,
};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
@ -125,7 +128,7 @@ fn make_rule_matcher(child_spec: &StructChild) -> Option<TokenStream> {
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,14 +136,11 @@ fn make_rule_matcher(child_spec: &StructChild) -> Option<TokenStream> {
Rule::#rule_ident => { #action }
})
}
StructChild::MemberChild(member_child) => {
match member_child.build() {
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
);
let action =
make_node_member_child_match_action(member_child.name(), node_member_build);
Some(quote! {
Rule::#rule_ident => { #action }
})
@ -152,9 +152,8 @@ fn make_rule_matcher(child_spec: &StructChild) -> Option<TokenStream> {
Rule::#rule_ident => { #action }
})
}
}
},
StructChild::Special(_) => None
StructChild::Special(_) => None,
}
}
@ -192,7 +191,7 @@ fn make_special_child_arg(special_child: &SpecialChild) -> TokenStream {
quote! { #child_ident }
}
fn make_child_arg(child_spec: &StructChild, pair_ident: &Ident) -> Option<TokenStream> {
fn make_child_arg(child_spec: &StructChild) -> Option<TokenStream> {
match child_spec {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)),
@ -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)),
}
@ -214,7 +213,7 @@ fn make_return_value_stream(build_spec: &StructSpec, pair_ident: &Ident) -> Toke
let type_ident = format_ident!("{}", build_spec.build());
let child_args = build_spec
.children()
.map(|child| make_child_arg(child, pair_ident))
.map(|child| make_child_arg(child))
.filter(|child_arg| child_arg.is_some())
.map(|child_arg| child_arg.unwrap())
.collect::<Vec<_>>();

View File

@ -5,6 +5,23 @@ use crate::deserialize::util::{get_as_bool, make_build_fn_name, unwrap_single_me
use crate::spec::struct_spec::*;
use yaml_rust2::Yaml;
fn deserialize_fields(fields: &Yaml) -> Vec<Box<StructField>> {
fields
.as_vec()
.unwrap()
.iter()
.map(|field| unwrap_single_member_hash(field))
.map(|(name, props)| {
let kind = match props["kind"].as_str().unwrap() {
"usize" => StructFieldKind::USize,
_ => panic!()
};
StructField::new(&name, kind, get_as_bool(&props["optional"]))
})
.map(Box::new)
.collect()
}
fn deserialize_skip_child(props: &Yaml) -> StructChild {
let rule = props["rule"].as_str().unwrap();
StructChild::SkipChild(SkipChild::new(rule))
@ -96,7 +113,11 @@ fn deserialize_special_child(name: &str, props: &Yaml) -> StructChild {
match props["kind"].as_str().unwrap() {
"file_id" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::FileId)),
"range" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::Range)),
_ => panic!("Invalid special child kind {} in {}", props["kind"].as_str().unwrap(), name),
_ => panic!(
"Invalid special child kind {} in {}",
props["kind"].as_str().unwrap(),
name
),
}
}
@ -151,5 +172,11 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
} else {
deserialize_error!("array", "children", name);
};
StructSpec::new(name, children)
let fields = if struct_yaml["fields"].is_array() {
deserialize_fields(&struct_yaml["fields"])
} else {
vec![]
};
StructSpec::new(name, children, fields)
}

View File

@ -1,13 +1,19 @@
pub struct StructSpec {
build: String,
children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
}
impl StructSpec {
pub fn new(build: &str, children: Vec<Box<StructChild>>) -> Self {
pub fn new(
build: &str,
children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
) -> Self {
Self {
build: build.to_string(),
children,
fields,
}
}
@ -20,6 +26,10 @@ impl StructSpec {
pub fn children(&self) -> impl Iterator<Item = &StructChild> {
self.children.iter().map(Box::as_ref)
}
pub fn fields(&self) -> impl Iterator<Item = &StructField> {
self.fields.iter().map(Box::as_ref)
}
}
pub enum StructChild {
@ -39,10 +49,8 @@ impl StructChild {
pub fn unwrap_special(&self) -> Option<&SpecialChild> {
match self {
StructChild::Special(special_child) => {
Some(special_child)
},
_ => None
StructChild::Special(special_child) => Some(special_child),
_ => None,
}
}
}
@ -242,7 +250,7 @@ impl SpecialChild {
pub fn new(name: &str, kind: SpecialChildKind) -> Self {
Self {
name: name.to_string(),
kind
kind,
}
}
@ -260,3 +268,35 @@ pub enum SpecialChildKind {
FileId,
Range,
}
pub struct StructField {
name: String,
kind: StructFieldKind,
optional: bool,
}
impl StructField {
pub fn new(name: &str, kind: StructFieldKind, optional: bool) -> Self {
Self {
name: name.to_string(),
kind,
optional,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn kind(&self) -> &StructFieldKind {
&self.kind
}
pub fn optional(&self) -> bool {
self.optional
}
}
pub enum StructFieldKind {
USize,
}

View File

@ -1,6 +1,6 @@
use crate::spec::struct_spec::{
MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec,
VecChild, VecChildBuild,
MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructField,
StructFieldKind, StructSpec, VecChild, VecChildBuild,
};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
@ -99,7 +99,7 @@ fn make_special_child_accessors(special_child: &SpecialChild) -> TokenStream {
}
}
fn make_accessors(child: &StructChild) -> Option<TokenStream> {
fn make_child_accessors(child: &StructChild) -> Option<TokenStream> {
match child {
StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_accessors(vec_child)),
@ -182,15 +182,68 @@ fn make_annotated_member(child: &StructChild) -> Option<TokenStream> {
}
}
fn make_annotated_field(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
let field_type_ident = match field.kind() {
StructFieldKind::USize => quote! { usize },
};
if field.optional() {
quote! {
#field_ident: Option<#field_type_ident>
}
} else {
quote! {
#field_ident: #field_type_ident
}
}
}
fn make_field_init(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
if field.optional() {
quote! {
#field_ident: None
}
} else {
todo!()
}
}
fn make_field_accessors(field: &StructField) -> TokenStream {
let field_ident = format_ident!("{}", field.name());
let field_type_ident = match field.kind() {
StructFieldKind::USize => quote! { usize },
};
if field.optional() {
let setter_ident = format_ident!("set_{}", field.name());
quote! {
pub fn #field_ident(&self) -> Option<#field_type_ident> {
self.#field_ident
}
pub fn #setter_ident(&mut self, #field_ident: #field_type_ident) {
self.#field_ident = Some(#field_ident);
}
}
} else {
todo!()
}
}
pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec
let annotated_children = build_spec
.children()
.map(|child| make_annotated_member(child))
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let annotated_fields = build_spec
.fields()
.map(|field| make_annotated_field(field))
.collect::<Vec<_>>();
let member_names = build_spec
.children()
.map(|child| make_member_ident(child))
@ -198,26 +251,39 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
.map(Option::unwrap)
.collect::<Vec<_>>();
let accessors = build_spec
let field_inits = build_spec
.fields()
.map(|field| make_field_init(field))
.collect::<Vec<_>>();
let child_accessors = build_spec
.children()
.map(|child| make_accessors(child))
.map(|child| make_child_accessors(child))
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let field_accessors = build_spec
.fields()
.map(|field| make_field_accessors(field))
.collect::<Vec<_>>();
quote! {
pub struct #type_ident {
#(#annotated_members),*
#(#annotated_children,)*
#(#annotated_fields,)*
}
impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self {
pub fn new(#(#annotated_children),*) -> Self {
Self {
#(#member_names),*
#(#member_names,)*
#(#field_inits,)*
}
}
#(#accessors)*
#(#child_accessors)*
#(#field_accessors)*
}
}
}

View File

@ -209,59 +209,8 @@ fn gather_node(
AstNodeRef::Member(member) => {
gather_member(member, symbol_table, fqn_context, diagnostics);
}
AstNodeRef::Statement(statement) => match statement {
Statement::VariableDeclaration(variable_declaration) => {
gather_node(
variable_declaration.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
Statement::AssignmentStatement(assignment_statement) => {
gather_node(
assignment_statement.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
Statement::ExpressionStatement(expression_statement) => {
gather_node(
expression_statement.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
Statement::UseStatement(use_statement) => {
gather_node(
use_statement.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
Statement::IfStatement(if_statement) => gather_node(
if_statement.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
),
Statement::WhileStatement(while_statement) => gather_node(
while_statement.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
),
Statement::ForStatement(for_statement) => {
gather_node(
for_statement.as_node_ref(),
symbol_table,
fqn_context,
diagnostics,
);
}
AstNodeRef::Statement(statement) => {
gather_node_children(statement, symbol_table, fqn_context, diagnostics);
},
AstNodeRef::VariableDeclaration(variable_declaration) => {
gather_variable_declaration(
@ -279,6 +228,9 @@ fn gather_node(
AstNodeRef::IfElse(_) => {}
AstNodeRef::WhileStatement(_) => {}
AstNodeRef::ForStatement(_) => {}
AstNodeRef::LValue(_) => {},
AstNodeRef::LValueSuffix(_) => {},
AstNodeRef::VariableUse(_) => {},
AstNodeRef::Expression(_) => {}
AstNodeRef::TernaryExpression(_) => {}
AstNodeRef::TernaryRhs(_) => {}

View File

@ -628,12 +628,8 @@ VariableDeclaration:
AssignmentStatement:
struct:
children:
- left:
member:
rule: Expression
- right:
member:
rule: Expression
- l_value
- expression
ExpressionStatement:
struct:
children:
@ -715,6 +711,30 @@ ForStatement:
skip:
rule: End
# LValue
LValue:
struct:
children:
- variable_use
- suffixes:
vec:
rule: LValueSuffix
LValueSuffix:
tree_enum:
rules:
- ObjectProperty
- ObjectIndex
# VariableUse
VariableUse:
struct:
children:
- identifier
fields:
- scope_id:
kind: usize
optional: true
# Expressions
Expression:
polymorphic_type:
@ -749,6 +769,9 @@ Expression:
- Literal:
inner:
kind: Literal
- VariableUse:
inner:
kind: VariableUse
- Fqn:
inner:
kind: FullyQualifiedName
@ -1091,6 +1114,9 @@ PrimaryExpression:
- Literal:
inner:
kind: Literal
- VariableUse:
inner:
kind: VariableUse
- Fqn:
inner:
kind: FullyQualifiedName

View File

@ -542,7 +542,7 @@ VariableDeclaration = {
}
AssignmentStatement = {
Expression
LValue
~ "="
~ Expression
}
@ -593,6 +593,24 @@ ForStatement = {
~ End
}
// LValue
LValue = {
VariableUse
~ LValueSuffix*
}
LValueSuffix = {
ObjectProperty
| ObjectIndex
}
// Variable Use
VariableUse = {
Identifier
}
// Expressions
Expression = {
@ -741,6 +759,7 @@ ObjectIndex = {
PrimaryExpression = {
Literal
| VariableUse
| FullyQualifiedName
| Closure
| ListExpression