Compare commits

..

No commits in common. "6bcef184eb85939422568a4076fff04e60e73981" and "13330300c1a744b58d88a8564a2a353fa6868063" have entirely different histories.

19 changed files with 385 additions and 837 deletions

View File

@ -11,10 +11,6 @@ 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();
@ -48,11 +44,9 @@ 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) -> #result {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented(#type_string)?;
writer.increase_indent();
#(#child_print_statements)*
@ -76,11 +70,9 @@ 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) -> #result {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
match self {
#(#child_matchers,)*
}
@ -102,11 +94,9 @@ 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) -> #result {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
match self {
#(#child_matchers,)*
}
@ -147,11 +137,9 @@ 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) -> #result {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented(#type_str)?;
writer.increase_indent();
match self {
@ -196,11 +184,9 @@ 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) -> #result {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented(&format!(#format_string, #(#members),*))
}
}
@ -246,7 +232,7 @@ fn make_struct_p2_impl(struct_build_spec: &StructSpec) -> TokenStream {
})
}
},
StructChild::Special(_) => None,
StructChild::Special(_) => None
})
.filter(Option::is_some)
.map(Option::unwrap)
@ -255,11 +241,9 @@ 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) -> #result {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented(#type_string)?;
writer.increase_indent();
#(#child_print_statements)*

View File

@ -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::fmt::Result;
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()>;
}
include!(concat!(env!("OUT_DIR"), "/src/ast/pretty_print.rs"));

View File

@ -43,7 +43,7 @@ pub fn name_analysis(paths: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>
let mut compilation_units = vec![];
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
let mut parse_errors = vec![];
for (path, source) in &paths_and_sources {
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
match parse_result {
@ -57,11 +57,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();

View File

@ -11,12 +11,10 @@ pub fn pretty_print_parse(path: &PathBuf) {
match parse_result {
Ok(mut pairs) => {
let compilation_unit = build_ast(0, &mut pairs);
let mut acc = String::new();
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
let mut indent_writer = IndentWriter::new(0, " ", Box::new(std::io::stdout()));
compilation_unit
.pretty_print(&mut indent_writer)
.expect("Unable to pretty-print.");
println!("{}", acc);
}
Err(e) => {
eprintln!("{}", e);

View File

@ -1,20 +1,25 @@
use crate::ast::node::{
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody
, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration
, StarUseStatement, UseStatement,
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody,
GenericParameters, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration, Parameter,
Parameters, PrimitiveType, ReturnType, StarUseStatement, TypeUse, TypedArray, 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::{
handle_insert_error, join_fqn_parts,
format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts,
};
use std::cell::RefCell;
use std::fmt::format;
use std::rc::Rc;
pub fn na_p1_compilation_unit(
@ -33,8 +38,6 @@ 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));
@ -247,7 +250,7 @@ fn na_p1_function(
false,
Some(SourceDefinition::from_identifier(function.identifier())),
);
let maybe_function_symbol = match symbol_table.insert_function_symbol(to_insert) {
let function_symbol = match symbol_table.insert_function_symbol(to_insert) {
Ok(function_symbol) => Some(function_symbol),
Err(symbol_insert_error) => {
handle_insert_error(
@ -261,14 +264,232 @@ fn na_p1_function(
}
};
if maybe_function_symbol.is_some() {
function.set_function_symbol(maybe_function_symbol.as_ref().unwrap().clone());
}
// create a scope for this function
symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name()));
function.set_scope_id(symbol_table.current_scope_id());
symbol_table.pop_scope();
if function_symbol.is_some() {
let mut as_ref_mut = function_symbol.as_ref().unwrap().borrow_mut();
maybe_function_symbol
// push 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
);
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());
}
}
}

View File

@ -40,7 +40,7 @@ pub fn analyze_names<
'a,
F: Files<'a, FileId = usize, Name = &'a str, Source = &'a str> + ?Sized,
>(
compilation_units: &mut [CompilationUnit],
compilation_units: &mut Vec<CompilationUnit>,
files: &'a F,
symbol_table: &mut SymbolTable,
) -> Vec<DmDiagnostic> {
@ -51,13 +51,13 @@ pub fn analyze_names<
let file_name = files.name(compilation_unit.file_id()).unwrap();
na_p1_compilation_unit(file_name, compilation_unit, symbol_table, &mut diagnostics);
}
if !diagnostics.is_empty() {
return diagnostics;
}
// resolve symbols
for compilation_unit in compilation_units.iter_mut() {
for compilation_unit in compilation_units {
na_p2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
}
@ -67,28 +67,22 @@ 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![];
let mut compilation_units: Vec<CompilationUnit> = vec![];
for (file_name, source) in sources {
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
@ -110,7 +104,7 @@ mod tests {
sources: HashMap<&'a str, &'a str>,
symbol_table: &mut SymbolTable,
number_of_diagnostics: usize,
) -> (Vec<CompilationUnit>, SimpleFiles<&'a str, &'a str>) {
) -> Vec<CompilationUnit> {
let mut files = SimpleFiles::<&'a str, &'a str>::new();
let mut compilation_units = parse_compilation_units(&mut files, sources);
@ -125,44 +119,20 @@ 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, files)
compilation_units
}
fn assert_no_diagnostics<'a>(
sources: HashMap<&'a str, &'a str>,
fn assert_no_diagnostics(
sources: HashMap<&str, &str>,
symbol_table: &mut SymbolTable,
) -> (Vec<CompilationUnit>, SimpleFiles<&'a str, &'a str>) {
) -> Vec<CompilationUnit> {
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([(
@ -174,80 +144,7 @@ mod tests {
",
)]);
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);
assert_no_diagnostics(sources, &mut SymbolTable::new());
}
#[test]
@ -298,7 +195,7 @@ mod tests {
)]);
assert_number_of_diagnostics(sources, &mut SymbolTable::new(), 1);
}
#[test]
fn sees_println() {
let sources = HashMap::from([(
@ -307,24 +204,17 @@ mod tests {
fn main(args: Array<String>)
println args
end
",
"
)]);
let mut symbol_table = SymbolTable::new();
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)
let global_std_core_use = StarUseSymbol::new(
&[Rc::from("std"), Rc::from("core")],
None
);
symbol_table.insert_star_use_symbol(global_std_core_use)
.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);
}
}

