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::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 proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; 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 { match child_spec {
StructChild::SkipChild(skip_child) => { StructChild::SkipChild(skip_child) => {
let rule_ident = format_ident!("{}", skip_child.rule()); let rule_ident = format_ident!("{}", skip_child.rule());
Some(quote! { Some(quote! {
Rule::#rule_ident => {} Rule::#rule_ident => {}
}) })
}, }
StructChild::VecChild(vec_child) => { StructChild::VecChild(vec_child) => {
let rule_ident = format_ident!("{}", vec_child.rule()); let rule_ident = format_ident!("{}", vec_child.rule());
let action = make_vec_child_match_action(vec_child); 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 } Rule::#rule_ident => { #action }
}) })
} }
StructChild::MemberChild(member_child) => { StructChild::MemberChild(member_child) => match member_child.build() {
match member_child.build() { MemberChildBuild::Node(node_member_build) => {
MemberChildBuild::Node(node_member_build) => { let rule_ident = format_ident!("{}", member_child.rule());
let rule_ident = format_ident!("{}", member_child.rule()); let action =
let action = make_node_member_child_match_action( make_node_member_child_match_action(member_child.name(), node_member_build);
member_child.name(), Some(quote! {
node_member_build Rule::#rule_ident => { #action }
); })
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());
MemberChildBuild::Boolean(_) => { Some(quote! {
let rule_ident = format_ident!("{}", member_child.rule()); Rule::#rule_ident => { #action }
let action = make_boolean_member_child_match_action(member_child.name()); })
Some(quote! {
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 } 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 { match child_spec {
StructChild::SkipChild(_) => None, StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_arg(vec_child)), 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(_) => { MemberChildBuild::Boolean(_) => {
Some(make_boolean_member_child_arg(member_child.name())) Some(make_boolean_member_child_arg(member_child.name()))
}, }
}, },
StructChild::Special(special_child) => Some(make_special_child_arg(special_child)), 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 type_ident = format_ident!("{}", build_spec.build());
let child_args = build_spec let child_args = build_spec
.children() .children()
.map(|child| make_child_arg(child, pair_ident)) .map(|child| make_child_arg(child))
.filter(|child_arg| child_arg.is_some()) .filter(|child_arg| child_arg.is_some())
.map(|child_arg| child_arg.unwrap()) .map(|child_arg| child_arg.unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -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 build_fn_ident = format_ident!("{}", make_build_fn_name(build_spec.build()));
let pair_ident = format_ident!("{}", make_build_pair(build_spec.build())); let pair_ident = format_ident!("{}", make_build_pair(build_spec.build()));
let return_type_ident = format_ident!("{}", build_spec.build()); let return_type_ident = format_ident!("{}", build_spec.build());
let preamble = make_preamble(build_spec, &pair_ident); let preamble = make_preamble(build_spec, &pair_ident);
let special_children = make_special_children(build_spec); let special_children = make_special_children(build_spec);
let child_holders = build_spec let child_holders = build_spec
@ -261,9 +260,9 @@ pub fn make_struct_build_fn(build_spec: &StructSpec) -> TokenStream {
quote! { quote! {
fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident { fn #build_fn_ident(file_id: usize, #pair_ident: Pair<Rule>) -> #return_type_ident {
#preamble #preamble
#(#special_children;)* #(#special_children;)*
#(#child_holders;)* #(#child_holders;)*
#iter_stream #iter_stream

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 crate::spec::struct_spec::*;
use yaml_rust2::Yaml; 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 { fn deserialize_skip_child(props: &Yaml) -> StructChild {
let rule = props["rule"].as_str().unwrap(); let rule = props["rule"].as_str().unwrap();
StructChild::SkipChild(SkipChild::new(rule)) StructChild::SkipChild(SkipChild::new(rule))
@ -96,8 +113,12 @@ fn deserialize_special_child(name: &str, props: &Yaml) -> StructChild {
match props["kind"].as_str().unwrap() { match props["kind"].as_str().unwrap() {
"file_id" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::FileId)), "file_id" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::FileId)),
"range" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::Range)), "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
),
}
} }
fn deserialize_hash_child(name: &str, props: &Yaml) -> StructChild { fn deserialize_hash_child(name: &str, props: &Yaml) -> StructChild {
@ -108,7 +129,7 @@ fn deserialize_hash_child(name: &str, props: &Yaml) -> StructChild {
} else if props["member"].is_hash() { } else if props["member"].is_hash() {
deserialize_member_child(name, &props["member"]) deserialize_member_child(name, &props["member"])
} else if props["special"].is_hash() { } else if props["special"].is_hash() {
deserialize_special_child(name, &props["special"]) deserialize_special_child(name, &props["special"])
} else { } else {
panic!("Expected 'skip' or 'vec' in 'member' in {}", name); panic!("Expected 'skip' or 'vec' in 'member' in {}", name);
} }
@ -151,5 +172,11 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
} else { } else {
deserialize_error!("array", "children", name); 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 { pub struct StructSpec {
build: String, build: String,
children: Vec<Box<StructChild>>, children: Vec<Box<StructChild>>,
fields: Vec<Box<StructField>>,
} }
impl StructSpec { 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 { Self {
build: build.to_string(), build: build.to_string(),
children, children,
fields,
} }
} }
@ -20,6 +26,10 @@ impl StructSpec {
pub fn children(&self) -> impl Iterator<Item = &StructChild> { pub fn children(&self) -> impl Iterator<Item = &StructChild> {
self.children.iter().map(Box::as_ref) 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 { pub enum StructChild {
@ -36,13 +46,11 @@ impl StructChild {
_ => false, _ => false,
} }
} }
pub fn unwrap_special(&self) -> Option<&SpecialChild> { pub fn unwrap_special(&self) -> Option<&SpecialChild> {
match self { match self {
StructChild::Special(special_child) => { StructChild::Special(special_child) => Some(special_child),
Some(special_child) _ => None,
},
_ => None
} }
} }
} }
@ -242,14 +250,14 @@ impl SpecialChild {
pub fn new(name: &str, kind: SpecialChildKind) -> Self { pub fn new(name: &str, kind: SpecialChildKind) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
kind kind,
} }
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
pub fn kind(&self) -> &SpecialChildKind { pub fn kind(&self) -> &SpecialChildKind {
&self.kind &self.kind
} }
@ -260,3 +268,35 @@ pub enum SpecialChildKind {
FileId, FileId,
Range, 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::{ use crate::spec::struct_spec::{
MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructSpec, MemberChild, MemberChildBuild, SpecialChild, SpecialChildKind, StructChild, StructField,
VecChild, VecChildBuild, StructFieldKind, StructSpec, VecChild, VecChildBuild,
}; };
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; 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 { match child {
StructChild::SkipChild(_) => None, StructChild::SkipChild(_) => None,
StructChild::VecChild(vec_child) => Some(make_vec_child_accessors(vec_child)), 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 { pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build()); let type_ident = format_ident!("{}", build_spec.build());
let annotated_members = build_spec let annotated_children = build_spec
.children() .children()
.map(|child| make_annotated_member(child)) .map(|child| make_annotated_member(child))
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let annotated_fields = build_spec
.fields()
.map(|field| make_annotated_field(field))
.collect::<Vec<_>>();
let member_names = build_spec let member_names = build_spec
.children() .children()
.map(|child| make_member_ident(child)) .map(|child| make_member_ident(child))
@ -198,26 +251,39 @@ pub fn make_struct_type(build_spec: &StructSpec) -> TokenStream {
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .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() .children()
.map(|child| make_accessors(child)) .map(|child| make_child_accessors(child))
.filter(Option::is_some) .filter(Option::is_some)
.map(Option::unwrap) .map(Option::unwrap)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let field_accessors = build_spec
.fields()
.map(|field| make_field_accessors(field))
.collect::<Vec<_>>();
quote! { quote! {
pub struct #type_ident { pub struct #type_ident {
#(#annotated_members),* #(#annotated_children,)*
#(#annotated_fields,)*
} }
impl #type_ident { impl #type_ident {
pub fn new(#(#annotated_members),*) -> Self { pub fn new(#(#annotated_children),*) -> Self {
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) => { AstNodeRef::Member(member) => {
gather_member(member, symbol_table, fqn_context, diagnostics); gather_member(member, symbol_table, fqn_context, diagnostics);
} }
AstNodeRef::Statement(statement) => match statement { AstNodeRef::Statement(statement) => {
Statement::VariableDeclaration(variable_declaration) => { gather_node_children(statement, symbol_table, fqn_context, diagnostics);
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::VariableDeclaration(variable_declaration) => { AstNodeRef::VariableDeclaration(variable_declaration) => {
gather_variable_declaration( gather_variable_declaration(
@ -279,6 +228,9 @@ fn gather_node(
AstNodeRef::IfElse(_) => {} AstNodeRef::IfElse(_) => {}
AstNodeRef::WhileStatement(_) => {} AstNodeRef::WhileStatement(_) => {}
AstNodeRef::ForStatement(_) => {} AstNodeRef::ForStatement(_) => {}
AstNodeRef::LValue(_) => {},
AstNodeRef::LValueSuffix(_) => {},
AstNodeRef::VariableUse(_) => {},
AstNodeRef::Expression(_) => {} AstNodeRef::Expression(_) => {}
AstNodeRef::TernaryExpression(_) => {} AstNodeRef::TernaryExpression(_) => {}
AstNodeRef::TernaryRhs(_) => {} AstNodeRef::TernaryRhs(_) => {}

View File

@ -1,16 +1,16 @@
# $schema: ./ast.schema.yaml # $schema: ./ast.schema.yaml
# Operators # Operators
Operator: Operator:
struct: struct:
children: children:
- inner: - inner:
member: member:
rule: OperatorInner rule: OperatorInner
- file_id: - file_id:
special: special:
kind: file_id kind: file_id
- range: - range:
special: special:
kind: range kind: range
OperatorInner: OperatorInner:
leaf_enum: leaf_enum:
@ -442,24 +442,24 @@ PlatformFunction:
- parameters - parameters
- return_type - return_type
PlatformOperatorFunction: PlatformOperatorFunction:
struct: struct:
children: children:
- is_public: - is_public:
member: member:
rule: Pub rule: Pub
build: build:
boolean: boolean:
on: rule_present on: rule_present
- platform_kw: - platform_kw:
skip: skip:
rule: Platform rule: Platform
- op_kw: - op_kw:
skip: skip:
rule: Op rule: Op
- generics: - generics:
member: member:
rule: GenericParameters rule: GenericParameters
build: build:
node: node:
or_else_default: true or_else_default: true
- operator - operator
@ -628,12 +628,8 @@ VariableDeclaration:
AssignmentStatement: AssignmentStatement:
struct: struct:
children: children:
- left: - l_value
member: - expression
rule: Expression
- right:
member:
rule: Expression
ExpressionStatement: ExpressionStatement:
struct: struct:
children: children:
@ -715,6 +711,30 @@ ForStatement:
skip: skip:
rule: End 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 # Expressions
Expression: Expression:
polymorphic_type: polymorphic_type:
@ -749,6 +769,9 @@ Expression:
- Literal: - Literal:
inner: inner:
kind: Literal kind: Literal
- VariableUse:
inner:
kind: VariableUse
- Fqn: - Fqn:
inner: inner:
kind: FullyQualifiedName kind: FullyQualifiedName
@ -1091,6 +1114,9 @@ PrimaryExpression:
- Literal: - Literal:
inner: inner:
kind: Literal kind: Literal
- VariableUse:
inner:
kind: VariableUse
- Fqn: - Fqn:
inner: inner:
kind: FullyQualifiedName kind: FullyQualifiedName

View File

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