Compare commits
2 Commits
13330300c1
...
6bcef184eb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bcef184eb | ||
|
|
0550df534e |
@ -11,6 +11,10 @@ use convert_case::{Case, Casing};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
fn make_result() -> TokenStream {
|
||||
quote! { std::fmt::Result }
|
||||
}
|
||||
|
||||
fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> TokenStream {
|
||||
let type_ident = format_ident!("{}", spec.name());
|
||||
let type_string = spec.name();
|
||||
@ -44,9 +48,11 @@ fn make_polymorphic_enum_loop_p2_impl(spec: &PolymorphicEnumLoopBuildSpec) -> To
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(#type_string)?;
|
||||
writer.increase_indent();
|
||||
#(#child_print_statements)*
|
||||
@ -70,9 +76,11 @@ fn make_polymorphic_type_p2_impl(spec: &PolymorphicTypeBuildSpec) -> TokenStream
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
match self {
|
||||
#(#child_matchers,)*
|
||||
}
|
||||
@ -94,9 +102,11 @@ fn make_leaf_enum_p2_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
match self {
|
||||
#(#child_matchers,)*
|
||||
}
|
||||
@ -137,9 +147,11 @@ fn make_tree_enum_p2_impl(spec: &TreeEnumBuildSpec) -> TokenStream {
|
||||
.map(Option::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(#type_str)?;
|
||||
writer.increase_indent();
|
||||
match self {
|
||||
@ -184,9 +196,11 @@ fn make_leaf_struct_p2_impl(leaf_struct_build_spec: &LeafStructBuildSpec) -> Tok
|
||||
.map(Option::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(&format!(#format_string, #(#members),*))
|
||||
}
|
||||
}
|
||||
@ -232,7 +246,7 @@ fn make_struct_p2_impl(struct_build_spec: &StructSpec) -> TokenStream {
|
||||
})
|
||||
}
|
||||
},
|
||||
StructChild::Special(_) => None
|
||||
StructChild::Special(_) => None,
|
||||
})
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap)
|
||||
@ -241,9 +255,11 @@ fn make_struct_p2_impl(struct_build_spec: &StructSpec) -> TokenStream {
|
||||
let type_ident = format_ident!("{}", struct_build_spec.build());
|
||||
let type_string = struct_build_spec.build();
|
||||
|
||||
let result = make_result();
|
||||
|
||||
quote! {
|
||||
impl PrettyPrint for #type_ident {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> #result {
|
||||
writer.writeln_indented(#type_string)?;
|
||||
writer.increase_indent();
|
||||
#(#child_print_statements)*
|
||||
|
||||
@ -166,7 +166,7 @@ pub mod pretty_print {
|
||||
use crate::util::indent_writer::IndentWriter;
|
||||
|
||||
pub trait PrettyPrint {
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()>;
|
||||
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result;
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/src/ast/pretty_print.rs"));
|
||||
|
||||
@ -59,7 +59,9 @@ pub fn name_analysis(paths: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>
|
||||
}
|
||||
|
||||
if !parse_errors.is_empty() {
|
||||
return Err(Box::new(ParseErrors { errors: parse_errors }));
|
||||
return Err(Box::new(ParseErrors {
|
||||
errors: parse_errors,
|
||||
}));
|
||||
}
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
|
||||
@ -11,10 +11,12 @@ pub fn pretty_print_parse(path: &PathBuf) {
|
||||
match parse_result {
|
||||
Ok(mut pairs) => {
|
||||
let compilation_unit = build_ast(0, &mut pairs);
|
||||
let mut indent_writer = IndentWriter::new(0, " ", Box::new(std::io::stdout()));
|
||||
let mut acc = String::new();
|
||||
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
|
||||
compilation_unit
|
||||
.pretty_print(&mut indent_writer)
|
||||
.expect("Unable to pretty-print.");
|
||||
println!("{}", acc);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
|
||||
@ -1,25 +1,20 @@
|
||||
use crate::ast::node::{
|
||||
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody,
|
||||
GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameter,
|
||||
Parameters, PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, UseStatement,
|
||||
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody
|
||||
, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration
|
||||
, StarUseStatement, UseStatement,
|
||||
UseStatementIdentifier, UseStatementPrefix,
|
||||
};
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::name_analysis::symbol::generic_type_symbol::GenericTypeSymbol;
|
||||
use crate::name_analysis::symbol::module_level_symbol::ModuleLevelSymbol;
|
||||
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
||||
use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::name_analysis::symbol::primitive_type_symbol::PrimitiveTypeSymbol;
|
||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
|
||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||
use crate::name_analysis::symbol_table::SymbolTable;
|
||||
use crate::name_analysis::util::{
|
||||
format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts,
|
||||
handle_insert_error, join_fqn_parts,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::format;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn na_p1_compilation_unit(
|
||||
@ -38,6 +33,8 @@ pub fn na_p1_compilation_unit(
|
||||
.set_current_fqn(&fqn.identifiers().map(Identifier::name).collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
symbol_table.set_current_fqn(&[]);
|
||||
}
|
||||
|
||||
symbol_table.push_scope(&format!("FileScope {}", file_name));
|
||||
@ -250,7 +247,7 @@ fn na_p1_function(
|
||||
false,
|
||||
Some(SourceDefinition::from_identifier(function.identifier())),
|
||||
);
|
||||
let function_symbol = match symbol_table.insert_function_symbol(to_insert) {
|
||||
let maybe_function_symbol = match symbol_table.insert_function_symbol(to_insert) {
|
||||
Ok(function_symbol) => Some(function_symbol),
|
||||
Err(symbol_insert_error) => {
|
||||
handle_insert_error(
|
||||
@ -264,232 +261,14 @@ fn na_p1_function(
|
||||
}
|
||||
};
|
||||
|
||||
if function_symbol.is_some() {
|
||||
let mut as_ref_mut = function_symbol.as_ref().unwrap().borrow_mut();
|
||||
if maybe_function_symbol.is_some() {
|
||||
function.set_function_symbol(maybe_function_symbol.as_ref().unwrap().clone());
|
||||
}
|
||||
|
||||
// push a scope for this function
|
||||
// create a scope for this function
|
||||
symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name()));
|
||||
|
||||
// generics
|
||||
na_p1_generic_parameters(function.generics_mut(), symbol_table, diagnostics);
|
||||
|
||||
// parameters
|
||||
as_ref_mut.set_parameter_symbols(na_p1_parameters(
|
||||
function.parameters_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
));
|
||||
|
||||
// return type
|
||||
let return_type = na_p1_return_type(function.return_type_mut(), symbol_table, diagnostics);
|
||||
if let Some(type_symbol) = return_type {
|
||||
as_ref_mut.set_return_type(type_symbol);
|
||||
}
|
||||
|
||||
symbol_table.push_scope(&format!(
|
||||
"FunctionBodyScope {}",
|
||||
function.identifier().name()
|
||||
));
|
||||
|
||||
na_p1_function_body(
|
||||
function.function_body_mut(),
|
||||
symbol_table,
|
||||
diagnostics
|
||||
);
|
||||
|
||||
function.set_scope_id(symbol_table.current_scope_id());
|
||||
symbol_table.pop_scope();
|
||||
symbol_table.pop_scope();
|
||||
}
|
||||
|
||||
function_symbol
|
||||
}
|
||||
|
||||
fn na_p1_parameters(
|
||||
parameters: &mut Parameters,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Vec<Rc<RefCell<ParameterSymbol>>> {
|
||||
parameters
|
||||
.parameters_mut()
|
||||
.map(|parameter| na_p1_parameter(parameter, symbol_table, diagnostics))
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn na_p1_parameter(
|
||||
parameter: &mut Parameter,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Option<Rc<RefCell<ParameterSymbol>>> {
|
||||
let parameter_type_symbol = na_p1_type_use(parameter.type_use_mut(), symbol_table, diagnostics);
|
||||
let to_insert = ParameterSymbol::new(
|
||||
parameter.identifier().name(),
|
||||
Some(SourceDefinition::from_identifier(parameter.identifier())),
|
||||
parameter_type_symbol,
|
||||
);
|
||||
match symbol_table.insert_parameter_symbol(to_insert) {
|
||||
Ok(parameter_symbol) => Some(parameter_symbol),
|
||||
Err(symbol_insert_error) => {
|
||||
handle_insert_error(
|
||||
symbol_insert_error,
|
||||
parameter.identifier().name(),
|
||||
parameter.identifier().file_id(),
|
||||
parameter.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p1_return_type(
|
||||
return_type: &mut ReturnType,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Option<TypeSymbol> {
|
||||
na_p1_type_use(return_type.type_use_mut(), symbol_table, diagnostics)
|
||||
}
|
||||
|
||||
fn na_p1_type_use(
|
||||
type_use: &mut TypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Option<TypeSymbol> {
|
||||
match type_use {
|
||||
TypeUse::PrimitiveType(primitive_type) => {
|
||||
Some(TypeSymbol::Primitive(match primitive_type {
|
||||
PrimitiveType::Byte => PrimitiveTypeSymbol::Byte,
|
||||
PrimitiveType::Short => PrimitiveTypeSymbol::Short,
|
||||
PrimitiveType::Char => PrimitiveTypeSymbol::Char,
|
||||
PrimitiveType::Int => PrimitiveTypeSymbol::Int,
|
||||
PrimitiveType::Long => PrimitiveTypeSymbol::Long,
|
||||
PrimitiveType::Double => PrimitiveTypeSymbol::Double,
|
||||
PrimitiveType::Bool => PrimitiveTypeSymbol::Boolean,
|
||||
PrimitiveType::String => PrimitiveTypeSymbol::String,
|
||||
PrimitiveType::TypedArray(typed_array) => {
|
||||
na_p1_typed_array(typed_array, symbol_table, diagnostics)
|
||||
}
|
||||
PrimitiveType::Any => PrimitiveTypeSymbol::Any,
|
||||
PrimitiveType::Void => PrimitiveTypeSymbol::Void,
|
||||
}))
|
||||
}
|
||||
TypeUse::InterfaceOrClassTypeUse(interface_or_class_type) => {
|
||||
match interface_or_class_type.identifier_or_fqn() {
|
||||
IdentifierOrFqn::Identifier(identifier) => {
|
||||
match symbol_table.lookup_type(identifier.name()) {
|
||||
Ok(type_symbol) => {
|
||||
interface_or_class_type.set_type_symbol(type_symbol.clone());
|
||||
Some(type_symbol)
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
identifier.name(),
|
||||
identifier.file_id(),
|
||||
identifier.range(),
|
||||
diagnostics,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
IdentifierOrFqn::FullyQualifiedName(fqn) => {
|
||||
let fqn_parts = fqn
|
||||
.identifiers()
|
||||
.map(Identifier::name)
|
||||
.collect::<Vec<&str>>();
|
||||
match symbol_table.lookup_type_by_fqn(&fqn_parts) {
|
||||
Ok(type_symbol) => {
|
||||
interface_or_class_type.set_type_symbol(type_symbol.clone());
|
||||
Some(type_symbol)
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
&format_fqn(&fqn_parts),
|
||||
fqn.file_id(),
|
||||
fqn.range(),
|
||||
diagnostics,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeUse::TupleTypeUse(tuple_type) => {
|
||||
todo!()
|
||||
}
|
||||
TypeUse::FunctionTypeUse(function_type) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p1_typed_array(
|
||||
typed_array: &mut TypedArray,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> PrimitiveTypeSymbol {
|
||||
let inner_type_use = typed_array
|
||||
.generic_arguments_mut()
|
||||
.type_use_list_mut()
|
||||
.type_uses_mut()
|
||||
.next()
|
||||
.unwrap();
|
||||
let inner_type_symbol = na_p1_type_use(inner_type_use, symbol_table, diagnostics);
|
||||
PrimitiveTypeSymbol::TypedArray {
|
||||
inner_type: inner_type_symbol.map(Box::from),
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p1_generic_parameters(
|
||||
generic_parameters: &mut GenericParameters,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for identifier in generic_parameters.identifier_list().identifiers() {
|
||||
let generic_type_symbol = GenericTypeSymbol::new(
|
||||
identifier.name(),
|
||||
Some(SourceDefinition::from_identifier(identifier)),
|
||||
);
|
||||
match symbol_table.insert_generic_type_symbol(generic_type_symbol) {
|
||||
Ok(_) => {}
|
||||
Err(symbol_insert_error) => {
|
||||
handle_insert_error(
|
||||
symbol_insert_error,
|
||||
identifier.name(),
|
||||
identifier.file_id(),
|
||||
identifier.range(),
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p1_function_body(
|
||||
function_body: &mut FunctionBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match function_body {
|
||||
FunctionBody::FunctionAliasBody(alias_body) => {
|
||||
// set scope id for pass 2; see below
|
||||
alias_body.set_scope_id(symbol_table.current_scope_id());
|
||||
}
|
||||
FunctionBody::FunctionEqualsBody(equals_body) => {
|
||||
// see below
|
||||
equals_body.set_scope_id(symbol_table.current_scope_id());
|
||||
}
|
||||
FunctionBody::FunctionBlockBody(block_body) => {
|
||||
// we need to do all insertion/resolution in pass 2, because we
|
||||
// might call functions/use classes/etc from the same compilation
|
||||
// unit which haven't been defined yet. So the strategy is to set
|
||||
// the scope id for the body and then in pass 2, set the symbol
|
||||
// table's current scope to that id.
|
||||
block_body.set_scope_id(symbol_table.current_scope_id());
|
||||
}
|
||||
}
|
||||
maybe_function_symbol
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ pub fn analyze_names<
|
||||
'a,
|
||||
F: Files<'a, FileId = usize, Name = &'a str, Source = &'a str> + ?Sized,
|
||||
>(
|
||||
compilation_units: &mut Vec<CompilationUnit>,
|
||||
compilation_units: &mut [CompilationUnit],
|
||||
files: &'a F,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Vec<DmDiagnostic> {
|
||||
@ -57,7 +57,7 @@ pub fn analyze_names<
|
||||
}
|
||||
|
||||
// resolve symbols
|
||||
for compilation_unit in compilation_units {
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
na_p2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
||||
}
|
||||
|
||||
@ -67,22 +67,28 @@ pub fn analyze_names<
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::ast_node::AstNodeRef;
|
||||
use crate::ast::build::build_ast;
|
||||
use crate::ast::pretty_print::PrettyPrint;
|
||||
use crate::ast::walk::walk_depth_first;
|
||||
use crate::name_analysis::symbol::use_symbol::StarUseSymbol;
|
||||
use crate::name_analysis::symbol::{ExpressibleSymbol, PrimitiveTypeSymbol, TypeSymbol};
|
||||
use crate::name_analysis::util::str_slice_to_rcs;
|
||||
use crate::parser::{DeimosParser, Rule};
|
||||
use crate::std_core::add_std_core_symbols;
|
||||
use crate::util::indent_writer::IndentWriter;
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use pest::Parser;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use crate::name_analysis::symbol::use_symbol::StarUseSymbol;
|
||||
|
||||
fn parse_compilation_units<'a>(
|
||||
files: &mut SimpleFiles<&'a str, &'a str>,
|
||||
sources: HashMap<&'a str, &'a str>,
|
||||
) -> Vec<CompilationUnit> {
|
||||
let mut compilation_units: Vec<CompilationUnit> = vec![];
|
||||
let mut compilation_units = vec![];
|
||||
|
||||
for (file_name, source) in sources {
|
||||
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
|
||||
@ -104,7 +110,7 @@ mod tests {
|
||||
sources: HashMap<&'a str, &'a str>,
|
||||
symbol_table: &mut SymbolTable,
|
||||
number_of_diagnostics: usize,
|
||||
) -> Vec<CompilationUnit> {
|
||||
) -> (Vec<CompilationUnit>, SimpleFiles<&'a str, &'a str>) {
|
||||
let mut files = SimpleFiles::<&'a str, &'a str>::new();
|
||||
let mut compilation_units = parse_compilation_units(&mut files, sources);
|
||||
|
||||
@ -119,20 +125,44 @@ mod tests {
|
||||
}
|
||||
|
||||
eprintln!("{}", symbol_table);
|
||||
|
||||
for compilation_unit in &compilation_units {
|
||||
let mut acc = String::new();
|
||||
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
|
||||
compilation_unit
|
||||
.pretty_print(&mut indent_writer)
|
||||
.expect("Pretty print failed");
|
||||
eprintln!("{}", acc);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(number_of_diagnostics, diagnostics.len());
|
||||
|
||||
compilation_units
|
||||
(compilation_units, files)
|
||||
}
|
||||
|
||||
fn assert_no_diagnostics(
|
||||
sources: HashMap<&str, &str>,
|
||||
fn assert_no_diagnostics<'a>(
|
||||
sources: HashMap<&'a str, &'a str>,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Vec<CompilationUnit> {
|
||||
) -> (Vec<CompilationUnit>, SimpleFiles<&'a str, &'a str>) {
|
||||
assert_number_of_diagnostics(sources, symbol_table, 0)
|
||||
}
|
||||
|
||||
fn make_names_to_cus_map<'a>(
|
||||
compilation_units: &'a [CompilationUnit],
|
||||
files: &SimpleFiles<&'a str, &str>,
|
||||
) -> HashMap<&'a str, &'a CompilationUnit> {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
for compilation_unit in compilation_units {
|
||||
let file_id = compilation_unit.file_id();
|
||||
let name = files.name(file_id).unwrap();
|
||||
map.insert(name, compilation_unit);
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn params_seen() {
|
||||
let sources = HashMap::from([(
|
||||
@ -144,7 +174,80 @@ mod tests {
|
||||
",
|
||||
)]);
|
||||
|
||||
assert_no_diagnostics(sources, &mut SymbolTable::new());
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
let (cus, files) = assert_no_diagnostics(sources, &mut symbol_table);
|
||||
let results_map = make_names_to_cus_map(&cus, &files);
|
||||
let main_cu = *results_map.get("main.dm").unwrap();
|
||||
|
||||
let mut found_main = false;
|
||||
let mut found_x = false;
|
||||
let mut found_args_ref = false;
|
||||
|
||||
walk_depth_first(main_cu, &mut |node| {
|
||||
use AstNodeRef::*;
|
||||
match node {
|
||||
Function(function) => {
|
||||
if function.identifier().name() == "main" {
|
||||
found_main = true;
|
||||
let function_symbol_ref = function.function_symbol().unwrap().borrow();
|
||||
assert_eq!("main", function_symbol_ref.declared_name());
|
||||
let parameter_symbols = function_symbol_ref.parameter_symbols();
|
||||
assert_eq!(parameter_symbols.len(), 1);
|
||||
let args_ref = parameter_symbols[0].borrow();
|
||||
assert_eq!(args_ref.declared_name(), "args");
|
||||
let args_type_symbol = args_ref.type_symbol().unwrap();
|
||||
match args_type_symbol {
|
||||
TypeSymbol::Primitive(primitive_type_symbol) => {
|
||||
match primitive_type_symbol {
|
||||
PrimitiveTypeSymbol::TypedArray { inner_type } => {
|
||||
match *inner_type.clone().unwrap() {
|
||||
TypeSymbol::Primitive(primitive_type_symbol) => {
|
||||
match primitive_type_symbol {
|
||||
PrimitiveTypeSymbol::String => {}
|
||||
_ => panic!("Expected String for args' inner type.")
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected a primitive type symbol for args' inner type.")
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected a TypeArray for args."),
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected a primitive type symbol for args.")
|
||||
}
|
||||
}
|
||||
}
|
||||
VariableDeclaration(variable_declaration) => {
|
||||
if variable_declaration.identifier().name() == "x" {
|
||||
found_x = true;
|
||||
assert_eq!(
|
||||
variable_declaration
|
||||
.variable_symbol()
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.declared_name(),
|
||||
"x"
|
||||
);
|
||||
}
|
||||
}
|
||||
IdentifierExpression(identifier_expression) => {
|
||||
if identifier_expression.identifier().name() == "args" {
|
||||
found_args_ref = true;
|
||||
match identifier_expression.expressible_symbol().unwrap() {
|
||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||
assert_eq!(parameter_symbol.borrow().declared_name(), "args")
|
||||
}
|
||||
_ => panic!("Expected args variable use to be a parameter symbol."),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
assert!(found_main);
|
||||
assert!(found_x);
|
||||
assert!(found_args_ref);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -204,17 +307,24 @@ mod tests {
|
||||
fn main(args: Array<String>)
|
||||
println args
|
||||
end
|
||||
"
|
||||
",
|
||||
)]);
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
let global_std_core_use = StarUseSymbol::new(
|
||||
&[Rc::from("std"), Rc::from("core")],
|
||||
None
|
||||
);
|
||||
symbol_table.insert_star_use_symbol(global_std_core_use)
|
||||
let global_std_core_star_use_to_insert =
|
||||
StarUseSymbol::new(&[Rc::from("std"), Rc::from("core")], None);
|
||||
let global_std_core_star_use = symbol_table
|
||||
.insert_star_use_symbol(global_std_core_star_use_to_insert)
|
||||
.expect("Failed to insert star use symbol.");
|
||||
|
||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std/core symbols.");
|
||||
|
||||
let resolved_std_core_symbols = symbol_table
|
||||
.find_usable_symbols_by_base_fqn(&str_slice_to_rcs(&["std", "core"]))
|
||||
.unwrap();
|
||||
global_std_core_star_use
|
||||
.borrow_mut()
|
||||
.set_resolved_symbols(resolved_std_core_symbols);
|
||||
|
||||
assert_no_diagnostics(sources, &mut symbol_table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,23 @@
|
||||
use crate::ast::node::{AssignmentStatement, CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Expression, ExpressionStatement, Function, FunctionAliasBody, FunctionBlockBody, FunctionBody, Identifier, LValue, ModuleLevelDeclaration, StarUseStatement, Statement, TypeUse, UseStatement, UseStatementIdentifier, UseStatementPrefix, VariableDeclaration, VariableUse};
|
||||
use crate::ast::node::{
|
||||
AssignmentStatement, Call, CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix,
|
||||
Expression, ExpressionList, ExpressionStatement, Function, FunctionAliasBody,
|
||||
FunctionBlockBody, FunctionBody, FunctionEqualsBody, GenericParameters, Identifier,
|
||||
IdentifierExpression, IdentifierOrFqn, LValue, LValueSuffix, ModuleLevelDeclaration,
|
||||
ObjectIndex, Parameter, Parameters, PrimitiveType, ReturnType, StarUseStatement, Statement,
|
||||
SuffixExpression, SuffixOperator, TypeUse, TypedArray, UseStatement, UseStatementIdentifier,
|
||||
UseStatementPrefix, VariableDeclaration,
|
||||
};
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::name_analysis::symbol::{
|
||||
GenericTypeSymbol, ParameterSymbol, PrimitiveTypeSymbol, TypeSymbol,
|
||||
};
|
||||
use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable};
|
||||
use crate::name_analysis::util::{handle_insert_error, handle_lookup_error, join_fqn_parts};
|
||||
use crate::name_analysis::util::{
|
||||
format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn na_p2_compilation_unit(
|
||||
@ -149,9 +163,206 @@ fn na_p2_function(
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_function_body(function.function_body_mut(), symbol_table, diagnostics);
|
||||
// change to this function's scope
|
||||
symbol_table.set_current_scope(*function.scope_id().unwrap());
|
||||
|
||||
// generics
|
||||
na_p2_generic_parameters(function.generics_mut(), symbol_table, diagnostics);
|
||||
|
||||
// parameters
|
||||
let parameter_symbols = na_p2_parameters(function.parameters_mut(), symbol_table, diagnostics);
|
||||
function
|
||||
.function_symbol()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_parameter_symbols(parameter_symbols);
|
||||
|
||||
// return type
|
||||
let maybe_return_type_symbol =
|
||||
na_p2_return_type(function.return_type_mut(), symbol_table, diagnostics);
|
||||
if let Some(return_type_symbol) = maybe_return_type_symbol {
|
||||
function
|
||||
.function_symbol()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type(return_type_symbol);
|
||||
}
|
||||
|
||||
// push a scope for the body and check the body
|
||||
symbol_table.push_scope(&format!(
|
||||
"FunctionBodyScope {}",
|
||||
function.identifier().name()
|
||||
));
|
||||
na_p2_function_body(function.function_body_mut(), symbol_table, diagnostics);
|
||||
symbol_table.pop_scope();
|
||||
}
|
||||
|
||||
fn na_p2_generic_parameters(
|
||||
generic_parameters: &mut GenericParameters,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for identifier in generic_parameters.identifier_list().identifiers() {
|
||||
let generic_type_symbol = GenericTypeSymbol::new(
|
||||
identifier.name(),
|
||||
Some(SourceDefinition::from_identifier(identifier)),
|
||||
);
|
||||
match symbol_table.insert_generic_type_symbol(generic_type_symbol) {
|
||||
Ok(_) => {}
|
||||
Err(symbol_insert_error) => {
|
||||
handle_insert_error(
|
||||
symbol_insert_error,
|
||||
identifier.name(),
|
||||
identifier.file_id(),
|
||||
identifier.range(),
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_parameters(
|
||||
parameters: &mut Parameters,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Vec<Rc<RefCell<ParameterSymbol>>> {
|
||||
parameters
|
||||
.parameters_mut()
|
||||
.map(|parameter| na_p2_parameter(parameter, symbol_table, diagnostics))
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn na_p2_parameter(
|
||||
parameter: &mut Parameter,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Option<Rc<RefCell<ParameterSymbol>>> {
|
||||
let parameter_type_symbol = na_p2_type_use(parameter.type_use_mut(), symbol_table, diagnostics);
|
||||
let to_insert = ParameterSymbol::new(
|
||||
parameter.identifier().name(),
|
||||
Some(SourceDefinition::from_identifier(parameter.identifier())),
|
||||
parameter_type_symbol,
|
||||
);
|
||||
match symbol_table.insert_parameter_symbol(to_insert) {
|
||||
Ok(parameter_symbol) => Some(parameter_symbol),
|
||||
Err(symbol_insert_error) => {
|
||||
handle_insert_error(
|
||||
symbol_insert_error,
|
||||
parameter.identifier().name(),
|
||||
parameter.identifier().file_id(),
|
||||
parameter.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_return_type(
|
||||
return_type: &mut ReturnType,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Option<TypeSymbol> {
|
||||
na_p2_type_use(return_type.type_use_mut(), symbol_table, diagnostics)
|
||||
}
|
||||
|
||||
fn na_p2_type_use(
|
||||
type_use: &mut TypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Option<TypeSymbol> {
|
||||
match type_use {
|
||||
TypeUse::PrimitiveType(primitive_type) => {
|
||||
Some(TypeSymbol::Primitive(match primitive_type {
|
||||
PrimitiveType::Byte => PrimitiveTypeSymbol::Byte,
|
||||
PrimitiveType::Short => PrimitiveTypeSymbol::Short,
|
||||
PrimitiveType::Char => PrimitiveTypeSymbol::Char,
|
||||
PrimitiveType::Int => PrimitiveTypeSymbol::Int,
|
||||
PrimitiveType::Long => PrimitiveTypeSymbol::Long,
|
||||
PrimitiveType::Double => PrimitiveTypeSymbol::Double,
|
||||
PrimitiveType::Bool => PrimitiveTypeSymbol::Boolean,
|
||||
PrimitiveType::String => PrimitiveTypeSymbol::String,
|
||||
PrimitiveType::TypedArray(typed_array) => {
|
||||
na_p2_typed_array(typed_array, symbol_table, diagnostics)
|
||||
}
|
||||
PrimitiveType::Any => PrimitiveTypeSymbol::Any,
|
||||
PrimitiveType::Void => PrimitiveTypeSymbol::Void,
|
||||
}))
|
||||
}
|
||||
TypeUse::InterfaceOrClassTypeUse(interface_or_class_type) => {
|
||||
match interface_or_class_type.identifier_or_fqn() {
|
||||
IdentifierOrFqn::Identifier(identifier) => {
|
||||
match symbol_table.lookup_type(identifier.name()) {
|
||||
Ok(type_symbol) => {
|
||||
interface_or_class_type.set_type_symbol(type_symbol.clone());
|
||||
Some(type_symbol)
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
identifier.name(),
|
||||
identifier.file_id(),
|
||||
identifier.range(),
|
||||
diagnostics,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
IdentifierOrFqn::FullyQualifiedName(fqn) => {
|
||||
let fqn_parts = fqn
|
||||
.identifiers()
|
||||
.map(Identifier::name)
|
||||
.collect::<Vec<&str>>();
|
||||
match symbol_table.lookup_type_by_fqn(&fqn_parts) {
|
||||
Ok(type_symbol) => {
|
||||
interface_or_class_type.set_type_symbol(type_symbol.clone());
|
||||
Some(type_symbol)
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
&format_fqn(&fqn_parts),
|
||||
fqn.file_id(),
|
||||
fqn.range(),
|
||||
diagnostics,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeUse::TupleTypeUse(tuple_type) => {
|
||||
todo!()
|
||||
}
|
||||
TypeUse::FunctionTypeUse(function_type) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_typed_array(
|
||||
typed_array: &mut TypedArray,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> PrimitiveTypeSymbol {
|
||||
let inner_type_use = typed_array
|
||||
.generic_arguments_mut()
|
||||
.type_use_list_mut()
|
||||
.type_uses_mut()
|
||||
.next()
|
||||
.unwrap();
|
||||
let inner_type_symbol = na_p2_type_use(inner_type_use, symbol_table, diagnostics);
|
||||
PrimitiveTypeSymbol::TypedArray {
|
||||
inner_type: inner_type_symbol.map(Box::from),
|
||||
}
|
||||
}
|
||||
|
||||
/// **Note:** caller needs to push a scope before calling.
|
||||
fn na_p2_function_body(
|
||||
function_body: &mut FunctionBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
@ -161,7 +372,9 @@ fn na_p2_function_body(
|
||||
FunctionBody::FunctionAliasBody(alias_body) => {
|
||||
na_p2_function_alias_body(alias_body, symbol_table, diagnostics);
|
||||
}
|
||||
FunctionBody::FunctionEqualsBody(equals_body) => {}
|
||||
FunctionBody::FunctionEqualsBody(equals_body) => {
|
||||
na_p2_function_equals_body(equals_body, symbol_table, diagnostics);
|
||||
}
|
||||
FunctionBody::FunctionBlockBody(block_body) => {
|
||||
na_p2_function_block_body(block_body, symbol_table, diagnostics);
|
||||
}
|
||||
@ -173,10 +386,8 @@ fn na_p2_function_alias_body(
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let maybe_function_symbol = symbol_table.lookup_function_symbol(
|
||||
function_alias_body.identifier().name(),
|
||||
*function_alias_body.scope_id().unwrap(),
|
||||
);
|
||||
let maybe_function_symbol =
|
||||
symbol_table.lookup_function_symbol(function_alias_body.identifier().name());
|
||||
match maybe_function_symbol {
|
||||
Ok(function_symbol) => {
|
||||
function_alias_body.set_resolved_function_symbol(function_symbol);
|
||||
@ -193,12 +404,23 @@ fn na_p2_function_alias_body(
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_function_equals_body(
|
||||
function_equals_body: &mut FunctionEqualsBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_expression(
|
||||
function_equals_body.expression_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn na_p2_function_block_body(
|
||||
function_block_body: &mut FunctionBlockBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
symbol_table.set_current_scope(*function_block_body.scope_id().unwrap());
|
||||
for statement in function_block_body.statements_mut() {
|
||||
na_p2_statement(statement, symbol_table, diagnostics);
|
||||
}
|
||||
@ -278,8 +500,16 @@ fn na_p2_assignment_statement(
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_l_value(assignment_statement.l_value_mut(), symbol_table, diagnostics);
|
||||
na_p2_expression(assignment_statement.expression_mut(), symbol_table, diagnostics);
|
||||
na_p2_l_value(
|
||||
assignment_statement.l_value_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
na_p2_expression(
|
||||
assignment_statement.expression_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn na_p2_l_value(
|
||||
@ -287,8 +517,43 @@ fn na_p2_l_value(
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_variable_use(l_value.variable_use_mut(), symbol_table, diagnostics);
|
||||
// TODO: suffixes
|
||||
match symbol_table.lookup_lv_symbol(l_value.identifier().name()) {
|
||||
Ok(lv_symbol) => {
|
||||
l_value.set_lv_symbol(lv_symbol);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
l_value.identifier().name(),
|
||||
l_value.identifier().file_id(),
|
||||
l_value.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
// "Name analysis" of suffixes is done during type-checking. We don't want to deal with getting
|
||||
// out the different potential return types of things until that point, especially if we end up
|
||||
// adding dynamic objects to the language. However, suffixes may contain things (like arguments)
|
||||
// which we do need to recurse into.
|
||||
for l_value_suffix in l_value.suffixes_mut() {
|
||||
na_p2_l_value_suffix(l_value_suffix, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_l_value_suffix(
|
||||
l_value_suffix: &mut LValueSuffix,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match l_value_suffix {
|
||||
LValueSuffix::ObjectProperty(_) => {
|
||||
// no-op; properties are checked during type-checking for soundness
|
||||
}
|
||||
LValueSuffix::ObjectIndex(object_index) => {
|
||||
// check inner expression
|
||||
na_p2_expression(object_index.expression_mut(), symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_expression_statement(
|
||||
@ -296,29 +561,12 @@ fn na_p2_expression_statement(
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_expression(expression_statement.expression_mut(), symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn na_p2_variable_use(
|
||||
variable_use: &mut VariableUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match symbol_table.lookup_lv_symbol(variable_use.identifier().name()) {
|
||||
Ok(lv_symbol) => {
|
||||
variable_use.set_lv_symbol(lv_symbol);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
variable_use.identifier().name(),
|
||||
variable_use.identifier().file_id(),
|
||||
variable_use.identifier().range(),
|
||||
na_p2_expression(
|
||||
expression_statement.expression_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_expression(
|
||||
expression: &mut Expression,
|
||||
@ -351,13 +599,13 @@ fn na_p2_expression(
|
||||
todo!()
|
||||
}
|
||||
Expression::Suffix(suffix) => {
|
||||
todo!()
|
||||
na_p2_suffix_expression(suffix, symbol_table, diagnostics);
|
||||
}
|
||||
Expression::Literal(literal) => {
|
||||
todo!()
|
||||
}
|
||||
Expression::VariableUse(variable_use) => {
|
||||
na_p2_variable_use(variable_use, symbol_table, diagnostics);
|
||||
Expression::Identifier(identifier_expression) => {
|
||||
na_p2_identifier_expression(identifier_expression, symbol_table, diagnostics);
|
||||
}
|
||||
Expression::Fqn(fqn) => {
|
||||
todo!()
|
||||
@ -371,24 +619,110 @@ fn na_p2_expression(
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_type_use(
|
||||
type_use: &mut TypeUse,
|
||||
fn na_p2_suffix_expression(
|
||||
suffix_expression: &mut SuffixExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match type_use {
|
||||
TypeUse::PrimitiveType(primitive_type_use) => {
|
||||
todo!()
|
||||
na_p2_expression(
|
||||
suffix_expression.expression_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
na_p2_suffix_operator(suffix_expression.operator_mut(), symbol_table, diagnostics);
|
||||
}
|
||||
TypeUse::InterfaceOrClassTypeUse(interface_or_class_type_use) => {
|
||||
todo!()
|
||||
|
||||
fn na_p2_suffix_operator(
|
||||
suffix_operator: &mut SuffixOperator,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match suffix_operator {
|
||||
SuffixOperator::PlusPlus => {
|
||||
// no-op
|
||||
}
|
||||
TypeUse::TupleTypeUse(tuple_type_use) => {
|
||||
todo!()
|
||||
SuffixOperator::MinusMinus => {
|
||||
// no-op
|
||||
}
|
||||
TypeUse::FunctionTypeUse(function_type_use) => {
|
||||
todo!()
|
||||
SuffixOperator::ObjectProperty(_) => {
|
||||
// no-op; props checked during type checking
|
||||
}
|
||||
SuffixOperator::ObjectIndex(object_index) => {
|
||||
na_p2_object_index(object_index, symbol_table, diagnostics);
|
||||
}
|
||||
SuffixOperator::Call(call) => {
|
||||
na_p2_call(call, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_object_index(
|
||||
object_index: &mut ObjectIndex,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
na_p2_expression(object_index.expression_mut(), symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn na_p2_call(
|
||||
call: &mut Call,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
// TODO: modify the ast-gen so that we don't have to match on these. They should be the same.
|
||||
match call {
|
||||
Call::ParenthesesCall(parentheses_call) => {
|
||||
if let Some(turbo_fish) = parentheses_call.turbo_fish_mut() {
|
||||
todo!()
|
||||
}
|
||||
if let Some(expression_list) = parentheses_call.expression_list_mut() {
|
||||
na_p2_expression_list(expression_list, symbol_table, diagnostics);
|
||||
}
|
||||
if let Some(closure) = parentheses_call.closure_mut() {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Call::NonParenthesesCall(non_parentheses_call) => {
|
||||
if let Some(turbo_fish) = non_parentheses_call.turbo_fish_mut() {
|
||||
todo!()
|
||||
}
|
||||
if let Some(expression_list) = non_parentheses_call.expression_list_mut() {
|
||||
na_p2_expression_list(expression_list, symbol_table, diagnostics);
|
||||
}
|
||||
if let Some(closure) = non_parentheses_call.closure_mut() {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_identifier_expression(
|
||||
identifier_expression: &mut IdentifierExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match symbol_table.lookup_expressible_symbol(identifier_expression.identifier().name()) {
|
||||
Ok(expressible_symbol) => {
|
||||
identifier_expression.set_expressible_symbol(expressible_symbol);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
handle_lookup_error(
|
||||
symbol_lookup_error,
|
||||
identifier_expression.identifier().name(),
|
||||
identifier_expression.identifier().file_id(),
|
||||
identifier_expression.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_expression_list(
|
||||
expression_list: &mut ExpressionList,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for expression in expression_list.expressions_mut() {
|
||||
na_p2_expression(expression, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
33
src/name_analysis/symbol/expressible_symbol.rs
Normal file
33
src/name_analysis/symbol/expressible_symbol.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use crate::name_analysis::symbol::{ClassMemberSymbol, ClassSymbol, FunctionSymbol, ParameterSymbol, Symbol, VariableSymbol};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub enum ExpressibleSymbol {
|
||||
Class(Rc<RefCell<ClassSymbol>>),
|
||||
Function(Rc<RefCell<FunctionSymbol>>),
|
||||
ClassMember(Rc<RefCell<ClassMemberSymbol>>),
|
||||
Parameter(Rc<RefCell<ParameterSymbol>>),
|
||||
Variable(Rc<RefCell<VariableSymbol>>),
|
||||
}
|
||||
|
||||
impl ExpressibleSymbol {
|
||||
pub fn to_symbol(self) -> Rc<RefCell<dyn Symbol>> {
|
||||
match self {
|
||||
ExpressibleSymbol::Class(class_symbol) => {
|
||||
class_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::Function(function_symbol) => {
|
||||
function_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::ClassMember(class_member_symbol) => {
|
||||
class_member_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||
parameter_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||
variable_symbol as Rc<RefCell<dyn Symbol>>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod class_member_symbol;
|
||||
pub mod class_symbol;
|
||||
pub mod expressible_symbol;
|
||||
pub mod function_symbol;
|
||||
pub mod generic_type_symbol;
|
||||
pub mod interface_symbol;
|
||||
@ -18,10 +19,10 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub use self::{
|
||||
class_member_symbol::*, class_symbol::*, function_symbol::*, function_symbol::*,
|
||||
generic_type_symbol::*, interface_symbol::*, lv_symbol::*, module_level_symbol::*,
|
||||
module_symbol::*, parameter_symbol::*, primitive_type_symbol::*, type_symbol::*,
|
||||
usable_symbol::*, use_symbol::*, variable_symbol::*,
|
||||
class_member_symbol::*, class_symbol::*, expressible_symbol::*, function_symbol::*,
|
||||
function_symbol::*, generic_type_symbol::*, interface_symbol::*, lv_symbol::*,
|
||||
module_level_symbol::*, module_symbol::*, parameter_symbol::*, primitive_type_symbol::*,
|
||||
type_symbol::*, usable_symbol::*, use_symbol::*, variable_symbol::*,
|
||||
};
|
||||
|
||||
pub trait Symbol: Debug {
|
||||
|
||||
@ -30,6 +30,14 @@ impl ParameterSymbol {
|
||||
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||
self.declared_name.clone()
|
||||
}
|
||||
|
||||
pub fn type_symbol(&self) -> Option<&TypeSymbol> {
|
||||
self.type_symbol.as_ref()
|
||||
}
|
||||
|
||||
pub fn type_symbol_mut(&mut self) -> Option<&mut TypeSymbol> {
|
||||
self.type_symbol.as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl Symbol for ParameterSymbol {
|
||||
@ -43,6 +51,7 @@ impl Debug for ParameterSymbol {
|
||||
f.debug_struct("ParameterSymbol")
|
||||
.field("declared_name", &self.declared_name)
|
||||
.field("source_definition", &self.source_definition)
|
||||
.field("type_symbol", &self.type_symbol)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,9 +109,10 @@ impl Symbol for StarUseSymbol {
|
||||
|
||||
impl Debug for StarUseSymbol {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("StarUseStatementSymbol")
|
||||
f.debug_struct("StarUseSymbol")
|
||||
.field("fqn", &join_fqn_parts(&self.fqn_parts))
|
||||
.field("source_definition", &self.source_definition)
|
||||
.field("resolved_symbols", &self.resolved_symbols)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,8 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
|
||||
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||
use crate::name_analysis::symbol::{LVSymbol, Symbol};
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::name_analysis::symbol::{ExpressibleSymbol, LVSymbol, 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;
|
||||
@ -14,7 +15,6 @@ use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
|
||||
pub(self) mod fqn_context;
|
||||
mod scope;
|
||||
@ -25,6 +25,7 @@ pub enum SymbolInsertError {
|
||||
SymbolAlreadyDefined(Rc<RefCell<dyn Symbol>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SymbolLookupError {
|
||||
NoDefinition,
|
||||
NoSuchNamespace,
|
||||
@ -44,7 +45,7 @@ impl SymbolTable {
|
||||
Self {
|
||||
scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))],
|
||||
current_scope_id: 0,
|
||||
symbol_tree: Box::new(SymbolTree::new()),
|
||||
symbol_tree: Box::new(SymbolTree::new("<DEFAULT>")),
|
||||
fqn_context: Box::new(FqnContext::new()),
|
||||
}
|
||||
}
|
||||
@ -122,6 +123,15 @@ impl SymbolTable {
|
||||
self.symbol_tree.register_module_by_fqn_parts(fqn_parts);
|
||||
}
|
||||
|
||||
pub fn register_function_symbol(
|
||||
&mut self,
|
||||
function_symbol: FunctionSymbol,
|
||||
) -> Rc<RefCell<FunctionSymbol>> {
|
||||
let as_rc = Rc::new(RefCell::new(function_symbol));
|
||||
self.symbol_tree.register_function(as_rc.clone());
|
||||
as_rc
|
||||
}
|
||||
|
||||
pub fn find_usable_symbols_by_base_fqn(
|
||||
&self,
|
||||
fqn_parts: &[Rc<str>],
|
||||
@ -267,8 +277,11 @@ impl SymbolTable {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn lookup_function_symbol(&self, declared_name: &str, scope_id: usize) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolLookupError> {
|
||||
let mut current_scope: Option<&Scope> = self.scopes.get(scope_id);
|
||||
pub fn lookup_function_symbol(
|
||||
&self,
|
||||
declared_name: &str,
|
||||
) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolLookupError> {
|
||||
let mut current_scope: Option<&Scope> = Some(self.current_scope());
|
||||
while let Some(scope) = current_scope.take() {
|
||||
if let Some(function_symbol) = scope.find_function_symbol(declared_name) {
|
||||
return Ok(function_symbol.clone());
|
||||
@ -285,7 +298,24 @@ impl SymbolTable {
|
||||
let mut current_scope: Option<&Scope> = Some(self.current_scope());
|
||||
while let Some(scope) = current_scope.take() {
|
||||
if let Some(lv_symbol) = scope.find_lv_symbol(declared_name) {
|
||||
return Ok(lv_symbol)
|
||||
return Ok(lv_symbol);
|
||||
} else {
|
||||
current_scope = scope
|
||||
.parent()
|
||||
.and_then(|parent_id| self.scopes.get(parent_id));
|
||||
}
|
||||
}
|
||||
Err(SymbolLookupError::NoDefinition)
|
||||
}
|
||||
|
||||
pub fn lookup_expressible_symbol(
|
||||
&self,
|
||||
declared_name: &str,
|
||||
) -> Result<ExpressibleSymbol, SymbolLookupError> {
|
||||
let mut current_scope: Option<&Scope> = Some(self.current_scope());
|
||||
while let Some(scope) = current_scope.take() {
|
||||
if let Some(expressible_symbol) = scope.find_expressible_symbol(declared_name) {
|
||||
return Ok(expressible_symbol);
|
||||
} else {
|
||||
current_scope = scope
|
||||
.parent()
|
||||
@ -302,6 +332,8 @@ impl Display for SymbolTable {
|
||||
for scope in &self.scopes {
|
||||
writeln!(f, "{}", scope)?;
|
||||
}
|
||||
writeln!(f, "---SymbolTable: SymbolTree---")?;
|
||||
writeln!(f, "{}", self.symbol_tree)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::name_analysis::symbol::type_symbol::TypeSymbol;
|
||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::name_analysis::symbol::{ExpressibleSymbol, UsableSymbol};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -204,10 +205,83 @@ impl Scope {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_function_symbol(&self, declared_name: &str) -> Option<&Rc<RefCell<FunctionSymbol>>> {
|
||||
pub fn find_function_symbol(
|
||||
&self,
|
||||
declared_name: &str,
|
||||
) -> Option<&Rc<RefCell<FunctionSymbol>>> {
|
||||
self.function_symbols.get(declared_name)
|
||||
}
|
||||
|
||||
pub fn find_expressible_symbol(&self, declared_name: &str) -> Option<ExpressibleSymbol> {
|
||||
// First, try all the usual suspects: classes, functions, members, parameters, and variables
|
||||
// which are in scope. If we don't find any of those, try looking through imports; start
|
||||
// with concrete imports by declared name; if none of those match, check all resolved
|
||||
// symbols of the star imports until one is found or none.
|
||||
// !! Eventually consider registering star-imported symbols in a scope so that we can just
|
||||
// check them via the hash maps instead of looping through the star symbols.
|
||||
self.class_symbols
|
||||
.get(declared_name)
|
||||
.map(|class_symbol| ExpressibleSymbol::Class(class_symbol.clone()))
|
||||
.or_else(|| {
|
||||
self.function_symbols
|
||||
.get(declared_name)
|
||||
.map(|function_symbol| ExpressibleSymbol::Function(function_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
self.class_member_symbols
|
||||
.get(declared_name)
|
||||
.map(|class_member_symbol| {
|
||||
ExpressibleSymbol::ClassMember(class_member_symbol.clone())
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
self.parameter_symbols
|
||||
.get(declared_name)
|
||||
.map(|parameter_symbol| ExpressibleSymbol::Parameter(parameter_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
self.variable_symbols
|
||||
.get(declared_name)
|
||||
.map(|variable_symbol| ExpressibleSymbol::Variable(variable_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
if let Some(concrete_use_symbol) = self.concrete_use_symbols.get(declared_name) {
|
||||
return match concrete_use_symbol.borrow().resolved_symbol().unwrap() {
|
||||
UsableSymbol::Interface(_) => {
|
||||
None
|
||||
}
|
||||
UsableSymbol::Class(class_symbol) => {
|
||||
Some(ExpressibleSymbol::Class(class_symbol.clone()))
|
||||
}
|
||||
UsableSymbol::Function(function_symbol) => {
|
||||
Some(ExpressibleSymbol::Function(function_symbol.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.or_else(|| {
|
||||
for star_use_symbol in self.star_use_symbols.values() {
|
||||
for usable_symbol in star_use_symbol.borrow().resolved_symbols() {
|
||||
match usable_symbol {
|
||||
UsableSymbol::Class(class_symbol) => {
|
||||
if class_symbol.borrow().declared_name() == declared_name {
|
||||
return Some(ExpressibleSymbol::Class(class_symbol.clone()));
|
||||
}
|
||||
}
|
||||
UsableSymbol::Function(function_symbol) => {
|
||||
if function_symbol.borrow().declared_name() == declared_name {
|
||||
return Some(ExpressibleSymbol::Function(function_symbol.clone()));
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
pub fn debug_name(&self) -> &str {
|
||||
&self.debug_name
|
||||
}
|
||||
|
||||
@ -4,12 +4,15 @@ use crate::name_analysis::symbol::interface_symbol::InterfaceSymbol;
|
||||
use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
||||
use crate::name_analysis::symbol::usable_symbol::UsableSymbol;
|
||||
use crate::name_analysis::symbol_table::SymbolLookupError;
|
||||
use crate::util::indent_writer::IndentWriter;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SymbolTree {
|
||||
debug_name: String,
|
||||
children: Box<HashMap<Rc<str>, SymbolTree>>,
|
||||
classes: Box<HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>>,
|
||||
interfaces: Box<HashMap<Rc<str>, Rc<RefCell<InterfaceSymbol>>>>,
|
||||
@ -17,8 +20,9 @@ pub struct SymbolTree {
|
||||
}
|
||||
|
||||
impl SymbolTree {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(debug_name: &str) -> Self {
|
||||
Self {
|
||||
debug_name: debug_name.to_string(),
|
||||
children: Box::new(HashMap::new()),
|
||||
classes: Box::new(HashMap::new()),
|
||||
interfaces: Box::new(HashMap::new()),
|
||||
@ -78,13 +82,13 @@ impl SymbolTree {
|
||||
}
|
||||
if fqn_parts.len() == 1 {
|
||||
self.children
|
||||
.insert(fqn_parts[0].clone(), SymbolTree::new());
|
||||
.insert(fqn_parts[0].clone(), SymbolTree::new(fqn_parts[0].as_ref()));
|
||||
} else {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
let child = self.children.get_mut(fqn_parts[0].as_ref()).unwrap();
|
||||
child.recurse_register_module(&fqn_parts[1..]);
|
||||
} else {
|
||||
let mut child = SymbolTree::new();
|
||||
let mut child = SymbolTree::new(fqn_parts[0].as_ref());
|
||||
child.recurse_register_module(&fqn_parts[1..]);
|
||||
self.children.insert(fqn_parts[0].clone(), child);
|
||||
}
|
||||
@ -105,6 +109,12 @@ impl SymbolTree {
|
||||
panic!("Unable to register function fqn with no parts.");
|
||||
}
|
||||
if fqn_parts.len() == 1 {
|
||||
if self.functions.contains_key(fqn_parts[0].as_ref()) {
|
||||
panic!(
|
||||
"There is already a function registered in this symbol tree with the name {}",
|
||||
fqn_parts[0]
|
||||
);
|
||||
}
|
||||
self.functions.insert(fqn_parts[0].clone(), function_symbol);
|
||||
} else {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
@ -137,7 +147,7 @@ impl SymbolTree {
|
||||
_ => {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
let child = self.children.get(fqn_parts[0].as_ref()).unwrap();
|
||||
child.find_all_by_base_fqn(fqn_parts)
|
||||
child.find_all_by_base_fqn(&fqn_parts[1..])
|
||||
} else {
|
||||
Err(SymbolLookupError::NoSuchNamespace)
|
||||
}
|
||||
@ -145,3 +155,55 @@ impl SymbolTree {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FormatAction<'a> {
|
||||
PrintSymbolTree(&'a SymbolTree),
|
||||
IncreaseIndent,
|
||||
DecreaseIndent
|
||||
}
|
||||
|
||||
impl Display for SymbolTree {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let mut acc = String::new();
|
||||
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
|
||||
let mut stack: Vec<FormatAction> = vec![];
|
||||
stack.push(FormatAction::PrintSymbolTree(self));
|
||||
|
||||
while let Some(format_action) = stack.pop() {
|
||||
match format_action {
|
||||
FormatAction::PrintSymbolTree(symbol_tree) => {
|
||||
// reverse order: start with decrease
|
||||
stack.push(FormatAction::DecreaseIndent);
|
||||
// add children
|
||||
for child in symbol_tree.children.values() {
|
||||
stack.push(FormatAction::PrintSymbolTree(child));
|
||||
}
|
||||
// increase for the first child
|
||||
stack.push(FormatAction::IncreaseIndent);
|
||||
|
||||
indent_writer.writeln_indented(&format!("SymbolTree(debug_name = {})", symbol_tree.debug_name))?;
|
||||
|
||||
indent_writer.increase_indent();
|
||||
for interface in symbol_tree.interfaces.values() {
|
||||
indent_writer.writeln_indented(&format!("Interface({:?}", interface))?;
|
||||
}
|
||||
for class in symbol_tree.classes.values() {
|
||||
indent_writer.writeln_indented(&format!("Class({:?})", class))?;
|
||||
}
|
||||
for function in symbol_tree.functions.values() {
|
||||
indent_writer.writeln_indented(&format!("Function({:?})", function))?;
|
||||
}
|
||||
indent_writer.decrease_indent();
|
||||
}
|
||||
FormatAction::IncreaseIndent => {
|
||||
indent_writer.increase_indent();
|
||||
}
|
||||
FormatAction::DecreaseIndent => {
|
||||
indent_writer.decrease_indent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(f, "{}", acc)
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,12 +50,12 @@ pub fn handle_lookup_error(
|
||||
Label::primary(error_file_id, error_range).with_message("Symbol used here."),
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
},
|
||||
}
|
||||
SymbolLookupError::NoSuchNamespace => {
|
||||
let diagnostic = Diagnostic::error()
|
||||
.with_message(format!("No such namespace '{}' found", error_symbol_name))
|
||||
.with_label(
|
||||
Label::primary(error_file_id, error_range).with_message("Namespace used here.")
|
||||
Label::primary(error_file_id, error_range).with_message("Namespace used here."),
|
||||
);
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@ -69,3 +69,7 @@ pub fn format_fqn(parts: &[&str]) -> String {
|
||||
pub fn join_fqn_parts(parts: &[Rc<str>]) -> String {
|
||||
format_fqn(&parts.iter().map(|part| part.as_ref()).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub fn str_slice_to_rcs(str_slice: &[&str]) -> Vec<Rc<str>> {
|
||||
str_slice.iter().map(|s| Rc::from(*s)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
@ -447,6 +447,12 @@ Function:
|
||||
node:
|
||||
or_else: void
|
||||
- function_body
|
||||
fields:
|
||||
- function_symbol:
|
||||
kind: FunctionSymbol
|
||||
wrap: rc_ref_cell
|
||||
- scope_id:
|
||||
kind: usize
|
||||
OperatorFunction:
|
||||
struct:
|
||||
children:
|
||||
@ -609,9 +615,6 @@ FunctionEqualsBody:
|
||||
struct:
|
||||
children:
|
||||
- expression
|
||||
fields:
|
||||
- scope_id:
|
||||
kind: usize
|
||||
FunctionAliasBody:
|
||||
struct:
|
||||
children:
|
||||
@ -620,8 +623,6 @@ FunctionAliasBody:
|
||||
rule: Alias
|
||||
- identifier
|
||||
fields:
|
||||
- scope_id:
|
||||
kind: usize
|
||||
- resolved_function_symbol:
|
||||
kind: FunctionSymbol
|
||||
wrap: rc_ref_cell
|
||||
@ -634,9 +635,6 @@ FunctionBlockBody:
|
||||
- end_kw:
|
||||
skip:
|
||||
rule: End
|
||||
fields:
|
||||
- scope_id:
|
||||
kind: usize
|
||||
|
||||
# Class constructs
|
||||
ClassConstructor:
|
||||
@ -787,25 +785,19 @@ ForStatement:
|
||||
LValue:
|
||||
struct:
|
||||
children:
|
||||
- variable_use
|
||||
- identifier
|
||||
- suffixes:
|
||||
vec:
|
||||
rule: LValueSuffix
|
||||
fields:
|
||||
- lv_symbol:
|
||||
kind: LVSymbol
|
||||
LValueSuffix:
|
||||
tree_enum:
|
||||
rules:
|
||||
- ObjectProperty
|
||||
- ObjectIndex
|
||||
|
||||
# VariableUse
|
||||
VariableUse:
|
||||
struct:
|
||||
children:
|
||||
- identifier
|
||||
fields:
|
||||
- lv_symbol:
|
||||
kind: LVSymbol
|
||||
|
||||
# Expressions
|
||||
Expression:
|
||||
polymorphic_type:
|
||||
@ -840,9 +832,9 @@ Expression:
|
||||
- Literal:
|
||||
inner:
|
||||
kind: Literal
|
||||
- VariableUse:
|
||||
- Identifier:
|
||||
inner:
|
||||
kind: VariableUse
|
||||
kind: IdentifierExpression
|
||||
- Fqn:
|
||||
inner:
|
||||
kind: FullyQualifiedName
|
||||
@ -1185,9 +1177,9 @@ PrimaryExpression:
|
||||
- Literal:
|
||||
inner:
|
||||
kind: Literal
|
||||
- VariableUse:
|
||||
- Identifier:
|
||||
inner:
|
||||
kind: VariableUse
|
||||
kind: IdentifierExpression
|
||||
- Fqn:
|
||||
inner:
|
||||
kind: FullyQualifiedName
|
||||
@ -1200,6 +1192,13 @@ PrimaryExpression:
|
||||
- ParenthesizedExpression:
|
||||
pass_through:
|
||||
kind: Expression
|
||||
IdentifierExpression:
|
||||
struct:
|
||||
children:
|
||||
- identifier
|
||||
fields:
|
||||
- expressible_symbol:
|
||||
kind: ExpressibleSymbol
|
||||
ListExpression:
|
||||
struct:
|
||||
children:
|
||||
|
||||
@ -615,7 +615,7 @@ ForStatement = {
|
||||
// LValue
|
||||
|
||||
LValue = {
|
||||
VariableUse
|
||||
Identifier
|
||||
~ LValueSuffix*
|
||||
}
|
||||
|
||||
@ -624,12 +624,6 @@ LValueSuffix = {
|
||||
| ObjectIndex
|
||||
}
|
||||
|
||||
// Variable Use
|
||||
|
||||
VariableUse = {
|
||||
Identifier
|
||||
}
|
||||
|
||||
// Expressions
|
||||
|
||||
Expression = {
|
||||
@ -778,13 +772,17 @@ ObjectIndex = {
|
||||
|
||||
PrimaryExpression = {
|
||||
Literal
|
||||
| VariableUse
|
||||
| IdentifierExpression
|
||||
| FullyQualifiedName
|
||||
| Closure
|
||||
| ListExpression
|
||||
| ParenthesizedExpression
|
||||
}
|
||||
|
||||
IdentifierExpression = {
|
||||
Identifier
|
||||
}
|
||||
|
||||
ListExpression = {
|
||||
"["
|
||||
~ ExpressionList?
|
||||
|
||||
@ -26,7 +26,7 @@ pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), Symbol
|
||||
&vec![Rc::new(RefCell::new(println_msg_symbol))],
|
||||
None,
|
||||
);
|
||||
symbol_table.insert_function_symbol(println_symbol)?;
|
||||
symbol_table.register_function_symbol(println_symbol);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
pub struct IndentWriter {
|
||||
pub struct IndentWriter<'a> {
|
||||
indent_level: usize,
|
||||
indent_string: String,
|
||||
out: Box<dyn std::io::Write>,
|
||||
out: &'a mut dyn std::fmt::Write,
|
||||
}
|
||||
|
||||
impl IndentWriter {
|
||||
pub fn new(
|
||||
start_level: usize,
|
||||
indent_string: &str,
|
||||
out: Box<dyn std::io::Write>,
|
||||
) -> IndentWriter {
|
||||
impl<'a> IndentWriter<'a> {
|
||||
pub fn new(start_level: usize, indent_string: &str, out: &'a mut dyn std::fmt::Write) -> Self {
|
||||
IndentWriter {
|
||||
indent_level: start_level,
|
||||
indent_string: indent_string.to_string(),
|
||||
@ -25,22 +21,22 @@ impl IndentWriter {
|
||||
self.indent_level -= 1;
|
||||
}
|
||||
|
||||
pub fn write(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn write(&mut self, s: &str) -> std::fmt::Result {
|
||||
write!(self.out, "{}", s)
|
||||
}
|
||||
|
||||
pub fn writeln(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn writeln(&mut self, s: &str) -> std::fmt::Result {
|
||||
self.write(&format!("{}\n", s))
|
||||
}
|
||||
|
||||
pub fn write_indented(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn write_indented(&mut self, s: &str) -> std::fmt::Result {
|
||||
for _ in 0..self.indent_level {
|
||||
write!(self.out, "{}", self.indent_string)?;
|
||||
}
|
||||
write!(self.out, "{}", s)
|
||||
}
|
||||
|
||||
pub fn writeln_indented(&mut self, s: &str) -> std::io::Result<()> {
|
||||
pub fn writeln_indented(&mut self, s: &str) -> std::fmt::Result {
|
||||
self.write_indented(&format!("{}\n", s))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user