824 lines
27 KiB
Rust
824 lines
27 KiB
Rust
use crate::ast::node::{
|
|
AnySpaceSuffixOperator, AssignmentStatement, BacktickString, BoundSuffixOperator, Call,
|
|
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, DString, Expression,
|
|
ExpressionList, ExpressionStatement, Function, FunctionAliasBody, FunctionBlockBody,
|
|
FunctionBody, FunctionEqualsBody, GenericParameters, Identifier, IdentifierExpression,
|
|
IdentifierOrFqn, LValue, LValueSuffix, Literal, ModuleLevelDeclaration,
|
|
NoNewlineSuffixOperator, ObjectIndex, Parameter, Parameters, PlatformFunction, 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::{
|
|
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(
|
|
compilation_unit: &mut CompilationUnit,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
for use_statement in compilation_unit.use_statements_mut() {
|
|
na_p2_use_statement(use_statement, symbol_table, diagnostics);
|
|
}
|
|
for declaration in compilation_unit.module_level_declarations_mut() {
|
|
na_p2_module_level_declaration(declaration, symbol_table, diagnostics);
|
|
}
|
|
}
|
|
|
|
fn na_p2_use_statement(
|
|
use_statement: &mut UseStatement,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
match use_statement {
|
|
UseStatement::ConcreteUseStatement(concrete_use_statement) => {
|
|
na_p2_concrete_use_statement(concrete_use_statement, symbol_table, diagnostics);
|
|
}
|
|
UseStatement::StarUseStatement(star_use_statement) => {
|
|
na_p2_star_use_statement(star_use_statement, symbol_table, diagnostics);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_concrete_use_statement(
|
|
concrete_use_statement: &mut ConcreteUseStatement,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
let base_fqn_parts = concrete_use_statement
|
|
.prefixes()
|
|
.map(UseStatementPrefix::identifier)
|
|
.map(Identifier::name)
|
|
.map(Rc::from)
|
|
.collect::<Vec<Rc<str>>>();
|
|
|
|
match concrete_use_statement.suffix_mut() {
|
|
ConcreteUseStatementSuffix::UseStatementIdentifier(use_statement_identifier) => {
|
|
handle_concrete_use_statement_identifier(
|
|
&base_fqn_parts,
|
|
use_statement_identifier,
|
|
symbol_table,
|
|
diagnostics,
|
|
);
|
|
}
|
|
ConcreteUseStatementSuffix::UseList(use_list) => {
|
|
for use_statement_identifier in use_list.identifiers_mut() {
|
|
handle_concrete_use_statement_identifier(
|
|
&base_fqn_parts,
|
|
use_statement_identifier,
|
|
symbol_table,
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn handle_concrete_use_statement_identifier(
|
|
base_fqn_parts: &[Rc<str>],
|
|
use_statement_identifier: &mut UseStatementIdentifier,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
let fqn_parts = {
|
|
let mut all_parts = base_fqn_parts.to_vec();
|
|
all_parts.push(Rc::from(use_statement_identifier.identifier().name()));
|
|
all_parts
|
|
};
|
|
|
|
let maybe_usable_symbol = symbol_table.find_usable_symbol(&fqn_parts);
|
|
if let Some(usable_symbol) = maybe_usable_symbol {
|
|
use_statement_identifier
|
|
.symbol_mut()
|
|
.expect("Should have set the symbol on the use statement already.")
|
|
.borrow_mut()
|
|
.set_resolved_symbol(usable_symbol);
|
|
} else {
|
|
handle_lookup_error(
|
|
SymbolLookupError::NoDefinition,
|
|
&join_fqn_parts(&fqn_parts),
|
|
use_statement_identifier.identifier().file_id(),
|
|
use_statement_identifier.identifier().range(),
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|
|
|
|
fn na_p2_star_use_statement(
|
|
star_use_statement: &mut StarUseStatement,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
let mut symbol_ref_mut = star_use_statement.symbol().unwrap().borrow_mut();
|
|
match symbol_table.find_usable_symbols_by_base_fqn(symbol_ref_mut.fqn_parts()) {
|
|
Ok(usable_symbols) => {
|
|
symbol_ref_mut.set_resolved_symbols(usable_symbols);
|
|
}
|
|
Err(symbol_lookup_error) => {
|
|
handle_lookup_error(
|
|
symbol_lookup_error,
|
|
&join_fqn_parts(symbol_ref_mut.fqn_parts()),
|
|
star_use_statement.file_id(),
|
|
star_use_statement.range(),
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_module_level_declaration(
|
|
module_level_declaration: &mut ModuleLevelDeclaration,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
match module_level_declaration {
|
|
ModuleLevelDeclaration::Module(module_declaration) => {
|
|
todo!()
|
|
}
|
|
ModuleLevelDeclaration::Interface(interface) => {
|
|
todo!()
|
|
}
|
|
ModuleLevelDeclaration::Class(class) => {
|
|
todo!()
|
|
}
|
|
ModuleLevelDeclaration::Function(function) => {
|
|
na_p2_function(function, symbol_table, diagnostics);
|
|
}
|
|
ModuleLevelDeclaration::PlatformFunction(platform_function) => {
|
|
na_p2_platform_function(platform_function, symbol_table, diagnostics);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_function(
|
|
function: &mut 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_platform_function(
|
|
platform_function: &mut PlatformFunction,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
// change to this function's scope
|
|
symbol_table.set_current_scope(*platform_function.scope_id().unwrap());
|
|
|
|
// generics
|
|
na_p2_generic_parameters(platform_function.generics_mut(), symbol_table, diagnostics);
|
|
|
|
// parameters
|
|
let parameter_symbols = na_p2_parameters(
|
|
platform_function.parameters_mut(),
|
|
symbol_table,
|
|
diagnostics,
|
|
);
|
|
platform_function
|
|
.function_symbol_mut()
|
|
.unwrap()
|
|
.borrow_mut()
|
|
.set_parameter_symbols(parameter_symbols);
|
|
|
|
// return_type
|
|
let maybe_return_type_symbol = na_p2_return_type(
|
|
platform_function.return_type_mut(),
|
|
symbol_table,
|
|
diagnostics,
|
|
);
|
|
if let Some(return_type_symbol) = maybe_return_type_symbol {
|
|
platform_function
|
|
.function_symbol_mut()
|
|
.unwrap()
|
|
.borrow_mut()
|
|
.set_return_type(return_type_symbol);
|
|
}
|
|
}
|
|
|
|
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,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
match 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::FunctionBlockBody(block_body) => {
|
|
na_p2_function_block_body(block_body, symbol_table, diagnostics);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_function_alias_body(
|
|
function_alias_body: &mut FunctionAliasBody,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
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);
|
|
}
|
|
Err(symbol_lookup_error) => {
|
|
handle_lookup_error(
|
|
symbol_lookup_error,
|
|
function_alias_body.identifier().name(),
|
|
function_alias_body.identifier().file_id(),
|
|
function_alias_body.identifier().range(),
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
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>,
|
|
) {
|
|
for statement in function_block_body.statements_mut() {
|
|
na_p2_statement(statement, symbol_table, diagnostics);
|
|
}
|
|
}
|
|
|
|
fn na_p2_statement(
|
|
statement: &mut Statement,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
match statement {
|
|
Statement::VariableDeclaration(variable_declaration) => {
|
|
na_p2_variable_declaration(variable_declaration, symbol_table, diagnostics);
|
|
}
|
|
Statement::AssignmentStatement(assignment_statement) => {
|
|
na_p2_assignment_statement(assignment_statement, symbol_table, diagnostics);
|
|
}
|
|
Statement::ExpressionStatement(expression_statement) => {
|
|
na_p2_expression_statement(expression_statement, symbol_table, diagnostics);
|
|
}
|
|
Statement::UseStatement(use_statement) => {
|
|
todo!()
|
|
}
|
|
Statement::IfStatement(if_statement) => {
|
|
todo!()
|
|
}
|
|
Statement::WhileStatement(while_statement) => {
|
|
todo!()
|
|
}
|
|
Statement::ForStatement(for_statement) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_variable_declaration(
|
|
variable_declaration: &mut VariableDeclaration,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
// handle variable itself
|
|
let to_insert = VariableSymbol::new(
|
|
variable_declaration.identifier().name(),
|
|
variable_declaration.is_mut(),
|
|
Some(SourceDefinition::from_identifier(
|
|
variable_declaration.identifier(),
|
|
)),
|
|
);
|
|
match symbol_table.insert_variable_symbol(to_insert) {
|
|
Ok(variable_symbol) => {
|
|
variable_declaration.set_variable_symbol(variable_symbol);
|
|
}
|
|
Err(symbol_insert_error) => {
|
|
handle_insert_error(
|
|
symbol_insert_error,
|
|
variable_declaration.identifier().name(),
|
|
variable_declaration.identifier().file_id(),
|
|
variable_declaration.identifier().range(),
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
fn na_p2_assignment_statement(
|
|
assignment_statement: &mut AssignmentStatement,
|
|
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,
|
|
);
|
|
}
|
|
|
|
fn na_p2_l_value(
|
|
l_value: &mut LValue,
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_expression_statement(
|
|
expression_statement: &mut ExpressionStatement,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
na_p2_expression(
|
|
expression_statement.expression_mut(),
|
|
symbol_table,
|
|
diagnostics,
|
|
);
|
|
}
|
|
|
|
fn na_p2_expression(
|
|
expression: &mut Expression,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
match expression {
|
|
Expression::Ternary(ternary) => {
|
|
todo!()
|
|
}
|
|
Expression::Or(or) => {
|
|
todo!()
|
|
}
|
|
Expression::And(and) => {
|
|
todo!()
|
|
}
|
|
Expression::Comparison(comparison) => {
|
|
todo!()
|
|
}
|
|
Expression::Shift(shift) => {
|
|
todo!()
|
|
}
|
|
Expression::Additive(additive) => {
|
|
todo!()
|
|
}
|
|
Expression::Multiplicative(multiplicative) => {
|
|
todo!()
|
|
}
|
|
Expression::Prefix(prefix) => {
|
|
todo!()
|
|
}
|
|
Expression::Suffix(suffix) => {
|
|
na_p2_suffix_expression(suffix, symbol_table, diagnostics);
|
|
}
|
|
Expression::Literal(literal) => {
|
|
na_p2_literal(literal, symbol_table, diagnostics);
|
|
}
|
|
Expression::Identifier(identifier_expression) => {
|
|
na_p2_identifier_expression(identifier_expression, symbol_table, diagnostics);
|
|
}
|
|
Expression::Fqn(fqn) => {
|
|
todo!()
|
|
}
|
|
Expression::Closure(closure) => {
|
|
todo!()
|
|
}
|
|
Expression::List(list) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_suffix_expression(
|
|
suffix_expression: &mut SuffixExpression,
|
|
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::BoundSuffixOperator(bound_suffix) => {
|
|
match bound_suffix {
|
|
BoundSuffixOperator::PlusPlus => {
|
|
// no-op
|
|
}
|
|
BoundSuffixOperator::MinusMinus => {
|
|
// no-op
|
|
}
|
|
}
|
|
}
|
|
SuffixOperator::NoNewlineSuffixOperator(no_newline_suffix) => match no_newline_suffix {
|
|
NoNewlineSuffixOperator::ObjectIndex(object_index) => {
|
|
na_p2_object_index(object_index, symbol_table, diagnostics);
|
|
}
|
|
NoNewlineSuffixOperator::Call(call) => {
|
|
na_p2_call(call, symbol_table, diagnostics);
|
|
}
|
|
},
|
|
SuffixOperator::AnySpaceSuffixOperator(any_space_suffix) => {
|
|
match any_space_suffix {
|
|
AnySpaceSuffixOperator::ObjectProperty(_) => {
|
|
// no-op; this is checked during type checking
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
fn na_p2_literal(
|
|
literal: &mut Literal,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
match literal {
|
|
Literal::DString(d_string) => {
|
|
na_p2_d_string(d_string, symbol_table, diagnostics);
|
|
}
|
|
Literal::BacktickString(backtick_string) => {
|
|
na_p2_backtick_string(backtick_string, symbol_table, diagnostics);
|
|
}
|
|
_ => {
|
|
// no-op, nothing to check.
|
|
}
|
|
}
|
|
}
|
|
|
|
fn na_p2_d_string(
|
|
d_string: &mut DString,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
for d_string_expression in d_string.expressions_mut() {
|
|
na_p2_expression(
|
|
d_string_expression.expression_mut(),
|
|
symbol_table,
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|
|
|
|
fn na_p2_backtick_string(
|
|
backtick_string: &mut BacktickString,
|
|
symbol_table: &mut SymbolTable,
|
|
diagnostics: &mut Vec<DmDiagnostic>,
|
|
) {
|
|
for d_string_expression in backtick_string.expressions_mut() {
|
|
na_p2_expression(
|
|
d_string_expression.expression_mut(),
|
|
symbol_table,
|
|
diagnostics,
|
|
);
|
|
}
|
|
}
|