Compare commits
2 Commits
b5c0e44eeb
...
664aebfd61
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
664aebfd61 | ||
|
|
bdbc2543b8 |
@ -9,16 +9,15 @@ fn deserialize_field(field_yaml: &Yaml) -> StructField {
|
|||||||
let (name, props) = unwrap_single_member_hash(field_yaml);
|
let (name, props) = unwrap_single_member_hash(field_yaml);
|
||||||
let kind = props["kind"].as_str().unwrap();
|
let kind = props["kind"].as_str().unwrap();
|
||||||
let wrap = if let Some(wrap) = props["wrap"].as_str() {
|
let wrap = if let Some(wrap) = props["wrap"].as_str() {
|
||||||
match wrap {
|
match wrap {
|
||||||
"rc_ref_cell" => {
|
"rc_ref_cell" => Some(StructFieldWrap::RcRefCell),
|
||||||
Some(StructFieldWrap::RcRefCell)
|
_ => panic!(),
|
||||||
}
|
|
||||||
_ => panic!()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
StructField::new(&name, kind, wrap)
|
let vec = get_as_bool(&props["vec"]);
|
||||||
|
StructField::new(&name, kind, wrap, vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_skip_child(props: &Yaml) -> StructChild {
|
fn deserialize_skip_child(props: &Yaml) -> StructChild {
|
||||||
@ -112,8 +111,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 {
|
||||||
@ -124,7 +127,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);
|
||||||
}
|
}
|
||||||
@ -167,9 +170,10 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
|
|||||||
} else {
|
} else {
|
||||||
deserialize_error!("array", "children", name);
|
deserialize_error!("array", "children", name);
|
||||||
};
|
};
|
||||||
|
|
||||||
let fields = if struct_yaml["fields"].is_array() {
|
let fields = if struct_yaml["fields"].is_array() {
|
||||||
struct_yaml["fields"].as_vec()
|
struct_yaml["fields"]
|
||||||
|
.as_vec()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|field| deserialize_field(field))
|
.map(|field| deserialize_field(field))
|
||||||
@ -178,9 +182,10 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
|
|||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
let derive = if struct_yaml["derive"].is_array() {
|
let derive = if struct_yaml["derive"].is_array() {
|
||||||
struct_yaml["derive"].as_vec()
|
struct_yaml["derive"]
|
||||||
|
.as_vec()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|derive| derive.as_str().unwrap().to_string())
|
.map(|derive| derive.as_str().unwrap().to_string())
|
||||||
@ -188,6 +193,6 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec {
|
|||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
StructSpec::new(name, children, fields, derive)
|
StructSpec::new(name, children, fields, derive)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,12 @@ pub struct StructSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StructSpec {
|
impl StructSpec {
|
||||||
pub fn new(build: &str, children: Vec<Box<StructChild>>, fields: Vec<Box<StructField>>, derive: Vec<String>) -> Self {
|
pub fn new(
|
||||||
|
build: &str,
|
||||||
|
children: Vec<Box<StructChild>>,
|
||||||
|
fields: Vec<Box<StructField>>,
|
||||||
|
derive: Vec<String>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
build: build.to_string(),
|
build: build.to_string(),
|
||||||
children,
|
children,
|
||||||
@ -24,11 +29,11 @@ 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> {
|
pub fn fields(&self) -> impl Iterator<Item = &StructField> {
|
||||||
self.fields.iter().map(Box::as_ref)
|
self.fields.iter().map(Box::as_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive(&self) -> &[String] {
|
pub fn derive(&self) -> &[String] {
|
||||||
&self.derive
|
&self.derive
|
||||||
}
|
}
|
||||||
@ -48,13 +53,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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,14 +257,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
|
||||||
}
|
}
|
||||||
@ -278,31 +281,37 @@ pub struct StructField {
|
|||||||
name: String,
|
name: String,
|
||||||
kind: String,
|
kind: String,
|
||||||
wrap: Option<StructFieldWrap>,
|
wrap: Option<StructFieldWrap>,
|
||||||
|
vec: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructField {
|
impl StructField {
|
||||||
pub fn new(name: &str, kind: &str, wrap: Option<StructFieldWrap>) -> Self {
|
pub fn new(name: &str, kind: &str, wrap: Option<StructFieldWrap>, vec: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
kind: kind.to_string(),
|
kind: kind.to_string(),
|
||||||
wrap,
|
wrap,
|
||||||
|
vec,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> &str {
|
pub fn kind(&self) -> &str {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wrap(&self) -> Option<&StructFieldWrap> {
|
pub fn wrap(&self) -> Option<&StructFieldWrap> {
|
||||||
self.wrap.as_ref()
|
self.wrap.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vec(&self) -> bool {
|
||||||
|
self.vec
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum StructFieldWrap {
|
pub enum StructFieldWrap {
|
||||||
RcRefCell
|
RcRefCell,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,35 +19,51 @@ fn make_field_accessors(field: &StructField) -> TokenStream {
|
|||||||
quote! { #inner }
|
quote! { #inner }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let set_field_ident = format_ident!("set_{}", field.name());
|
|
||||||
let field_ident_mut = format_ident!("{}_mut", field.name());
|
let field_ident_mut = format_ident!("{}_mut", field.name());
|
||||||
|
|
||||||
quote! {
|
if field.vec() {
|
||||||
pub fn #field_ident(&self) -> Option<&#field_type> {
|
quote! {
|
||||||
self.#field_ident.as_ref()
|
pub fn #field_ident(&self) -> &[#field_type] {
|
||||||
}
|
self.#field_ident.as_slice()
|
||||||
|
}
|
||||||
pub fn #field_ident_mut(&mut self) -> Option<&mut #field_type> {
|
|
||||||
self.#field_ident.as_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn #set_field_ident(&mut self, #field_ident: #field_type) {
|
pub fn #field_ident_mut(&mut self) -> &mut Vec<#field_type> {
|
||||||
self.#field_ident = Some(#field_ident);
|
&mut self.#field_ident
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let set_field_ident = format_ident!("set_{}", field.name());
|
||||||
|
quote! {
|
||||||
|
pub fn #field_ident(&self) -> Option<&#field_type> {
|
||||||
|
self.#field_ident.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn #field_ident_mut(&mut self) -> Option<&mut #field_type> {
|
||||||
|
self.#field_ident.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn #set_field_ident(&mut self, #field_ident: #field_type) {
|
||||||
|
self.#field_ident = Some(#field_ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_field_initializer(field: &StructField) -> TokenStream {
|
fn make_field_initializer(field: &StructField) -> TokenStream {
|
||||||
let field_ident = format_ident!("{}", field.name());
|
let field_ident = format_ident!("{}", field.name());
|
||||||
quote! { #field_ident: None }
|
if field.vec() {
|
||||||
|
quote! { #field_ident: vec![] }
|
||||||
|
} else {
|
||||||
|
quote! { #field_ident: None }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_annotated_field(field: &StructField) -> TokenStream {
|
fn make_annotated_field(field: &StructField) -> TokenStream {
|
||||||
let field_ident = format_ident!("{}", field.name());
|
let field_ident = format_ident!("{}", field.name());
|
||||||
let field_type = if let Some(wrap) = field.wrap() {
|
let field_type = if let Some(wrap) = field.wrap() {
|
||||||
|
let inner = format_ident!("{}", field.kind());
|
||||||
match wrap {
|
match wrap {
|
||||||
StructFieldWrap::RcRefCell => {
|
StructFieldWrap::RcRefCell => {
|
||||||
let inner = format_ident!("{}", field.kind());
|
|
||||||
quote! { Rc<RefCell<#inner>> }
|
quote! { Rc<RefCell<#inner>> }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,8 +72,14 @@ fn make_annotated_field(field: &StructField) -> TokenStream {
|
|||||||
quote! { #inner }
|
quote! { #inner }
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
if field.vec() {
|
||||||
#field_ident: Option<#field_type>
|
quote! {
|
||||||
|
#field_ident: Vec<#field_type>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
#field_ident: Option<#field_type>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use deimos::parser::{DeimosParser, Rule};
|
|||||||
use deimos::std_core::add_std_core_symbols;
|
use deimos::std_core::add_std_core_symbols;
|
||||||
use pest::Parser;
|
use pest::Parser;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use deimos::name_analysis::symbol_tree::SymbolTree;
|
||||||
|
|
||||||
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut compilation_units = vec![];
|
let mut compilation_units = vec![];
|
||||||
@ -29,9 +30,10 @@ pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Err
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
let mut symbol_tree = SymbolTree::new();
|
||||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
|
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
|
||||||
|
|
||||||
let diagnostics = analyze_names(&mut compilation_units, &files, &mut symbol_table);
|
let diagnostics = analyze_names(&mut compilation_units, &files, &mut symbol_table, &mut symbol_tree);
|
||||||
if diagnostics.is_empty() {
|
if diagnostics.is_empty() {
|
||||||
println!("Name analysis complete.");
|
println!("Name analysis complete.");
|
||||||
println!("{}", symbol_table);
|
println!("{}", symbol_table);
|
||||||
|
|||||||
@ -1,51 +1,19 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
|
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
|
||||||
use crate::diagnostic::DmDiagnostic;
|
use crate::diagnostic::DmDiagnostic;
|
||||||
use crate::name_analysis::fqn_context::FqnContext;
|
use crate::name_analysis::fqn_context::FqnContext;
|
||||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
|
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
|
||||||
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::name_analysis::symbol_table::SymbolTable;
|
||||||
use crate::name_analysis::util::use_statement_base_fqn;
|
use crate::name_analysis::symbol_tree::SymbolTree;
|
||||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
use crate::name_analysis::util;
|
||||||
use std::range::Range;
|
use crate::name_analysis::util::{handle_insert_error, use_statement_base_fqn};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn handle_insert_error(
|
|
||||||
err: SymbolInsertError,
|
|
||||||
error_symbol_name: &str,
|
|
||||||
error_file_id: usize,
|
|
||||||
error_range: Range<usize>,
|
|
||||||
symbol_types: &str,
|
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
|
||||||
) {
|
|
||||||
match err {
|
|
||||||
SymbolInsertError::SymbolAlreadyDefined(s) => {
|
|
||||||
let mut diagnostic = Diagnostic::error()
|
|
||||||
.with_message(format!(
|
|
||||||
"{} symbol '{}' already defined in the current scope.",
|
|
||||||
symbol_types, error_symbol_name,
|
|
||||||
))
|
|
||||||
.with_label(
|
|
||||||
Label::primary(error_file_id, error_range)
|
|
||||||
.with_message("Symbol duplicated here."),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(source_definition) = s.definition() {
|
|
||||||
diagnostic = diagnostic.with_label(
|
|
||||||
Label::secondary(source_definition.file_id(), source_definition.range())
|
|
||||||
.with_message("Symbol defined here."),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! insert_symbol {
|
macro_rules! insert_symbol {
|
||||||
($insert_method:ident, $symbol:expr, $symbol_table:ident, $name:expr, $node:ident, $symbol_kinds:literal, $diagnostics:ident) => {
|
($insert_method:ident, $symbol:expr, $symbol_table:ident, $name:expr, $node:ident, $symbol_kinds:literal, $diagnostics:ident) => {
|
||||||
if let Err(insert_error) = $symbol_table.$insert_method($symbol) {
|
if let Err(insert_error) = $symbol_table.$insert_method($symbol) {
|
||||||
handle_insert_error(
|
util::handle_insert_error(
|
||||||
insert_error,
|
insert_error,
|
||||||
$name,
|
$name,
|
||||||
$node.file_id(),
|
$node.file_id(),
|
||||||
@ -57,24 +25,11 @@ macro_rules! insert_symbol {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! insert_concrete_use_symbol {
|
|
||||||
($symbol:expr, $symbol_table:ident, $symbol_name:expr, $source_node:ident, $symbol_kinds:literal, $diagnostics:ident) => {
|
|
||||||
insert_symbol!(
|
|
||||||
insert_concrete_use_symbol,
|
|
||||||
$symbol,
|
|
||||||
$symbol_table,
|
|
||||||
$symbol_name,
|
|
||||||
$source_node,
|
|
||||||
$symbol_kinds,
|
|
||||||
$diagnostics
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nap1_compilation_unit(
|
pub fn nap1_compilation_unit(
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
compilation_unit: &mut CompilationUnit,
|
compilation_unit: &mut CompilationUnit,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
|
symbol_tree: &mut SymbolTree,
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
) {
|
) {
|
||||||
let mut fqn_context = FqnContext::new();
|
let mut fqn_context = FqnContext::new();
|
||||||
@ -93,22 +48,20 @@ pub fn nap1_compilation_unit(
|
|||||||
symbol_table.pop_scope();
|
symbol_table.pop_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_concrete_use_statement(
|
fn maybe_insert_concrete_use_symbol(
|
||||||
use_statement: &mut UseStatement,
|
use_statement: &UseStatement,
|
||||||
identifier: &Identifier,
|
identifier: &Identifier,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
) {
|
) -> Option<Rc<RefCell<ConcreteUseSymbol>>> {
|
||||||
let base_fqn = use_statement_base_fqn(use_statement);
|
let base_fqn = use_statement_base_fqn(use_statement);
|
||||||
let to_insert = ConcreteUseSymbol::new(
|
let to_insert = ConcreteUseSymbol::new(
|
||||||
&base_fqn,
|
&base_fqn,
|
||||||
identifier.name(),
|
identifier.name(),
|
||||||
Some(SourceDefinition::from_identifier(identifier))
|
Some(SourceDefinition::from_identifier(identifier)),
|
||||||
);
|
);
|
||||||
match symbol_table.insert_concrete_use_symbol(to_insert) {
|
match symbol_table.insert_concrete_use_symbol(to_insert) {
|
||||||
Ok(inserted) => {
|
Ok(inserted) => Some(inserted),
|
||||||
use_statement.set_use_symbol(Rc::new(RefCell::new(UseSymbol::Concrete(inserted))));
|
|
||||||
}
|
|
||||||
Err(insert_error) => {
|
Err(insert_error) => {
|
||||||
handle_insert_error(
|
handle_insert_error(
|
||||||
insert_error,
|
insert_error,
|
||||||
@ -116,8 +69,9 @@ fn handle_concrete_use_statement(
|
|||||||
identifier.file_id(),
|
identifier.file_id(),
|
||||||
identifier.range(),
|
identifier.range(),
|
||||||
"Use Symbol",
|
"Use Symbol",
|
||||||
diagnostics
|
diagnostics,
|
||||||
);
|
);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,47 +85,51 @@ fn nap1_use_statement(
|
|||||||
|
|
||||||
match use_statement.suffix() {
|
match use_statement.suffix() {
|
||||||
UseStatementSuffix::Identifier(identifier) => {
|
UseStatementSuffix::Identifier(identifier) => {
|
||||||
insert_concrete_use_symbol!(
|
let maybe_symbol = maybe_insert_concrete_use_symbol(
|
||||||
ConcreteUseSymbol::new(
|
use_statement,
|
||||||
&base_fqn,
|
&identifier,
|
||||||
identifier.name(),
|
|
||||||
Some(SourceDefinition::from_identifier(identifier))
|
|
||||||
),
|
|
||||||
symbol_table,
|
symbol_table,
|
||||||
&base_fqn,
|
diagnostics,
|
||||||
identifier,
|
);
|
||||||
"Use Statement",
|
if let Some(concrete_use_symbol) = maybe_symbol {
|
||||||
diagnostics
|
use_statement.use_symbols_mut().push(UseSymbol::Concrete(concrete_use_symbol));
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
UseStatementSuffix::Star => {
|
UseStatementSuffix::Star => {
|
||||||
insert_symbol!(
|
let maybe_symbol = match symbol_table.insert_star_use_symbol(
|
||||||
insert_star_use_symbol,
|
StarUseSymbol::new(&base_fqn, Some(SourceDefinition::from_use_statement(use_statement)))
|
||||||
StarUseSymbol::new(
|
) {
|
||||||
&base_fqn,
|
Ok(inserted) => {
|
||||||
Some(SourceDefinition::from_use_statement(use_statement))
|
Some(todo!())
|
||||||
),
|
},
|
||||||
symbol_table,
|
Err(insert_error) => {
|
||||||
&base_fqn,
|
handle_insert_error(
|
||||||
use_statement,
|
insert_error,
|
||||||
"Use Statement",
|
&base_fqn,
|
||||||
diagnostics
|
use_statement.file_id(),
|
||||||
);
|
use_statement.range(),
|
||||||
|
"Star Use Symbol",
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
UseStatementSuffix::UseList(use_list) => {
|
UseStatementSuffix::UseList(use_list) => {
|
||||||
for identifier in use_list.identifiers() {
|
let maybe_symbols = use_list.identifiers()
|
||||||
insert_concrete_use_symbol!(
|
.map(|identifier| {
|
||||||
ConcreteUseSymbol::new(
|
maybe_insert_concrete_use_symbol(
|
||||||
&base_fqn,
|
use_statement,
|
||||||
identifier.name(),
|
identifier,
|
||||||
Some(SourceDefinition::from_identifier(identifier))
|
symbol_table,
|
||||||
),
|
diagnostics,
|
||||||
symbol_table,
|
)
|
||||||
&base_fqn,
|
})
|
||||||
identifier,
|
.collect::<Vec<_>>();
|
||||||
"Use Statement",
|
for maybe_symbol in maybe_symbols {
|
||||||
diagnostics
|
if let Some(symbol) = maybe_symbol {
|
||||||
);
|
use_statement.use_symbols_mut().push(UseSymbol::Concrete(symbol));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ use crate::name_analysis::second_pass::nap2_compilation_unit;
|
|||||||
use crate::name_analysis::symbol_table::SymbolTable;
|
use crate::name_analysis::symbol_table::SymbolTable;
|
||||||
use codespan_reporting::files::Files;
|
use codespan_reporting::files::Files;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use crate::name_analysis::symbol_tree::SymbolTree;
|
||||||
|
|
||||||
pub(self) mod fqn_context;
|
pub(self) mod fqn_context;
|
||||||
// mod resolve;
|
// mod resolve;
|
||||||
@ -36,24 +37,26 @@ mod scope_table;
|
|||||||
mod second_pass;
|
mod second_pass;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod symbol_table;
|
pub mod symbol_table;
|
||||||
|
pub mod symbol_tree;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
|
||||||
compilation_units: &mut Vec<Box<CompilationUnit>>,
|
compilation_units: &mut Vec<Box<CompilationUnit>>,
|
||||||
files: &'a F,
|
files: &'a F,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
|
symbol_tree: &mut SymbolTree,
|
||||||
) -> Vec<DmDiagnostic> {
|
) -> Vec<DmDiagnostic> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
// gather symbols
|
// gather symbols
|
||||||
for compilation_unit in compilation_units.iter_mut() {
|
for compilation_unit in compilation_units.iter_mut() {
|
||||||
let file_name = files.name(compilation_unit.file_id()).unwrap();
|
let file_name = files.name(compilation_unit.file_id()).unwrap();
|
||||||
nap1_compilation_unit(&file_name, compilation_unit, symbol_table, &mut diagnostics);
|
nap1_compilation_unit(&file_name, compilation_unit, symbol_table, symbol_tree, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve symbols
|
// resolve symbols
|
||||||
for compilation_unit in compilation_units {
|
for compilation_unit in compilation_units {
|
||||||
nap2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
nap2_compilation_unit(compilation_unit, symbol_table, symbol_tree, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.into()
|
diagnostics.into()
|
||||||
|
|||||||
@ -1,97 +1,124 @@
|
|||||||
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
|
use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix};
|
||||||
use crate::diagnostic::DmDiagnostic;
|
use crate::diagnostic::DmDiagnostic;
|
||||||
use crate::name_analysis::symbol::use_symbol::UseSymbol;
|
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_table::{SymbolLookupError, SymbolTable};
|
||||||
use crate::name_analysis::util::use_statement_base_fqn;
|
use crate::name_analysis::symbol_tree::SymbolTree;
|
||||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
use crate::name_analysis::util::{handle_lookup_error, use_statement_base_fqn};
|
||||||
use std::range::Range;
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
fn handle_lookup_error(
|
|
||||||
err: SymbolLookupError,
|
|
||||||
error_symbol_name: &str,
|
|
||||||
error_file_id: usize,
|
|
||||||
error_range: Range<usize>,
|
|
||||||
symbol_types: &str,
|
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
|
||||||
) {
|
|
||||||
match err {
|
|
||||||
SymbolLookupError::NoDefinition => {
|
|
||||||
let diagnostic = Diagnostic::error()
|
|
||||||
.with_message(format!(
|
|
||||||
"No such {} symbol '{}' in scope.",
|
|
||||||
symbol_types, error_symbol_name,
|
|
||||||
))
|
|
||||||
.with_label(
|
|
||||||
Label::primary(error_file_id, error_range).with_message("Symbol used here."),
|
|
||||||
);
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nap2_compilation_unit(
|
pub fn nap2_compilation_unit(
|
||||||
compilation_unit: &mut CompilationUnit,
|
compilation_unit: &mut CompilationUnit,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
symbol_tree: &SymbolTree,
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
) {
|
) {
|
||||||
// TODO: check namespace for proper file name
|
// TODO: check namespace for proper file name
|
||||||
for use_statement in compilation_unit.use_statements_mut() {
|
for use_statement in compilation_unit.use_statements_mut() {
|
||||||
nap2_use_statement(use_statement, symbol_table, diagnostics);
|
nap2_use_statement(use_statement, symbol_tree, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: declarations
|
// TODO: declarations
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nap2_use_statement(
|
fn find_usable_symbol(
|
||||||
use_statement: &mut UseStatement,
|
use_statement: &UseStatement,
|
||||||
symbol_table: &SymbolTable,
|
identifier: &Identifier,
|
||||||
|
symbol_tree: &SymbolTree,
|
||||||
|
) -> Option<UsableSymbol> {
|
||||||
|
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<Rc<RefCell<ConcreteUseSymbol>>> {
|
||||||
|
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,
|
||||||
diagnostics: &mut Vec<DmDiagnostic>,
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
) {
|
) {
|
||||||
let base_fqn = use_statement_base_fqn(use_statement);
|
let maybe_usable_symbol = find_usable_symbol(use_statement, identifier, symbol_tree);
|
||||||
|
if let Some(usable_symbol) = maybe_usable_symbol {
|
||||||
let mut handle_concrete_use_symbol = |identifier: &Identifier| {
|
let maybe_concrete_use_symbol =
|
||||||
let fqn = format!("{}::{}", base_fqn, identifier.name());
|
find_matching_concrete_use_symbol(use_statement, identifier);
|
||||||
match symbol_table.resolve_concrete_usable_by_fqn(&fqn) {
|
if let Some(concrete_use_symbol) = maybe_concrete_use_symbol {
|
||||||
Ok(resolved_symbol) => match *use_statement.use_symbol().unwrap().borrow() {
|
concrete_use_symbol
|
||||||
UseSymbol::Concrete(ref concrete_use_symbol) => {
|
.borrow_mut()
|
||||||
concrete_use_symbol
|
.set_resolved_symbol(usable_symbol);
|
||||||
.borrow_mut()
|
} else {
|
||||||
.set_resolved_symbol(resolved_symbol);
|
panic!("Can't find matching ConcreteUseSymbol");
|
||||||
}
|
|
||||||
_ => panic!("Unexpected symbol type"),
|
|
||||||
},
|
|
||||||
Err(lookup_error) => {
|
|
||||||
handle_lookup_error(
|
|
||||||
lookup_error,
|
|
||||||
&fqn,
|
|
||||||
use_statement.file_id(),
|
|
||||||
use_statement.range(),
|
|
||||||
"Usable Symbol",
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
|
handle_lookup_error(
|
||||||
|
SymbolLookupError::NoDefinition,
|
||||||
|
&format!(
|
||||||
|
"{}::{}",
|
||||||
|
use_statement_base_fqn(use_statement),
|
||||||
|
identifier.name()
|
||||||
|
),
|
||||||
|
use_statement.file_id(),
|
||||||
|
use_statement.range(),
|
||||||
|
"Usable Symbol",
|
||||||
|
diagnostics,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nap2_use_statement(
|
||||||
|
use_statement: &mut UseStatement,
|
||||||
|
symbol_tree: &SymbolTree,
|
||||||
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
|
) {
|
||||||
match use_statement.suffix() {
|
match use_statement.suffix() {
|
||||||
UseStatementSuffix::Identifier(identifier) => {
|
UseStatementSuffix::Identifier(identifier) => {
|
||||||
handle_concrete_use_symbol(identifier);
|
handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics);
|
||||||
}
|
}
|
||||||
UseStatementSuffix::Star => {
|
UseStatementSuffix::Star => {
|
||||||
if let Err(error) = symbol_table.resolve_usable_star(&base_fqn) {
|
todo!("Resolve star symbols")
|
||||||
handle_lookup_error(
|
|
||||||
error,
|
|
||||||
&base_fqn,
|
|
||||||
use_statement.file_id(),
|
|
||||||
use_statement.range(),
|
|
||||||
"Star Usable Symbol",
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
UseStatementSuffix::UseList(use_list) => {
|
UseStatementSuffix::UseList(use_list) => {
|
||||||
for identifier in use_list.identifiers() {
|
for identifier in use_list.identifiers() {
|
||||||
handle_concrete_use_symbol(identifier);
|
handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/name_analysis/symbol/class_symbol.rs
Normal file
40
src/name_analysis/symbol/class_symbol.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol;
|
||||||
|
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ClassSymbol {
|
||||||
|
declared_name: Rc<String>,
|
||||||
|
fqn: Rc<String>,
|
||||||
|
members: HashMap<Rc<String>, Rc<RefCell<ClassMemberSymbol>>>,
|
||||||
|
functions: HashMap<Rc<String>, Rc<RefCell<FunctionSymbol>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClassSymbol {
|
||||||
|
pub fn new(declared_name: &str, fqn: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
declared_name: Rc::new(declared_name.to_string()),
|
||||||
|
fqn: Rc::new(fqn.to_string()),
|
||||||
|
members: HashMap::new(),
|
||||||
|
functions: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
&self.declared_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<String> {
|
||||||
|
self.declared_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fqn(&self) -> &str {
|
||||||
|
&self.fqn
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fqn_owned(&self) -> Rc<String> {
|
||||||
|
self.fqn.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/name_analysis/symbol/interface_symbol.rs
Normal file
36
src/name_analysis/symbol/interface_symbol.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InterfaceSymbol {
|
||||||
|
declared_name: Rc<String>,
|
||||||
|
fqn: Rc<String>,
|
||||||
|
functions: HashMap<String, FunctionSymbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterfaceSymbol {
|
||||||
|
pub fn new(declared_name: &str, fqn: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
declared_name: Rc::new(declared_name.to_string()),
|
||||||
|
fqn: Rc::new(fqn.to_string()),
|
||||||
|
functions: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
&self.declared_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<String> {
|
||||||
|
self.declared_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fqn(&self) -> &str {
|
||||||
|
&self.fqn
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fqn_owned(&self) -> Rc<String> {
|
||||||
|
self.fqn.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,14 @@
|
|||||||
pub(crate) mod class_member_symbol;
|
pub mod class_member_symbol;
|
||||||
pub(crate) mod function_symbol;
|
pub mod class_symbol;
|
||||||
pub(crate) mod module_symbol;
|
pub mod function_symbol;
|
||||||
pub(crate) mod parameter_symbol;
|
pub mod interface_symbol;
|
||||||
pub(crate) mod source_definition;
|
pub mod module_symbol;
|
||||||
pub(crate) mod type_symbol;
|
pub mod parameter_symbol;
|
||||||
pub(crate) mod usable_symbol;
|
pub mod source_definition;
|
||||||
pub(crate) mod use_symbol;
|
pub mod type_symbol;
|
||||||
pub(crate) mod variable_symbol;
|
pub mod usable_symbol;
|
||||||
|
pub mod use_symbol;
|
||||||
|
pub mod variable_symbol;
|
||||||
|
|
||||||
use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol;
|
use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol;
|
||||||
use crate::name_analysis::symbol::use_symbol::UseSymbol;
|
use crate::name_analysis::symbol::use_symbol::UseSymbol;
|
||||||
@ -40,7 +42,9 @@ impl Symbol {
|
|||||||
Symbol::Use(use_symbol) => use_symbol.source_definition(),
|
Symbol::Use(use_symbol) => use_symbol.source_definition(),
|
||||||
Symbol::Module(module) => module.source_definition().cloned(),
|
Symbol::Module(module) => module.source_definition().cloned(),
|
||||||
Symbol::Type(type_symbol) => type_symbol.source_definition().cloned(),
|
Symbol::Type(type_symbol) => type_symbol.source_definition().cloned(),
|
||||||
Symbol::ConcreteType(concrete_type_symbol) => concrete_type_symbol.borrow().source_definition().cloned(),
|
Symbol::ConcreteType(concrete_type_symbol) => {
|
||||||
|
concrete_type_symbol.borrow().source_definition().cloned()
|
||||||
|
}
|
||||||
Symbol::Function(function_symbol) => function_symbol.source_definition().cloned(),
|
Symbol::Function(function_symbol) => function_symbol.source_definition().cloned(),
|
||||||
Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition().cloned(),
|
Symbol::Parameter(parameter_symbol) => parameter_symbol.source_definition().cloned(),
|
||||||
Symbol::Variable(variable_symbol) => variable_symbol.source_definition().cloned(),
|
Symbol::Variable(variable_symbol) => variable_symbol.source_definition().cloned(),
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
use crate::name_analysis::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::name_analysis::symbol::type_symbol::{ConcreteTypeSymbol, TypeSymbol};
|
use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ConcreteUsableSymbol {
|
pub enum UsableSymbol {
|
||||||
Type(Rc<RefCell<ConcreteTypeSymbol>>),
|
Interface(Rc<RefCell<InterfaceSymbol>>),
|
||||||
|
Class(Rc<RefCell<ClassSymbol>>),
|
||||||
Function(Rc<RefCell<FunctionSymbol>>),
|
Function(Rc<RefCell<FunctionSymbol>>),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||||
use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol;
|
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -24,7 +24,7 @@ pub struct ConcreteUseSymbol {
|
|||||||
base_fqn: String,
|
base_fqn: String,
|
||||||
declared_name: String,
|
declared_name: String,
|
||||||
source_definition: Option<SourceDefinition>,
|
source_definition: Option<SourceDefinition>,
|
||||||
resolved_symbol: Option<ConcreteUsableSymbol>,
|
resolved_symbol: Option<UsableSymbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConcreteUseSymbol {
|
impl ConcreteUseSymbol {
|
||||||
@ -53,11 +53,11 @@ impl ConcreteUseSymbol {
|
|||||||
self.source_definition.as_ref()
|
self.source_definition.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolved_symbol(&self) -> Option<&ConcreteUsableSymbol> {
|
pub fn resolved_symbol(&self) -> Option<&UsableSymbol> {
|
||||||
self.resolved_symbol.as_ref()
|
self.resolved_symbol.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_resolved_symbol(&mut self, symbol: ConcreteUsableSymbol) {
|
pub fn set_resolved_symbol(&mut self, symbol: UsableSymbol) {
|
||||||
self.resolved_symbol = Some(symbol);
|
self.resolved_symbol = Some(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,6 @@ use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol;
|
|||||||
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
||||||
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::name_analysis::symbol::type_symbol::ConcreteTypeSymbol;
|
|
||||||
use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol;
|
|
||||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
|
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol};
|
||||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||||
use crate::name_analysis::symbol::*;
|
use crate::name_analysis::symbol::*;
|
||||||
@ -11,7 +9,6 @@ use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
|
|||||||
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
|
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
|
||||||
use scope::Scope;
|
use scope::Scope;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -82,10 +79,6 @@ impl SymbolTable {
|
|||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_current_scope_star_use_symbol(&self, base_fqn: &str) -> Option<&StarUseSymbol> {
|
|
||||||
self.current_scope().star_use_symbols().get(base_fqn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_current_scope_module_symbol(&self, declared_name: &str) -> Option<&ModuleSymbol> {
|
fn find_current_scope_module_symbol(&self, declared_name: &str) -> Option<&ModuleSymbol> {
|
||||||
self.current_scope().module_symbols().get(declared_name)
|
self.current_scope().module_symbols().get(declared_name)
|
||||||
}
|
}
|
||||||
@ -159,19 +152,11 @@ impl SymbolTable {
|
|||||||
pub fn insert_star_use_symbol(
|
pub fn insert_star_use_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
star_use_symbol: StarUseSymbol,
|
star_use_symbol: StarUseSymbol,
|
||||||
) -> Result<(), SymbolInsertError> {
|
) -> Result<Rc<RefCell<StarUseSymbol>>, SymbolInsertError> {
|
||||||
if let Some(defined_symbol) =
|
let inserted = self
|
||||||
self.find_current_scope_star_use_symbol(star_use_symbol.base_fqn())
|
.current_scope_mut()
|
||||||
{
|
.insert_star_use_symbol(star_use_symbol);
|
||||||
Err(SymbolAlreadyDefined(Symbol::Use(UseSymbol::Star(
|
Ok(inserted)
|
||||||
defined_symbol.clone(),
|
|
||||||
))))
|
|
||||||
} else {
|
|
||||||
self.current_scope_mut()
|
|
||||||
.star_use_symbols_mut()
|
|
||||||
.insert(star_use_symbol.base_fqn().to_string(), star_use_symbol);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_module_symbol(
|
pub fn insert_module_symbol(
|
||||||
@ -190,27 +175,6 @@ impl SymbolTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_current_scope_concrete_type_symbol(
|
|
||||||
&self,
|
|
||||||
declared_name: &str,
|
|
||||||
) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
|
|
||||||
self.current_scope().get_concrete_type_symbol(declared_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_concrete_type_symbol(
|
|
||||||
&mut self,
|
|
||||||
symbol: ConcreteTypeSymbol,
|
|
||||||
) -> Result<(), SymbolInsertError> {
|
|
||||||
if let Some(defined_type) =
|
|
||||||
self.find_current_scope_concrete_type_symbol(symbol.declared_name())
|
|
||||||
{
|
|
||||||
Err(SymbolAlreadyDefined(Symbol::ConcreteType(defined_type)))
|
|
||||||
} else {
|
|
||||||
self.current_scope_mut().insert_concrete_type_symbol(symbol);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_function_symbol(
|
pub fn insert_function_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
function_symbol: FunctionSymbol,
|
function_symbol: FunctionSymbol,
|
||||||
@ -334,39 +298,6 @@ impl SymbolTable {
|
|||||||
}
|
}
|
||||||
Err(NoDefinition)
|
Err(NoDefinition)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_concrete_usable_by_fqn(
|
|
||||||
&self,
|
|
||||||
fqn: &str,
|
|
||||||
) -> Result<ConcreteUsableSymbol, SymbolLookupError> {
|
|
||||||
// breadth-first search, use a queue
|
|
||||||
let mut search_stack: VecDeque<usize> = VecDeque::new();
|
|
||||||
search_stack.push_back(0); // global scope
|
|
||||||
|
|
||||||
while let Some(scope_id) = search_stack.pop_front() {
|
|
||||||
let scope = &self.scopes[scope_id];
|
|
||||||
for child_id in scope.children() {
|
|
||||||
search_stack.push_back(child_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(concrete_type_symbol) = scope.get_concrete_type_symbol_by_fqn(fqn) {
|
|
||||||
return Ok(ConcreteUsableSymbol::Type(concrete_type_symbol));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: this is inefficient. Use a (cached) hash table of Fqn => Rc<RefCell<symbol>>
|
|
||||||
for function_symbol in scope.function_symbols().values() {
|
|
||||||
if function_symbol.fqn() == fqn {
|
|
||||||
return Ok(ConcreteUsableSymbol::Function(todo!()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(NoDefinition)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_usable_star(&self, base_fqn: &str) -> Result<(), SymbolLookupError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SymbolTable {
|
impl Display for SymbolTable {
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol;
|
use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol;
|
||||||
|
use crate::name_analysis::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||||
|
use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
|
||||||
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
||||||
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::name_analysis::symbol::type_symbol::{ConcreteTypeSymbol, TypeSymbol};
|
|
||||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@ -16,10 +17,10 @@ pub struct Scope {
|
|||||||
id: usize,
|
id: usize,
|
||||||
children: Vec<usize>,
|
children: Vec<usize>,
|
||||||
concrete_use_symbols: HashMap<String, Rc<RefCell<ConcreteUseSymbol>>>,
|
concrete_use_symbols: HashMap<String, Rc<RefCell<ConcreteUseSymbol>>>,
|
||||||
star_use_symbols: HashMap<String, StarUseSymbol>,
|
star_use_symbols: HashMap<String, Rc<RefCell<StarUseSymbol>>>,
|
||||||
module_symbols: HashMap<String, ModuleSymbol>,
|
module_symbols: HashMap<String, ModuleSymbol>,
|
||||||
concrete_type_symbols: HashMap<String, Rc<RefCell<ConcreteTypeSymbol>>>,
|
interface_symbols: HashMap<Rc<String>, Rc<RefCell<InterfaceSymbol>>>,
|
||||||
concrete_type_symbols_by_fqn: HashMap<String, Rc<RefCell<ConcreteTypeSymbol>>>,
|
class_symbols: HashMap<Rc<String>, Rc<RefCell<ClassSymbol>>>,
|
||||||
function_symbols: HashMap<String, FunctionSymbol>,
|
function_symbols: HashMap<String, FunctionSymbol>,
|
||||||
parameter_symbols: HashMap<String, ParameterSymbol>,
|
parameter_symbols: HashMap<String, ParameterSymbol>,
|
||||||
variable_symbols: HashMap<String, VariableSymbol>,
|
variable_symbols: HashMap<String, VariableSymbol>,
|
||||||
@ -36,8 +37,8 @@ impl Scope {
|
|||||||
concrete_use_symbols: HashMap::new(),
|
concrete_use_symbols: HashMap::new(),
|
||||||
star_use_symbols: HashMap::new(),
|
star_use_symbols: HashMap::new(),
|
||||||
module_symbols: HashMap::new(),
|
module_symbols: HashMap::new(),
|
||||||
concrete_type_symbols: HashMap::new(),
|
interface_symbols: HashMap::new(),
|
||||||
concrete_type_symbols_by_fqn: HashMap::new(),
|
class_symbols: HashMap::new(),
|
||||||
function_symbols: HashMap::new(),
|
function_symbols: HashMap::new(),
|
||||||
parameter_symbols: HashMap::new(),
|
parameter_symbols: HashMap::new(),
|
||||||
variable_symbols: HashMap::new(),
|
variable_symbols: HashMap::new(),
|
||||||
@ -71,13 +72,11 @@ impl Scope {
|
|||||||
) -> &mut HashMap<String, Rc<RefCell<ConcreteUseSymbol>>> {
|
) -> &mut HashMap<String, Rc<RefCell<ConcreteUseSymbol>>> {
|
||||||
&mut self.concrete_use_symbols
|
&mut self.concrete_use_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn star_use_symbols(&self) -> &HashMap<String, StarUseSymbol> {
|
pub fn insert_star_use_symbol(&mut self, symbol: StarUseSymbol) -> Rc<RefCell<StarUseSymbol>> {
|
||||||
&self.star_use_symbols
|
let as_rc = Rc::new(RefCell::new(symbol));
|
||||||
}
|
self.star_use_symbols.insert(as_rc.borrow().base_fqn().to_string(), as_rc.clone());
|
||||||
|
as_rc.clone()
|
||||||
pub fn star_use_symbols_mut(&mut self) -> &mut HashMap<String, StarUseSymbol> {
|
|
||||||
&mut self.star_use_symbols
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module_symbols(&self) -> &HashMap<String, ModuleSymbol> {
|
pub fn module_symbols(&self) -> &HashMap<String, ModuleSymbol> {
|
||||||
@ -88,24 +87,25 @@ impl Scope {
|
|||||||
&mut self.module_symbols
|
&mut self.module_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_concrete_type_symbol(&mut self, symbol: ConcreteTypeSymbol) {
|
pub fn insert_interface_symbol(&mut self, symbol: InterfaceSymbol) {
|
||||||
let as_rc = Rc::new(RefCell::new(symbol));
|
self.interface_symbols
|
||||||
self.concrete_type_symbols.insert(
|
.insert(symbol.declared_name_owned(), Rc::new(RefCell::new(symbol)));
|
||||||
as_rc.borrow().declared_name().to_string(),
|
|
||||||
as_rc.clone(),
|
|
||||||
);
|
|
||||||
self.concrete_type_symbols_by_fqn.insert(
|
|
||||||
as_rc.borrow().fqn().to_string(),
|
|
||||||
as_rc.clone(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_concrete_type_symbol(&self, declared_name: &str) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
|
pub fn get_interface_symbol(
|
||||||
self.concrete_type_symbols.get(declared_name).cloned()
|
&self,
|
||||||
|
declared_name: Rc<String>,
|
||||||
|
) -> Option<Rc<RefCell<InterfaceSymbol>>> {
|
||||||
|
self.interface_symbols.get(&declared_name).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_concrete_type_symbol_by_fqn(&self, fqn: &str) -> Option<Rc<RefCell<ConcreteTypeSymbol>>> {
|
pub fn insert_class_symbol(&mut self, symbol: ClassSymbol) {
|
||||||
self.concrete_type_symbols_by_fqn.get(fqn).cloned()
|
self.class_symbols
|
||||||
|
.insert(symbol.declared_name_owned(), Rc::new(RefCell::new(symbol)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_class_symbol(&self, declared_name: Rc<String>) -> Option<Rc<RefCell<ClassSymbol>>> {
|
||||||
|
self.class_symbols.get(&declared_name).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function_symbols(&self) -> &HashMap<String, FunctionSymbol> {
|
pub fn function_symbols(&self) -> &HashMap<String, FunctionSymbol> {
|
||||||
@ -165,7 +165,7 @@ impl Display for Scope {
|
|||||||
self.debug_name()
|
self.debug_name()
|
||||||
)?;
|
)?;
|
||||||
write_symbols!(f, self.concrete_use_symbols());
|
write_symbols!(f, self.concrete_use_symbols());
|
||||||
write_symbols!(f, self.star_use_symbols());
|
todo!("self.star_use_symbols");
|
||||||
write_symbols!(f, self.module_symbols());
|
write_symbols!(f, self.module_symbols());
|
||||||
todo!("self.concrete_type_symbols");
|
todo!("self.concrete_type_symbols");
|
||||||
write_symbols!(f, self.function_symbols());
|
write_symbols!(f, self.function_symbols());
|
||||||
|
|||||||
57
src/name_analysis/symbol_tree.rs
Normal file
57
src/name_analysis/symbol_tree.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use crate::name_analysis::symbol::class_symbol::ClassSymbol;
|
||||||
|
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||||
|
use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct SymbolTree {
|
||||||
|
children: Box<HashMap<String, SymbolTree>>,
|
||||||
|
classes: Box<HashMap<String, Rc<RefCell<ClassSymbol>>>>,
|
||||||
|
interfaces: Box<HashMap<String, Rc<RefCell<InterfaceSymbol>>>>,
|
||||||
|
functions: Box<HashMap<String, Rc<RefCell<FunctionSymbol>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymbolTree {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
children: Box::new(HashMap::new()),
|
||||||
|
classes: Box::new(HashMap::new()),
|
||||||
|
interfaces: Box::new(HashMap::new()),
|
||||||
|
functions: Box::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_class(&self, fqn_parts: &[&str]) -> Option<Rc<RefCell<ClassSymbol>>> {
|
||||||
|
match fqn_parts.len() {
|
||||||
|
0 => None,
|
||||||
|
1 => self.classes.get(fqn_parts[0]).cloned(),
|
||||||
|
_ => self
|
||||||
|
.children
|
||||||
|
.get(fqn_parts[0])
|
||||||
|
.and_then(|child_tree| child_tree.find_class(&fqn_parts[1..])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_interface(&self, fqn_parts: &[&str]) -> Option<Rc<RefCell<InterfaceSymbol>>> {
|
||||||
|
match fqn_parts.len() {
|
||||||
|
0 => None,
|
||||||
|
1 => self.interfaces.get(fqn_parts[0]).cloned(),
|
||||||
|
_ => self
|
||||||
|
.children
|
||||||
|
.get(fqn_parts[0])
|
||||||
|
.and_then(|child_tree| child_tree.find_interface(&fqn_parts[1..])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_function(&self, fqn_parts: &[&str]) -> Option<Rc<RefCell<FunctionSymbol>>> {
|
||||||
|
match fqn_parts.len() {
|
||||||
|
0 => None,
|
||||||
|
1 => self.functions.get(fqn_parts[0]).cloned(),
|
||||||
|
_ => self
|
||||||
|
.children
|
||||||
|
.get(fqn_parts[0])
|
||||||
|
.and_then(|child_tree| child_tree.find_function(&fqn_parts[1..])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,68 @@
|
|||||||
use crate::ast::node::UseStatement;
|
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(
|
pub fn use_statement_base_fqn(use_statement: &UseStatement) -> String {
|
||||||
use_statement: &UseStatement
|
|
||||||
) -> String {
|
|
||||||
use_statement
|
use_statement
|
||||||
.prefixes()
|
.prefixes()
|
||||||
.map(|prefix| prefix.identifier().name())
|
.map(|prefix| prefix.identifier().name())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("::")
|
.join("::")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_insert_error(
|
||||||
|
err: SymbolInsertError,
|
||||||
|
error_symbol_name: &str,
|
||||||
|
error_file_id: usize,
|
||||||
|
error_range: Range<usize>,
|
||||||
|
symbol_types: &str,
|
||||||
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
|
) {
|
||||||
|
match err {
|
||||||
|
SymbolInsertError::SymbolAlreadyDefined(s) => {
|
||||||
|
let mut diagnostic = Diagnostic::error()
|
||||||
|
.with_message(format!(
|
||||||
|
"{} symbol '{}' already defined in the current scope.",
|
||||||
|
symbol_types, error_symbol_name,
|
||||||
|
))
|
||||||
|
.with_label(
|
||||||
|
Label::primary(error_file_id, error_range)
|
||||||
|
.with_message("Symbol duplicated here."),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(source_definition) = s.definition() {
|
||||||
|
diagnostic = diagnostic.with_label(
|
||||||
|
Label::secondary(source_definition.file_id(), source_definition.range())
|
||||||
|
.with_message("Symbol defined here."),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_lookup_error(
|
||||||
|
err: SymbolLookupError,
|
||||||
|
error_symbol_name: &str,
|
||||||
|
error_file_id: usize,
|
||||||
|
error_range: Range<usize>,
|
||||||
|
symbol_types: &str,
|
||||||
|
diagnostics: &mut Vec<DmDiagnostic>,
|
||||||
|
) {
|
||||||
|
match err {
|
||||||
|
SymbolLookupError::NoDefinition => {
|
||||||
|
let diagnostic = Diagnostic::error()
|
||||||
|
.with_message(format!(
|
||||||
|
"No such {} symbol '{}' in scope.",
|
||||||
|
symbol_types, error_symbol_name,
|
||||||
|
))
|
||||||
|
.with_label(
|
||||||
|
Label::primary(error_file_id, error_range).with_message("Symbol used here."),
|
||||||
|
);
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -249,9 +249,9 @@ UseStatement:
|
|||||||
special:
|
special:
|
||||||
kind: range
|
kind: range
|
||||||
fields:
|
fields:
|
||||||
- use_symbol:
|
- use_symbols:
|
||||||
kind: UseSymbol
|
kind: UseSymbol
|
||||||
wrap: rc_ref_cell
|
vec: true
|
||||||
UseStatementPrefix:
|
UseStatementPrefix:
|
||||||
struct:
|
struct:
|
||||||
children:
|
children:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user