diff --git a/ast-generator/src/build_fn/struct_build_fn.rs b/ast-generator/src/build_fn/struct_build_fn.rs index 5c0b3f6..962a8db 100644 --- a/ast-generator/src/build_fn/struct_build_fn.rs +++ b/ast-generator/src/build_fn/struct_build_fn.rs @@ -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 { +fn make_rule_matcher(child_spec: &StructChild) -> Option { 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 { 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 { +fn make_child_arg(child_spec: &StructChild) -> Option { 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 { 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::>(); @@ -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) -> #return_type_ident { #preamble - + #(#special_children;)* - + #(#child_holders;)* #iter_stream diff --git a/ast-generator/src/deserialize/struct_spec.rs b/ast-generator/src/deserialize/struct_spec.rs index bae37c8..720b824 100644 --- a/ast-generator/src/deserialize/struct_spec.rs +++ b/ast-generator/src/deserialize/struct_spec.rs @@ -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> { + 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) } diff --git a/ast-generator/src/spec/struct_spec.rs b/ast-generator/src/spec/struct_spec.rs index e8a593e..27cb7a1 100644 --- a/ast-generator/src/spec/struct_spec.rs +++ b/ast-generator/src/spec/struct_spec.rs @@ -1,13 +1,19 @@ pub struct StructSpec { build: String, children: Vec>, + fields: Vec>, } impl StructSpec { - pub fn new(build: &str, children: Vec>) -> Self { + pub fn new( + build: &str, + children: Vec>, + fields: Vec>, + ) -> Self { Self { build: build.to_string(), children, + fields, } } @@ -20,6 +26,10 @@ impl StructSpec { pub fn children(&self) -> impl Iterator { self.children.iter().map(Box::as_ref) } + + pub fn fields(&self) -> impl Iterator { + 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, +} diff --git a/ast-generator/src/type_gen/struct_type.rs b/ast-generator/src/type_gen/struct_type.rs index 72d3f1f..2ca4ee1 100644 --- a/ast-generator/src/type_gen/struct_type.rs +++ b/ast-generator/src/type_gen/struct_type.rs @@ -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 { +fn make_child_accessors(child: &StructChild) -> Option { 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 { } } +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::>(); + let annotated_fields = build_spec + .fields() + .map(|field| make_annotated_field(field)) + .collect::>(); + 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::>(); - let accessors = build_spec + let field_inits = build_spec + .fields() + .map(|field| make_field_init(field)) + .collect::>(); + + 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::>(); + let field_accessors = build_spec + .fields() + .map(|field| make_field_accessors(field)) + .collect::>(); + 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)* } } } diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index 14577bf..8b90cc9 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -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(_) => {} diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index df559fb..421916d 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -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 diff --git a/src/parser/deimos.pest b/src/parser/deimos.pest index 81cf3b8..4694984 100644 --- a/src/parser/deimos.pest +++ b/src/parser/deimos.pest @@ -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