View File

@ -1,23 +1,9 @@
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::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::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::{
format_fqn, handle_insert_error, handle_lookup_error, join_fqn_parts,
};
use std::cell::RefCell;
use crate::name_analysis::util::{handle_insert_error, handle_lookup_error, join_fqn_parts};
use std::rc::Rc;
pub fn na_p2_compilation_unit(
@ -163,206 +149,9 @@ fn na_p2_function(
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// 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,
@ -372,9 +161,7 @@ fn na_p2_function_body(
FunctionBody::FunctionAliasBody(alias_body) => {
na_p2_function_alias_body(alias_body, symbol_table, diagnostics);
}
FunctionBody::FunctionEqualsBody(equals_body) => {
na_p2_function_equals_body(equals_body, symbol_table, diagnostics);
}
FunctionBody::FunctionEqualsBody(equals_body) => {}
FunctionBody::FunctionBlockBody(block_body) => {
na_p2_function_block_body(block_body, symbol_table, diagnostics);
}
@ -386,8 +173,10 @@ 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());
let maybe_function_symbol = symbol_table.lookup_function_symbol(
function_alias_body.identifier().name(),
*function_alias_body.scope_id().unwrap(),
);
match maybe_function_symbol {
Ok(function_symbol) => {
function_alias_body.set_resolved_function_symbol(function_symbol);
@ -404,23 +193,12 @@ 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);
}
@ -483,12 +261,12 @@ fn na_p2_variable_declaration(
);
}
}
// type-use
if let Some(type_use) = variable_declaration.type_use_mut() {
na_p2_type_use(type_use, symbol_table, diagnostics);
}
// initializer
if let Some(expression) = variable_declaration.expression_mut() {
na_p2_expression(expression, symbol_table, diagnostics);
@ -500,16 +278,8 @@ 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(
@ -517,43 +287,8 @@ fn na_p2_l_value(
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
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);
}
}
na_p2_variable_use(l_value.variable_use_mut(), symbol_table, diagnostics);
// TODO: suffixes
}
fn na_p2_expression_statement(
@ -561,11 +296,28 @@ fn na_p2_expression_statement(
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
na_p2_expression(
expression_statement.expression_mut(),
symbol_table,
diagnostics,
);
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(),
diagnostics,
);
}
}
}
fn na_p2_expression(
@ -599,13 +351,13 @@ fn na_p2_expression(
todo!()
}
Expression::Suffix(suffix) => {
na_p2_suffix_expression(suffix, symbol_table, diagnostics);
todo!()
}
Expression::Literal(literal) => {
todo!()
}
Expression::Identifier(identifier_expression) => {
na_p2_identifier_expression(identifier_expression, symbol_table, diagnostics);
Expression::VariableUse(variable_use) => {
na_p2_variable_use(variable_use, symbol_table, diagnostics);
}
Expression::Fqn(fqn) => {
todo!()
@ -619,110 +371,24 @@ fn na_p2_expression(
}
}
fn na_p2_suffix_expression(
suffix_expression: &mut SuffixExpression,
fn na_p2_type_use(
type_use: &mut TypeUse,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
na_p2_expression(
suffix_expression.expression_mut(),
symbol_table,
diagnostics,
);
na_p2_suffix_operator(suffix_expression.operator_mut(), symbol_table, diagnostics);
}
fn na_p2_suffix_operator(
suffix_operator: &mut SuffixOperator,
symbol_table: &mut SymbolTable,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match suffix_operator {
SuffixOperator::PlusPlus => {
// no-op
match type_use {
TypeUse::PrimitiveType(primitive_type_use) => {
todo!()
}
SuffixOperator::MinusMinus => {
// no-op
TypeUse::InterfaceOrClassTypeUse(interface_or_class_type_use) => {
todo!()
}
SuffixOperator::ObjectProperty(_) => {
// no-op; props checked during type checking
TypeUse::TupleTypeUse(tuple_type_use) => {
todo!()
}
SuffixOperator::ObjectIndex(object_index) => {
na_p2_object_index(object_index, symbol_table, diagnostics);
}
SuffixOperator::Call(call) => {
na_p2_call(call, symbol_table, diagnostics);
TypeUse::FunctionTypeUse(function_type_use) => {
todo!()
}
}
}
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);
}
}

View File

@ -1,33 +0,0 @@
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>>
}
}
}
}

View File

@ -1,6 +1,5 @@
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;
@ -19,10 +18,10 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition;
use std::fmt::Debug;
pub use self::{
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::*,
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::*,
};
pub trait Symbol: Debug {

View File

@ -30,14 +30,6 @@ 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 {
@ -51,7 +43,6 @@ 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()
}
}

View File

@ -109,10 +109,9 @@ impl Symbol for StarUseSymbol {
impl Debug for StarUseSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StarUseSymbol")
f.debug_struct("StarUseStatementSymbol")
.field("fqn", &join_fqn_parts(&self.fqn_parts))
.field("source_definition", &self.source_definition)
.field("resolved_symbols", &self.resolved_symbols)
.finish()
}
}

