WIP name gather, add fields for struct nodes.
This commit is contained in:
parent
3ab59961dd
commit
542d5f6c80
@ -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};
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<_>>();
|
||||
@ -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
|
||||
|
||||
@ -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,8 +113,12 @@ 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
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
deserialize_member_child(name, &props["member"])
|
||||
} else if props["special"].is_hash() {
|
||||
deserialize_special_child(name, &props["special"])
|
||||
deserialize_special_child(name, &props["special"])
|
||||
} else {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
@ -36,13 +46,11 @@ impl StructChild {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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,14 +250,14 @@ impl SpecialChild {
|
||||
pub fn new(name: &str, kind: SpecialChildKind) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
kind
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
|
||||
pub fn kind(&self) -> &SpecialChildKind {
|
||||
&self.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,
|
||||
}
|
||||
|
||||
@ -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)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(_) => {}
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
# $schema: ./ast.schema.yaml
|
||||
# Operators
|
||||
Operator:
|
||||
struct:
|
||||
struct:
|
||||
children:
|
||||
- inner:
|
||||
member:
|
||||
member:
|
||||
rule: OperatorInner
|
||||
- file_id:
|
||||
special:
|
||||
special:
|
||||
kind: file_id
|
||||
- range:
|
||||
special:
|
||||
special:
|
||||
kind: range
|
||||
OperatorInner:
|
||||
leaf_enum:
|
||||
@ -442,24 +442,24 @@ PlatformFunction:
|
||||
- parameters
|
||||
- return_type
|
||||
PlatformOperatorFunction:
|
||||
struct:
|
||||
struct:
|
||||
children:
|
||||
- is_public:
|
||||
member:
|
||||
member:
|
||||
rule: Pub
|
||||
build:
|
||||
boolean:
|
||||
build:
|
||||
boolean:
|
||||
on: rule_present
|
||||
- platform_kw:
|
||||
skip:
|
||||
skip:
|
||||
rule: Platform
|
||||
- op_kw:
|
||||
skip:
|
||||
rule: Op
|
||||
- generics:
|
||||
member:
|
||||
member:
|
||||
rule: GenericParameters
|
||||
build:
|
||||
build:
|
||||
node:
|
||||
or_else_default: true
|
||||
- operator
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user