From 93c6a7118585aaf718954640cea2b7104d2cf822 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Fri, 24 Oct 2025 14:33:55 -0500 Subject: [PATCH] WIP never ending name analysis. --- ast-generator/src/lib.rs | 2 +- src/bin/dmc/name_analysis.rs | 9 +- src/name_analysis/first_pass.rs | 193 ++++++++---------- src/name_analysis/mod.rs | 12 +- src/name_analysis/second_pass.rs | 178 +++++++--------- src/name_analysis/symbol/source_definition.rs | 11 +- src/name_analysis/symbol/use_symbol.rs | 18 +- .../{ => symbol_table}/fqn_context.rs | 1 + src/name_analysis/symbol_table/mod.rs | 44 ++++ .../{ => symbol_table}/symbol_tree.rs | 1 + src/name_analysis/util.rs | 9 - src/parser/ast.yaml | 45 +++- src/parser/deimos.pest | 26 ++- 13 files changed, 286 insertions(+), 263 deletions(-) rename src/name_analysis/{ => symbol_table}/fqn_context.rs (98%) rename src/name_analysis/{ => symbol_table}/symbol_tree.rs (99%) diff --git a/ast-generator/src/lib.rs b/ast-generator/src/lib.rs index df53b9f..daa926f 100644 --- a/ast-generator/src/lib.rs +++ b/ast-generator/src/lib.rs @@ -116,7 +116,7 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile { use std::range::Range; use std::rc::Rc; use std::cell::RefCell; - use crate::name_analysis::symbol::use_symbol::UseSymbol; + use crate::name_analysis::symbol::use_symbol::*; #(#types)* }; diff --git a/src/bin/dmc/name_analysis.rs b/src/bin/dmc/name_analysis.rs index f497647..2b6f75e 100644 --- a/src/bin/dmc/name_analysis.rs +++ b/src/bin/dmc/name_analysis.rs @@ -3,12 +3,12 @@ use codespan_reporting::term; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use deimos::ast::build::build_ast; use deimos::name_analysis::analyze_names; +use deimos::name_analysis::symbol_table::symbol_tree::SymbolTree; use deimos::name_analysis::symbol_table::SymbolTable; use deimos::parser::{DeimosParser, Rule}; use deimos::std_core::add_std_core_symbols; use pest::Parser; use std::path::PathBuf; -use deimos::name_analysis::symbol_tree::SymbolTree; pub fn name_analysis(paths: &Vec) -> Result<(), Box> { let mut compilation_units = vec![]; @@ -30,10 +30,13 @@ pub fn name_analysis(paths: &Vec) -> Result<(), Box { - if let Err(insert_error) = $symbol_table.$insert_method($symbol) { - util::handle_insert_error( - insert_error, - $name, - $node.file_id(), - $node.range(), - $symbol_kinds, - $diagnostics, - ) - } - }; -} - -pub fn nap1_compilation_unit( +pub fn na_p1_compilation_unit( file_name: &str, compilation_unit: &mut CompilationUnit, symbol_table: &mut SymbolTable, - symbol_tree: &mut SymbolTree, diagnostics: &mut Vec, ) { - let mut fqn_context = FqnContext::new(); - symbol_table.push_scope(&format!("FileScope {}", file_name)); - if let Some(namespace) = compilation_unit.namespace() { - for identifier in namespace.fqn().identifiers() { - fqn_context.push(identifier.name()); - } + symbol_table.set_current_fqn( + &namespace + .fqn() + .identifiers() + .map(Identifier::name) + .collect::>(), + ); } + symbol_table.push_scope(&format!("FileScope {}", file_name)); + for use_statement in compilation_unit.use_statements_mut() { - nap1_use_statement(use_statement, symbol_table, diagnostics); + na_p1_use_statement(use_statement, symbol_table, diagnostics); } symbol_table.pop_scope(); } -fn maybe_insert_concrete_use_symbol( - use_statement: &UseStatement, - identifier: &Identifier, - symbol_table: &mut SymbolTable, - diagnostics: &mut Vec, -) -> Option>> { - let base_fqn = use_statement_base_fqn(use_statement); - let to_insert = ConcreteUseSymbol::new( - &base_fqn, - identifier.name(), - Some(SourceDefinition::from_identifier(identifier)), - ); - match symbol_table.insert_concrete_use_symbol(to_insert) { - Ok(inserted) => Some(inserted), - Err(insert_error) => { - handle_insert_error( - insert_error, - identifier.name(), - identifier.file_id(), - identifier.range(), - "Use Symbol", - diagnostics, - ); - None - } - } -} - -fn nap1_use_statement( +fn na_p1_use_statement( use_statement: &mut UseStatement, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, ) { - let base_fqn = use_statement_base_fqn(use_statement); + match use_statement { + UseStatement::ConcreteUseStatement(concrete_use_statement) => { + na_p1_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics); + } + UseStatement::StarUseStatement(star_use_statement) => { + todo!() + } + } +} - match use_statement.suffix() { - UseStatementSuffix::Identifier(identifier) => { - let maybe_symbol = maybe_insert_concrete_use_symbol( - use_statement, - &identifier, +fn na_p1_concrete_use_statement( + concrete_use_statement: &mut ConcreteUseStatement, + symbol_table: &mut SymbolTable, + diagnostics: &mut Vec, +) { + let prefixes: Vec = concrete_use_statement + .prefixes() + .map(UseStatementPrefix::identifier) + .map(Identifier::name) + .map(ToString::to_string) + .collect::>(); + + match concrete_use_statement.suffix_mut() { + ConcreteUseStatementSuffix::UseStatementIdentifier(use_statement_identifier) => { + handle_concrete_use_statement_identifier( + &prefixes, + use_statement_identifier, symbol_table, diagnostics, ); - if let Some(concrete_use_symbol) = maybe_symbol { - use_statement.use_symbols_mut().push(UseSymbol::Concrete(concrete_use_symbol)); - } } - UseStatementSuffix::Star => { - let maybe_symbol = match symbol_table.insert_star_use_symbol( - StarUseSymbol::new(&base_fqn, Some(SourceDefinition::from_use_statement(use_statement))) - ) { - Ok(inserted) => { - Some(todo!()) - }, - Err(insert_error) => { - handle_insert_error( - insert_error, - &base_fqn, - use_statement.file_id(), - use_statement.range(), - "Star Use Symbol", - diagnostics, - ); - None - } - }; - } - UseStatementSuffix::UseList(use_list) => { - let maybe_symbols = use_list.identifiers() - .map(|identifier| { - maybe_insert_concrete_use_symbol( - use_statement, - identifier, - symbol_table, - diagnostics, - ) - }) - .collect::>(); - for maybe_symbol in maybe_symbols { - if let Some(symbol) = maybe_symbol { - use_statement.use_symbols_mut().push(UseSymbol::Concrete(symbol)); - } + ConcreteUseStatementSuffix::UseList(use_list) => { + for use_statement_identifier in use_list.identifiers_mut() { + handle_concrete_use_statement_identifier( + &prefixes, + use_statement_identifier, + symbol_table, + diagnostics, + ); } } } } + +fn handle_concrete_use_statement_identifier( + prefixes: &Vec, + use_statement_identifier: &mut UseStatementIdentifier, + symbol_table: &mut SymbolTable, + diagnostics: &mut Vec, +) { + let mut fqn_parts: Vec<&str> = vec![]; + for prefix in prefixes { + fqn_parts.push(prefix); + } + fqn_parts.push(use_statement_identifier.identifier().name()); + + let to_insert = ConcreteUseSymbol::new( + &fqn_parts, + Some(SourceDefinition::from_identifier( + use_statement_identifier.identifier(), + )), + ); + + match symbol_table.insert_concrete_use_symbol(to_insert) { + Ok(inserted) => { + use_statement_identifier.set_symbol(inserted); + } + Err(insert_error) => { + handle_insert_error( + insert_error, + use_statement_identifier.identifier().name(), + use_statement_identifier.identifier().file_id(), + use_statement_identifier.identifier().range(), + "Use Symbol", + diagnostics, + ); + } + } +} diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index 5249f94..4a1d3c6 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -23,40 +23,36 @@ The resolve phase has one main responsibility: resolve all references based on t use crate::ast::ast_node::AstNode; use crate::ast::node::CompilationUnit; use crate::diagnostic::DmDiagnostic; -use crate::name_analysis::first_pass::nap1_compilation_unit; -use crate::name_analysis::second_pass::nap2_compilation_unit; +use crate::name_analysis::first_pass::na_p1_compilation_unit; +use crate::name_analysis::second_pass::na_p2_compilation_unit; use crate::name_analysis::symbol_table::SymbolTable; use codespan_reporting::files::Files; use std::hash::Hash; -use crate::name_analysis::symbol_tree::SymbolTree; -pub(self) mod fqn_context; // mod resolve; mod first_pass; mod scope_table; mod second_pass; pub mod symbol; pub mod symbol_table; -pub mod symbol_tree; mod util; pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>( compilation_units: &mut Vec>, files: &'a F, symbol_table: &mut SymbolTable, - symbol_tree: &mut SymbolTree, ) -> Vec { let mut diagnostics = vec![]; // gather symbols for compilation_unit in compilation_units.iter_mut() { let file_name = files.name(compilation_unit.file_id()).unwrap(); - nap1_compilation_unit(&file_name, compilation_unit, symbol_table, symbol_tree, &mut diagnostics); + na_p1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics); } // resolve symbols for compilation_unit in compilation_units { - nap2_compilation_unit(compilation_unit, symbol_table, symbol_tree, &mut diagnostics); + na_p2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics); } diagnostics.into() diff --git a/src/name_analysis/second_pass.rs b/src/name_analysis/second_pass.rs index b4be3fd..0ab3ed7 100644 --- a/src/name_analysis/second_pass.rs +++ b/src/name_analysis/second_pass.rs @@ -1,125 +1,103 @@ -use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; +use crate::ast::node::{ + CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Identifier, UseStatement, + UseStatementIdentifier, UseStatementPrefix, +}; use crate::diagnostic::DmDiagnostic; -use crate::name_analysis::symbol::usable_symbol::UsableSymbol; -use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, UseSymbol}; use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; -use crate::name_analysis::symbol_tree::SymbolTree; -use crate::name_analysis::util::{handle_lookup_error, use_statement_base_fqn}; -use std::cell::RefCell; -use std::rc::Rc; +use crate::name_analysis::util::handle_lookup_error; -pub fn nap2_compilation_unit( +pub fn na_p2_compilation_unit( compilation_unit: &mut CompilationUnit, symbol_table: &SymbolTable, - symbol_tree: &SymbolTree, diagnostics: &mut Vec, ) { // TODO: check namespace for proper file name for use_statement in compilation_unit.use_statements_mut() { - nap2_use_statement(use_statement, symbol_tree, diagnostics); + na_p2_use_statement(use_statement, symbol_table, diagnostics); } // TODO: declarations } -fn find_usable_symbol( - use_statement: &UseStatement, - identifier: &Identifier, - symbol_tree: &SymbolTree, -) -> Option { - let fqn_parts: Vec<&str> = { - let mut base: Vec<&str> = use_statement - .prefixes() - .map(|prefix| prefix.identifier().name()) - .collect(); - base.push(identifier.name()); - base - }; - symbol_tree - .find_interface(&fqn_parts) - .map(|interface_symbol| UsableSymbol::Interface(interface_symbol)) - .or_else(|| { - symbol_tree - .find_class(&fqn_parts) - .map(|class_symbol| UsableSymbol::Class(class_symbol)) - }) - .or_else(|| { - symbol_tree - .find_function(&fqn_parts) - .map(|function_symbol| UsableSymbol::Function(function_symbol)) - }) -} - -fn find_matching_concrete_use_symbol( - use_statement: &UseStatement, - identifier: &Identifier, -) -> Option>> { - let base_fqn = use_statement_base_fqn(use_statement); - use_statement - .use_symbols() - .iter() - .find(|use_symbol| match use_symbol { - UseSymbol::Concrete(concrete_use_symbol) => { - let borrowed = concrete_use_symbol.borrow(); - borrowed.base_fqn() == base_fqn && borrowed.declared_name() == identifier.name() - } - _ => false, - }) - .map(|use_symbol| match use_symbol { - UseSymbol::Concrete(concrete) => concrete.clone(), - _ => panic!(), - }) -} - -fn handle_concrete_use( - use_statement: &UseStatement, - identifier: &Identifier, - symbol_tree: &SymbolTree, +fn na_p2_use_statement( + use_statement: &mut UseStatement, + symbol_table: &SymbolTable, diagnostics: &mut Vec, ) { - let maybe_usable_symbol = find_usable_symbol(use_statement, identifier, symbol_tree); - if let Some(usable_symbol) = maybe_usable_symbol { - let maybe_concrete_use_symbol = - find_matching_concrete_use_symbol(use_statement, identifier); - if let Some(concrete_use_symbol) = maybe_concrete_use_symbol { - concrete_use_symbol - .borrow_mut() - .set_resolved_symbol(usable_symbol); - } else { - panic!("Can't find matching ConcreteUseSymbol"); + match use_statement { + UseStatement::ConcreteUseStatement(concrete_use_statement) => { + na_p2_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics); } + UseStatement::StarUseStatement(star_use_statement) => { + todo!() + } + } +} + +fn na_p2_concrete_use_statement( + concrete_use_statement: &mut ConcreteUseStatement, + symbol_table: &SymbolTable, + diagnostics: &mut Vec, +) { + let base_fqn_parts: Vec = concrete_use_statement + .prefixes() + .map(UseStatementPrefix::identifier) + .map(Identifier::name) + .map(ToString::to_string) + .collect(); + + match concrete_use_statement.suffix_mut() { + ConcreteUseStatementSuffix::UseStatementIdentifier(use_statement_identifier) => { + handle_concrete_use_statement_identifier( + &base_fqn_parts, + use_statement_identifier, + symbol_table, + diagnostics, + ); + } + ConcreteUseStatementSuffix::UseList(use_list) => { + for use_statement_identifier in use_list.identifiers_mut() { + handle_concrete_use_statement_identifier( + &base_fqn_parts, + use_statement_identifier, + symbol_table, + diagnostics, + ); + } + } + } +} + +fn handle_concrete_use_statement_identifier( + base_fqn_parts: &[String], + use_statement_identifier: &mut UseStatementIdentifier, + symbol_table: &SymbolTable, + diagnostics: &mut Vec, +) { + let fqn_parts = { + let mut all_parts: Vec<&str> = vec![]; + for part in base_fqn_parts { + all_parts.push(part); + } + all_parts.push(use_statement_identifier.identifier().name()); + all_parts + }; + + let maybe_usable_symbol = symbol_table.find_usable_symbol(&fqn_parts); + if let Some(usable_symbol) = maybe_usable_symbol { + use_statement_identifier + .symbol_mut() + .expect("Should have set the symbol on the use statement already.") + .borrow_mut() + .set_resolved_symbol(usable_symbol); } else { handle_lookup_error( SymbolLookupError::NoDefinition, - &format!( - "{}::{}", - use_statement_base_fqn(use_statement), - identifier.name() - ), - use_statement.file_id(), - use_statement.range(), + &fqn_parts.join("::"), + use_statement_identifier.identifier().file_id(), + use_statement_identifier.identifier().range(), "Usable Symbol", diagnostics, ); } } - -fn nap2_use_statement( - use_statement: &mut UseStatement, - symbol_tree: &SymbolTree, - diagnostics: &mut Vec, -) { - match use_statement.suffix() { - UseStatementSuffix::Identifier(identifier) => { - handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics); - } - UseStatementSuffix::Star => { - todo!("Resolve star symbols") - } - UseStatementSuffix::UseList(use_list) => { - for identifier in use_list.identifiers() { - handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics); - } - } - } -} diff --git a/src/name_analysis/symbol/source_definition.rs b/src/name_analysis/symbol/source_definition.rs index 73a030b..5f96d6b 100644 --- a/src/name_analysis/symbol/source_definition.rs +++ b/src/name_analysis/symbol/source_definition.rs @@ -1,7 +1,5 @@ -use std::cell::RefCell; +use crate::ast::node::{Identifier, Operator}; use std::range::Range; -use std::rc::Rc; -use crate::ast::node::{Identifier, Operator, UseStatement}; #[derive(Clone, Debug)] pub struct SourceDefinition { @@ -17,13 +15,6 @@ impl SourceDefinition { } } - pub fn from_use_statement(use_statement: &UseStatement) -> Self { - Self { - file_id: use_statement.file_id(), - range: use_statement.range(), - } - } - pub fn from_operator(operator: &Operator) -> Self { Self { file_id: operator.file_id(), diff --git a/src/name_analysis/symbol/use_symbol.rs b/src/name_analysis/symbol/use_symbol.rs index 182a38a..9b1a575 100644 --- a/src/name_analysis/symbol/use_symbol.rs +++ b/src/name_analysis/symbol/use_symbol.rs @@ -21,32 +21,29 @@ impl UseSymbol { #[derive(Clone)] pub struct ConcreteUseSymbol { - base_fqn: String, - declared_name: String, + fqn_parts: Vec, source_definition: Option, resolved_symbol: Option, } impl ConcreteUseSymbol { pub fn new( - base_fqn: &str, - declared_name: &str, + fqn_parts: &[&str], source_definition: Option, ) -> Self { Self { - base_fqn: base_fqn.to_string(), - declared_name: declared_name.to_string(), + fqn_parts: fqn_parts.iter().map(ToString::to_string).collect(), source_definition, resolved_symbol: None, } } - pub fn base_fqn(&self) -> &str { - &self.base_fqn + pub fn fqn_parts(&self) -> &[String] { + self.fqn_parts.as_slice() } pub fn declared_name(&self) -> &str { - &self.declared_name + self.fqn_parts.last().unwrap() } pub fn source_definition(&self) -> Option<&SourceDefinition> { @@ -65,8 +62,7 @@ impl ConcreteUseSymbol { impl Debug for ConcreteUseSymbol { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("ConcreteUseStatementSymbol") - .field("base_fqn", &self.base_fqn) - .field("declared_name", &self.declared_name) + .field("fqn_parts", &self.fqn_parts) .field("source_definition", &self.source_definition) .finish() } diff --git a/src/name_analysis/fqn_context.rs b/src/name_analysis/symbol_table/fqn_context.rs similarity index 98% rename from src/name_analysis/fqn_context.rs rename to src/name_analysis/symbol_table/fqn_context.rs index fd3ef36..1605b99 100644 --- a/src/name_analysis/fqn_context.rs +++ b/src/name_analysis/symbol_table/fqn_context.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub struct FqnContext { stack: Vec, } diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs index e6cde8f..27b4577 100644 --- a/src/name_analysis/symbol_table/mod.rs +++ b/src/name_analysis/symbol_table/mod.rs @@ -5,6 +5,8 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol}; use crate::name_analysis::symbol::variable_symbol::VariableSymbol; use crate::name_analysis::symbol::*; +use crate::name_analysis::symbol_table::fqn_context::FqnContext; +use crate::name_analysis::symbol_table::symbol_tree::SymbolTree; use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; use scope::Scope; @@ -12,8 +14,11 @@ use std::cell::RefCell; use std::fmt::Display; use std::ops::Deref; use std::rc::Rc; +use crate::name_analysis::symbol::usable_symbol::UsableSymbol; +pub(self) mod fqn_context; mod scope; +pub mod symbol_tree; #[derive(Debug)] pub enum SymbolInsertError { @@ -29,6 +34,8 @@ pub enum SymbolLookupError { pub struct SymbolTable { scopes: Vec, current_scope_id: usize, + symbol_tree: Box, + fqn_context: Box, } /// Contains a vec of scopes, like a flattened tree @@ -37,6 +44,8 @@ impl SymbolTable { Self { scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))], current_scope_id: 0, + symbol_tree: Box::new(SymbolTree::new()), + fqn_context: Box::new(FqnContext::new()), } } @@ -60,6 +69,41 @@ impl SymbolTable { self.current_scope_id = parent_id; } } + + pub fn set_current_fqn(&mut self, names: &[&str]) { + self.fqn_context = Box::new(FqnContext::new()); + for name in names { + self.fqn_context.push(*name); + } + } + + pub fn push_fqn_part(&mut self, part: &str) { + self.fqn_context.push(part); + } + + pub fn pop_fqn_part(&mut self) { + self.fqn_context.pop(); + } + + pub fn symbol_tree(&self) -> &SymbolTree { + &self.symbol_tree + } + + pub fn find_usable_symbol(&self, fqn_parts: &[&str]) -> Option { + self.symbol_tree + .find_interface(fqn_parts) + .map(|interface_symbol| UsableSymbol::Interface(interface_symbol)) + .or_else(|| { + self.symbol_tree + .find_class(fqn_parts) + .map(|class_symbol| UsableSymbol::Class(class_symbol)) + }) + .or_else(|| { + self.symbol_tree + .find_function(fqn_parts) + .map(|function_symbol| UsableSymbol::Function(function_symbol)) + }) + } fn current_scope(&self) -> &Scope { &self.scopes[self.current_scope_id] diff --git a/src/name_analysis/symbol_tree.rs b/src/name_analysis/symbol_table/symbol_tree.rs similarity index 99% rename from src/name_analysis/symbol_tree.rs rename to src/name_analysis/symbol_table/symbol_tree.rs index 9c06668..dadd453 100644 --- a/src/name_analysis/symbol_tree.rs +++ b/src/name_analysis/symbol_table/symbol_tree.rs @@ -5,6 +5,7 @@ use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol; use std::collections::HashMap; use std::rc::Rc; +#[derive(Debug)] pub struct SymbolTree { children: Box>, classes: Box>>>, diff --git a/src/name_analysis/util.rs b/src/name_analysis/util.rs index a2b4850..e3e7ce1 100644 --- a/src/name_analysis/util.rs +++ b/src/name_analysis/util.rs @@ -1,17 +1,8 @@ -use crate::ast::node::UseStatement; use crate::diagnostic::DmDiagnostic; use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolLookupError}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use std::range::Range; -pub fn use_statement_base_fqn(use_statement: &UseStatement) -> String { - use_statement - .prefixes() - .map(|prefix| prefix.identifier().name()) - .collect::>() - .join("::") -} - pub fn handle_insert_error( err: SymbolInsertError, error_symbol_name: &str, diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index d593336..1628408 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -231,6 +231,11 @@ Namespace: member: rule: FullyQualifiedName UseStatement: + tree_enum: + rules: + - ConcreteUseStatement + - StarUseStatement +ConcreteUseStatement: struct: children: - use_kw: @@ -241,34 +246,54 @@ UseStatement: rule: UseStatementPrefix - suffix: member: - rule: UseStatementSuffix + rule: ConcreteUseStatementSuffix + - file_id: + special: + kind: file_id + - range: + special: + kind: range +StarUseStatement: + struct: + children: + - use_kw: + skip: + rule: Use + - prefixes: + vec: + rule: UseStatementPrefix + - star_sym: + skip: + rule: Star - file_id: special: kind: file_id - range: special: kind: range - fields: - - use_symbols: - kind: UseSymbol - vec: true UseStatementPrefix: struct: children: - identifier -UseStatementSuffix: +ConcreteUseStatementSuffix: tree_enum: rules: - - Identifier - - Star: - child: false + - UseStatementIdentifier - UseList +UseStatementIdentifier: + struct: + children: + - identifier + fields: + - symbol: + kind: ConcreteUseSymbol + wrap: rc_ref_cell UseList: struct: children: - identifiers: vec: - rule: Identifier + rule: UseStatementIdentifier # Level declarations ModuleLevelDeclaration: diff --git a/src/parser/deimos.pest b/src/parser/deimos.pest index 6872bf0..8c083ea 100644 --- a/src/parser/deimos.pest +++ b/src/parser/deimos.pest @@ -322,9 +322,20 @@ Namespace = { } UseStatement = { + ConcreteUseStatement + | StarUseStatement +} + +ConcreteUseStatement = { Use ~ UseStatementPrefix* - ~ UseStatementSuffix + ~ ConcreteUseStatementSuffix +} + +StarUseStatement = { + Use + ~ UseStatementPrefix* + ~ Star } UseStatementPrefix = { @@ -332,16 +343,19 @@ UseStatementPrefix = { ~ "::" } -UseStatementSuffix = { - Identifier - | Star +ConcreteUseStatementSuffix = { + UseStatementIdentifier | UseList } +UseStatementIdentifier = { + Identifier +} + UseList = { "{" - ~ Identifier - ~ ( "," ~ Identifier )* + ~ UseStatementIdentifier + ~ ( "," ~ UseStatementIdentifier )* ~ "}" }