View File

@ -5,8 +5,7 @@ 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::variable_symbol::VariableSymbol;
use crate::name_analysis::symbol::{ExpressibleSymbol, LVSymbol, Symbol};
use crate::name_analysis::symbol::{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;
@ -15,6 +14,7 @@ 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,7 +25,6 @@ pub enum SymbolInsertError {
SymbolAlreadyDefined(Rc<RefCell<dyn Symbol>>),
}
#[derive(Debug)]
pub enum SymbolLookupError {
NoDefinition,
NoSuchNamespace,
@ -45,7 +44,7 @@ impl SymbolTable {
Self {
scopes: vec![Scope::new(None, 0, String::from("GlobalScope"))],
current_scope_id: 0,
symbol_tree: Box::new(SymbolTree::new("<DEFAULT>")),
symbol_tree: Box::new(SymbolTree::new()),
fqn_context: Box::new(FqnContext::new()),
}
}
@ -69,7 +68,7 @@ impl SymbolTable {
self.current_scope_id = parent_id;
}
}
pub fn set_current_scope(&mut self, id: usize) {
self.current_scope_id = id;
}
@ -123,15 +122,6 @@ 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>],
@ -241,7 +231,7 @@ impl SymbolTable {
Ok(inserted)
}
}
pub fn insert_variable_symbol(
&mut self,
variable_symbol: VariableSymbol,
@ -276,12 +266,9 @@ impl SymbolTable {
pub fn lookup_type_by_fqn(&self, fqn_parts: &[&str]) -> Result<TypeSymbol, SymbolLookupError> {
todo!()
}
pub fn lookup_function_symbol(
&self,
declared_name: &str,
) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolLookupError> {
let mut current_scope: Option<&Scope> = Some(self.current_scope());
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);
while let Some(scope) = current_scope.take() {
if let Some(function_symbol) = scope.find_function_symbol(declared_name) {
return Ok(function_symbol.clone());
@ -293,29 +280,12 @@ impl SymbolTable {
}
Err(SymbolLookupError::NoDefinition)
}
pub fn lookup_lv_symbol(&self, declared_name: &str) -> Result<LVSymbol, SymbolLookupError> {
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);
} 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);
return Ok(lv_symbol)
} else {
current_scope = scope
.parent()
@ -332,8 +302,6 @@ impl Display for SymbolTable {
for scope in &self.scopes {
writeln!(f, "{}", scope)?;
}
writeln!(f, "---SymbolTable: SymbolTree---")?;
writeln!(f, "{}", self.symbol_tree)?;
Ok(())
}
}

View File

@ -10,7 +10,6 @@ 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};
@ -143,7 +142,7 @@ impl Scope {
let key = symbol.declared_name_owned();
insert_symbol!(self.parameter_symbols, symbol, key)
}
pub fn insert_variable_symbol(
&mut self,
symbol: VariableSymbol,
@ -204,84 +203,11 @@ impl Scope {
.map(|variable_symbol| LVSymbol::Variable(variable_symbol.clone()))
})
}
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
}

View File

@ -4,15 +4,12 @@ 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>>>>,
@ -20,9 +17,8 @@ pub struct SymbolTree {
}
impl SymbolTree {
pub fn new(debug_name: &str) -> Self {
pub fn new() -> Self {
Self {
debug_name: debug_name.to_string(),
children: Box::new(HashMap::new()),
classes: Box::new(HashMap::new()),
interfaces: Box::new(HashMap::new()),
@ -82,13 +78,13 @@ impl SymbolTree {
}
if fqn_parts.len() == 1 {
self.children
.insert(fqn_parts[0].clone(), SymbolTree::new(fqn_parts[0].as_ref()));
.insert(fqn_parts[0].clone(), SymbolTree::new());
} 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(fqn_parts[0].as_ref());
let mut child = SymbolTree::new();
child.recurse_register_module(&fqn_parts[1..]);
self.children.insert(fqn_parts[0].clone(), child);
}
@ -109,12 +105,6 @@ 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()) {
@ -147,7 +137,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[1..])
child.find_all_by_base_fqn(fqn_parts)
} else {
Err(SymbolLookupError::NoSuchNamespace)
}
@ -155,55 +145,3 @@ 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)
}
}

View File

@ -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,7 +69,3 @@ 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<_>>()
}

View File

@ -447,12 +447,6 @@ Function:
node:
or_else: void
- function_body
fields:
- function_symbol:
kind: FunctionSymbol
wrap: rc_ref_cell
- scope_id:
kind: usize
OperatorFunction:
struct:
children:
@ -615,6 +609,9 @@ FunctionEqualsBody:
struct:
children:
- expression
fields:
- scope_id:
kind: usize
FunctionAliasBody:
struct:
children:
@ -623,6 +620,8 @@ FunctionAliasBody:
rule: Alias
- identifier
fields:
- scope_id:
kind: usize
- resolved_function_symbol:
kind: FunctionSymbol
wrap: rc_ref_cell
@ -635,6 +634,9 @@ FunctionBlockBody:
- end_kw:
skip:
rule: End
fields:
- scope_id:
kind: usize
# Class constructs
ClassConstructor:
@ -785,19 +787,25 @@ ForStatement:
LValue:
struct:
children:
- identifier
- variable_use
- 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:
@ -832,9 +840,9 @@ Expression:
- Literal:
inner:
kind: Literal
- Identifier:
- VariableUse:
inner:
kind: IdentifierExpression
kind: VariableUse
- Fqn:
inner:
kind: FullyQualifiedName
@ -1177,9 +1185,9 @@ PrimaryExpression:
- Literal:
inner:
kind: Literal
- Identifier:
- VariableUse:
inner:
kind: IdentifierExpression
kind: VariableUse
- Fqn:
inner:
kind: FullyQualifiedName
@ -1192,13 +1200,6 @@ PrimaryExpression:
- ParenthesizedExpression:
pass_through:
kind: Expression
IdentifierExpression:
struct:
children:
- identifier
fields:
- expressible_symbol:
kind: ExpressibleSymbol
ListExpression:
struct:
children:

View File

@ -615,7 +615,7 @@ ForStatement = {
// LValue
LValue = {
Identifier
VariableUse
~ LValueSuffix*
}
@ -624,6 +624,12 @@ LValueSuffix = {
| ObjectIndex
}
// Variable Use
VariableUse = {
Identifier
}
// Expressions
Expression = {
@ -772,17 +778,13 @@ ObjectIndex = {
PrimaryExpression = {
Literal
| IdentifierExpression
| VariableUse
| FullyQualifiedName
| Closure
| ListExpression
| ParenthesizedExpression
}
IdentifierExpression = {
Identifier
}
ListExpression = {
"["
~ ExpressionList?

View File

@ -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.register_function_symbol(println_symbol);
symbol_table.insert_function_symbol(println_symbol)?;
Ok(())
}

View File

@ -1,11 +1,15 @@
pub struct IndentWriter<'a> {
pub struct IndentWriter {
indent_level: usize,
indent_string: String,
out: &'a mut dyn std::fmt::Write,
out: Box<dyn std::io::Write>,
}
impl<'a> IndentWriter<'a> {
pub fn new(start_level: usize, indent_string: &str, out: &'a mut dyn std::fmt::Write) -> Self {
impl IndentWriter {
pub fn new(
start_level: usize,
indent_string: &str,
out: Box<dyn std::io::Write>,
) -> IndentWriter {
IndentWriter {
indent_level: start_level,
indent_string: indent_string.to_string(),
@ -21,22 +25,22 @@ impl<'a> IndentWriter<'a> {
self.indent_level -= 1;
}
pub fn write(&mut self, s: &str) -> std::fmt::Result {
pub fn write(&mut self, s: &str) -> std::io::Result<()> {
write!(self.out, "{}", s)
}
pub fn writeln(&mut self, s: &str) -> std::fmt::Result {
pub fn writeln(&mut self, s: &str) -> std::io::Result<()> {
self.write(&format!("{}\n", s))
}
pub fn write_indented(&mut self, s: &str) -> std::fmt::Result {
pub fn write_indented(&mut self, s: &str) -> std::io::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::fmt::Result {
pub fn writeln_indented(&mut self, s: &str) -> std::io::Result<()> {
self.write_indented(&format!("{}\n", s))
}
}