WIP AnalysisContext abstraction and methods.
This commit is contained in:
parent
c54db2d70d
commit
08625404ae
@ -6,8 +6,7 @@ use dmc_lib::diagnostic::Diagnostics;
|
|||||||
use dmc_lib::ir::variable_locations::VariableLocations;
|
use dmc_lib::ir::variable_locations::VariableLocations;
|
||||||
use dmc_lib::lexer::Lexer;
|
use dmc_lib::lexer::Lexer;
|
||||||
use dmc_lib::parser::{parse_expression, parse_let_statement};
|
use dmc_lib::parser::{parse_expression, parse_let_statement};
|
||||||
use dmc_lib::semantic_analysis::AnalysisContext;
|
use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use dmc_lib::semantic_analysis::scope::{Scope, ScopeId};
|
|
||||||
use dmc_lib::token::TokenKind;
|
use dmc_lib::token::TokenKind;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
@ -305,16 +304,8 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
|
|||||||
let mut analysis_context = AnalysisContext::new();
|
let mut analysis_context = AnalysisContext::new();
|
||||||
|
|
||||||
analysis_context.push_scope("__repl_root_scope");
|
analysis_context.push_scope("__repl_root_scope");
|
||||||
|
analysis_context.push_scope("__repl_function_scope");
|
||||||
let root_scope_id = analysis_context.root_scope_id();
|
analysis_context.push_scope("__repl_body_scope");
|
||||||
analysis_context
|
|
||||||
.scopes_mut()
|
|
||||||
.push(Scope::new(Some(root_scope_id))); // function scope
|
|
||||||
let function_scope_id = analysis_context.scopes().len() - 1;
|
|
||||||
analysis_context
|
|
||||||
.scopes_mut()
|
|
||||||
.push(Scope::new(Some(function_scope_id))); // body scope
|
|
||||||
let body_scope_id = analysis_context.scopes().len() - 1;
|
|
||||||
|
|
||||||
let fqn: Rc<str> = Rc::from("__repl");
|
let fqn: Rc<str> = Rc::from("__repl");
|
||||||
let mut variable_locations = VariableLocations::new();
|
let mut variable_locations = VariableLocations::new();
|
||||||
@ -353,7 +344,6 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
|
|||||||
let compile_result = compile_let_statement_2(
|
let compile_result = compile_let_statement_2(
|
||||||
input,
|
input,
|
||||||
&mut analysis_context,
|
&mut analysis_context,
|
||||||
body_scope_id,
|
|
||||||
&fqn,
|
&fqn,
|
||||||
&mut variable_locations,
|
&mut variable_locations,
|
||||||
register_count,
|
register_count,
|
||||||
@ -378,7 +368,6 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
|
|||||||
let compile_result = compile_expression_2(
|
let compile_result = compile_expression_2(
|
||||||
input,
|
input,
|
||||||
&mut analysis_context,
|
&mut analysis_context,
|
||||||
body_scope_id,
|
|
||||||
&fqn,
|
&fqn,
|
||||||
&mut variable_locations,
|
&mut variable_locations,
|
||||||
register_count,
|
register_count,
|
||||||
@ -438,7 +427,6 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
|
|||||||
fn compile_expression_2(
|
fn compile_expression_2(
|
||||||
input: &str,
|
input: &str,
|
||||||
analysis_context: &mut AnalysisContext,
|
analysis_context: &mut AnalysisContext,
|
||||||
function_scope_id: ScopeId,
|
|
||||||
fqn: &Rc<str>,
|
fqn: &Rc<str>,
|
||||||
variable_locations: &mut VariableLocations,
|
variable_locations: &mut VariableLocations,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
@ -454,7 +442,6 @@ fn compile_expression_2(
|
|||||||
compile_statement_to_synthetic_function(
|
compile_statement_to_synthetic_function(
|
||||||
&statement,
|
&statement,
|
||||||
analysis_context,
|
analysis_context,
|
||||||
function_scope_id,
|
|
||||||
fqn.clone(),
|
fqn.clone(),
|
||||||
variable_locations,
|
variable_locations,
|
||||||
register_count,
|
register_count,
|
||||||
@ -465,7 +452,6 @@ fn compile_expression_2(
|
|||||||
fn compile_let_statement_2(
|
fn compile_let_statement_2(
|
||||||
input: &str,
|
input: &str,
|
||||||
analysis_context: &mut AnalysisContext,
|
analysis_context: &mut AnalysisContext,
|
||||||
function_scope_id: ScopeId,
|
|
||||||
fqn: &Rc<str>,
|
fqn: &Rc<str>,
|
||||||
variable_locations: &mut VariableLocations,
|
variable_locations: &mut VariableLocations,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
@ -478,7 +464,6 @@ fn compile_let_statement_2(
|
|||||||
compile_statement_to_synthetic_function(
|
compile_statement_to_synthetic_function(
|
||||||
&Statement::Let(maybe_let_statement.unwrap()),
|
&Statement::Let(maybe_let_statement.unwrap()),
|
||||||
analysis_context,
|
analysis_context,
|
||||||
function_scope_id,
|
|
||||||
fqn.clone(),
|
fqn.clone(),
|
||||||
variable_locations,
|
variable_locations,
|
||||||
register_count,
|
register_count,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use dm_std_lib::add_all_std_core;
|
|||||||
use dmc_lib::compile_compilation_unit;
|
use dmc_lib::compile_compilation_unit;
|
||||||
use dmc_lib::constants_table::ConstantsTable;
|
use dmc_lib::constants_table::ConstantsTable;
|
||||||
use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
|
use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
|
||||||
use dmc_lib::semantic_analysis::AnalysisContext;
|
use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::{DvmContext, call};
|
use dvm_lib::vm::{DvmContext, call};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|||||||
@ -325,7 +325,7 @@ mod tests {
|
|||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::lowering::lower_to_ir_compilation_unit;
|
use crate::lowering::lower_to_ir_compilation_unit;
|
||||||
use crate::parser::get_compilation_unit;
|
use crate::parser::get_compilation_unit;
|
||||||
use crate::semantic_analysis::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::analyze_compilation_unit;
|
use crate::semantic_analysis::analyze_compilation_unit;
|
||||||
|
|
||||||
fn line_graph() -> InterferenceGraph {
|
fn line_graph() -> InterferenceGraph {
|
||||||
|
|||||||
@ -5,10 +5,9 @@ use crate::ir::compile_dvm_function;
|
|||||||
use crate::ir::variable_locations::VariableLocations;
|
use crate::ir::variable_locations::VariableLocations;
|
||||||
use crate::lowering::{lower_to_ir_compilation_unit, lower_to_ir_synthetic_function};
|
use crate::lowering::{lower_to_ir_compilation_unit, lower_to_ir_synthetic_function};
|
||||||
use crate::parser::parse_compilation_unit;
|
use crate::parser::parse_compilation_unit;
|
||||||
use crate::semantic_analysis::scope::ScopeId;
|
|
||||||
use crate::semantic_analysis::{analyze_compilation_unit, analyze_statement};
|
use crate::semantic_analysis::{analyze_compilation_unit, analyze_statement};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
use semantic_analysis::AnalysisContext;
|
use semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -79,7 +78,6 @@ pub fn compile_compilation_unit(
|
|||||||
pub fn compile_statement_to_synthetic_function(
|
pub fn compile_statement_to_synthetic_function(
|
||||||
statement: &Statement,
|
statement: &Statement,
|
||||||
analysis_context: &mut AnalysisContext,
|
analysis_context: &mut AnalysisContext,
|
||||||
function_scope_id: ScopeId,
|
|
||||||
fqn: Rc<str>,
|
fqn: Rc<str>,
|
||||||
variable_locations: &mut VariableLocations,
|
variable_locations: &mut VariableLocations,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
|
|||||||
@ -23,7 +23,7 @@ use crate::ir::ir_statement::IrStatement;
|
|||||||
use crate::ir::ir_type_info::IrTypeInfo;
|
use crate::ir::ir_type_info::IrTypeInfo;
|
||||||
use crate::ir::ir_variable::{IrVariable, IrVariableId};
|
use crate::ir::ir_variable::{IrVariable, IrVariableId};
|
||||||
use crate::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info};
|
use crate::lowering::util::{return_type_info_to_ir_type_info, to_ir_type_info};
|
||||||
use crate::semantic_analysis::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::symbol::{Symbol, SymbolId};
|
use crate::semantic_analysis::symbol::{Symbol, SymbolId};
|
||||||
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|||||||
308
dmc-lib/src/semantic_analysis/analysis_context.rs
Normal file
308
dmc-lib/src/semantic_analysis/analysis_context.rs
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
use crate::ast::NodeId;
|
||||||
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::diagnostic_factories::symbol_not_found;
|
||||||
|
use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared;
|
||||||
|
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
||||||
|
use crate::semantic_analysis::symbol::{Symbol, SymbolId};
|
||||||
|
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
||||||
|
use crate::source_range::SourceRange;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct AnalysisContext {
|
||||||
|
fqn_stack: Vec<Rc<str>>,
|
||||||
|
scopes: Vec<Scope>,
|
||||||
|
current_scope_id: Option<ScopeId>,
|
||||||
|
nodes_to_scopes: HashMap<NodeId, ScopeId>,
|
||||||
|
symbols: Vec<Symbol>,
|
||||||
|
nodes_to_symbols: HashMap<NodeId, SymbolId>,
|
||||||
|
type_infos: Vec<TypeInfo>,
|
||||||
|
symbols_to_type_infos: HashMap<SymbolId, TypeInfoId>,
|
||||||
|
nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnalysisContext {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
fqn_stack: Vec::new(),
|
||||||
|
scopes: Vec::new(),
|
||||||
|
current_scope_id: None,
|
||||||
|
nodes_to_scopes: HashMap::new(),
|
||||||
|
symbols: Vec::new(),
|
||||||
|
nodes_to_symbols: HashMap::new(),
|
||||||
|
type_infos: Vec::new(),
|
||||||
|
symbols_to_type_infos: HashMap::new(),
|
||||||
|
nodes_to_type_infos: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit(&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rollback(&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scopes(&self) -> &[Scope] {
|
||||||
|
&self.scopes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scopes_mut(&mut self) -> &mut Vec<Scope> {
|
||||||
|
&mut self.scopes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbols(&self) -> &[Symbol] {
|
||||||
|
&self.symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> {
|
||||||
|
&self.nodes_to_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_infos(&self) -> &[TypeInfo] {
|
||||||
|
&self.type_infos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbols_to_type_infos(&self) -> &HashMap<SymbolId, TypeInfoId> {
|
||||||
|
&self.symbols_to_type_infos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nodes_to_type_infos(&self) -> &HashMap<NodeId, TypeInfoId> {
|
||||||
|
&self.nodes_to_type_infos
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_fqn_part(&mut self, part: Rc<str>) {
|
||||||
|
self.fqn_stack.push(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_fqn_part(&mut self) {
|
||||||
|
self.fqn_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_fqn(&self, suffix: &str) -> String {
|
||||||
|
let mut fqn = self.fqn_stack.clone();
|
||||||
|
fqn.push(suffix.into());
|
||||||
|
fqn.join("::")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_scope(&mut self, _debug_name: &str) {
|
||||||
|
let scope = Scope::new(self.current_scope_id);
|
||||||
|
self.scopes.push(scope);
|
||||||
|
self.current_scope_id = Some(self.scopes.len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scope(&self, scope_id: ScopeId) -> &Scope {
|
||||||
|
self.scopes.get(scope_id).expect(&format!(
|
||||||
|
"scope_id {} is not a valid index of self.scopes",
|
||||||
|
scope_id
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scope_mut(&mut self, scope_id: ScopeId) -> &mut Scope {
|
||||||
|
self.scopes.get_mut(scope_id).expect(&format!(
|
||||||
|
"scope_id {} is not a valid index of self.scopes",
|
||||||
|
scope_id
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_scope(&self) -> &Scope {
|
||||||
|
self.get_scope(self.current_scope_id.expect("current_scope_id is None"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_scope_mut(&mut self) -> &mut Scope {
|
||||||
|
self.get_scope_mut(self.current_scope_id.expect("current_scope_id is None"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_scope(&mut self) {
|
||||||
|
self.current_scope_id = self.get_current_scope().parent_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn associate_node_to_current_scope(&mut self, node_id: NodeId) {
|
||||||
|
self.nodes_to_scopes.insert(
|
||||||
|
node_id,
|
||||||
|
self.current_scope_id.expect("current_scope_id is None"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_symbol_in_scope(&mut self, scope_id: ScopeId, symbol: Symbol) -> SymbolId {
|
||||||
|
// get declared name
|
||||||
|
let declared_name = symbol.declared_name_owned();
|
||||||
|
|
||||||
|
// push the symbol
|
||||||
|
self.symbols.push(symbol);
|
||||||
|
let symbol_id = self.symbols.len() - 1;
|
||||||
|
|
||||||
|
// put it in scope
|
||||||
|
self.get_scope_mut(scope_id)
|
||||||
|
.insert_symbol(declared_name, symbol_id);
|
||||||
|
|
||||||
|
symbol_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn associate_node_to_symbol(&mut self, node_id: NodeId, symbol_id: SymbolId) {
|
||||||
|
self.nodes_to_symbols.insert(node_id, symbol_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_symbol_in_scope(&self, scope: &Scope, declared_name: &str) -> Option<&Symbol> {
|
||||||
|
scope.get_symbol_id(declared_name).map(|symbol_id| {
|
||||||
|
self.symbols.get(symbol_id).expect(&format!(
|
||||||
|
"symbol_id {} is not a valid index of self.symbols",
|
||||||
|
symbol_id
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use this function only when there is no node associated with the symbol. Otherwise use
|
||||||
|
/// `try_insert_symbol_in_node_scope`.
|
||||||
|
pub fn try_insert_symbol_in_scope(
|
||||||
|
&mut self,
|
||||||
|
to_insert: Symbol,
|
||||||
|
scope_id: ScopeId,
|
||||||
|
) -> Result<(), Diagnostic> {
|
||||||
|
let scope = self.get_scope(scope_id);
|
||||||
|
if let Some(already_declared) = self.get_symbol_in_scope(scope, to_insert.declared_name()) {
|
||||||
|
Err(symbol_already_declared(already_declared, &to_insert))
|
||||||
|
} else {
|
||||||
|
self.insert_symbol_in_scope(scope_id, to_insert);
|
||||||
|
// no associated node, so no need to update self.nodes_to_symbols
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_insert_associate_symbol_in_node_scope(
|
||||||
|
&mut self,
|
||||||
|
to_insert: Symbol,
|
||||||
|
owner_node_id: NodeId,
|
||||||
|
) -> Result<(), Diagnostic> {
|
||||||
|
let node_scope_id = self.nodes_to_scopes.get(&owner_node_id).expect(&format!(
|
||||||
|
"owner_node_id {} is not in self.nodes_to_scopes",
|
||||||
|
owner_node_id
|
||||||
|
));
|
||||||
|
let node_scope = self.get_scope(*node_scope_id);
|
||||||
|
if let Some(already_declared) =
|
||||||
|
self.get_symbol_in_scope(node_scope, to_insert.declared_name())
|
||||||
|
{
|
||||||
|
Err(symbol_already_declared(already_declared, &to_insert))
|
||||||
|
} else {
|
||||||
|
let symbol_id = self.insert_symbol_in_scope(*node_scope_id, to_insert);
|
||||||
|
self.associate_node_to_symbol(owner_node_id, symbol_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_symbol_id_by_declared_name_in_node_scope(
|
||||||
|
&self,
|
||||||
|
node_id: NodeId,
|
||||||
|
declared_name: &str,
|
||||||
|
) -> Option<SymbolId> {
|
||||||
|
let scope_id = self
|
||||||
|
.nodes_to_scopes
|
||||||
|
.get(&node_id)
|
||||||
|
.expect(&format!("node_id {} has no associated scope", node_id));
|
||||||
|
let scope = self.get_scope(*scope_id);
|
||||||
|
scope.get_symbol_id(declared_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn associate_node_with_self_symbol(&mut self, node_id: NodeId, declared_name: &str) {
|
||||||
|
let symbol_id = self
|
||||||
|
.get_symbol_id_by_declared_name_in_node_scope(node_id, declared_name)
|
||||||
|
.expect(&format!(
|
||||||
|
"could not get symbol_id for node_id {} and declared_name {}",
|
||||||
|
node_id, declared_name
|
||||||
|
));
|
||||||
|
self.associate_node_to_symbol(node_id, symbol_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookup_and_associate_symbol_to_node(
|
||||||
|
&mut self,
|
||||||
|
node_id: NodeId,
|
||||||
|
declared_name: &str,
|
||||||
|
node_source_range: &SourceRange,
|
||||||
|
) -> Result<(), Diagnostic> {
|
||||||
|
let scope_id = self
|
||||||
|
.nodes_to_scopes
|
||||||
|
.get(&node_id)
|
||||||
|
.expect(&format!("node_id {} has no associated scope", node_id));
|
||||||
|
let mut maybe_scope = Some(self.get_scope(*scope_id));
|
||||||
|
let mut found_symbol_id: Option<SymbolId> = None;
|
||||||
|
while let Some(scope) = maybe_scope {
|
||||||
|
match scope.get_symbol_id(declared_name) {
|
||||||
|
None => {
|
||||||
|
maybe_scope = match scope.parent_id() {
|
||||||
|
None => None,
|
||||||
|
Some(parent_id) => Some(self.get_scope(parent_id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(symbol_id) => {
|
||||||
|
found_symbol_id = Some(symbol_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match found_symbol_id {
|
||||||
|
None => Err(symbol_not_found(declared_name, node_source_range)),
|
||||||
|
Some(symbol_id) => {
|
||||||
|
self.associate_node_to_symbol(node_id, symbol_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_type_info(&mut self, type_info: TypeInfo) -> TypeInfoId {
|
||||||
|
self.type_infos.push(type_info);
|
||||||
|
self.type_infos.len() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_type_info_for_node(&mut self, type_info: TypeInfo, node_id: NodeId) {
|
||||||
|
self.type_infos.push(type_info);
|
||||||
|
self.nodes_to_type_infos
|
||||||
|
.insert(node_id, self.type_infos.len() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn associate_node_and_symbol_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) {
|
||||||
|
let symbol_id = self
|
||||||
|
.nodes_to_symbols
|
||||||
|
.get(&node_id)
|
||||||
|
.expect(&format!("node_id {} has no associated symbol", node_id));
|
||||||
|
self.symbols_to_type_infos.insert(*symbol_id, type_info_id);
|
||||||
|
self.nodes_to_type_infos.insert(node_id, type_info_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type_info_id_for_node(&self, node_id: NodeId) -> TypeInfoId {
|
||||||
|
*self
|
||||||
|
.nodes_to_type_infos
|
||||||
|
.get(&node_id)
|
||||||
|
.expect(&format!("node_id {} has no associated type", node_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type_info_for_node(&self, node_id: NodeId) -> &TypeInfo {
|
||||||
|
let type_info_id = self.get_type_info_id_for_node(node_id);
|
||||||
|
self.type_infos
|
||||||
|
.get(type_info_id)
|
||||||
|
.expect(&format!("invalid type_info_id {}", type_info_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type_info_by_id(&self, type_info_id: TypeInfoId) -> &TypeInfo {
|
||||||
|
self.type_infos
|
||||||
|
.get(type_info_id)
|
||||||
|
.expect(&format!("invalid type_info_id {}", type_info_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn associate_node_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) {
|
||||||
|
self.nodes_to_type_infos.insert(node_id, type_info_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookup_type_for_node_via_symbol(&self, node_id: NodeId) -> TypeInfoId {
|
||||||
|
let symbol_id = self
|
||||||
|
.nodes_to_symbols
|
||||||
|
.get(&node_id)
|
||||||
|
.expect(&format!("node_id {} has no associated symbol", node_id));
|
||||||
|
let symbol_type_info_id = self.symbols_to_type_infos.get(symbol_id).expect(&format!(
|
||||||
|
"symbol_id {} has no associated type_info",
|
||||||
|
symbol_id
|
||||||
|
));
|
||||||
|
*symbol_type_info_id
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ use crate::ast::identifier::Identifier;
|
|||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
use crate::ast::negative_expression::NegativeExpression;
|
use crate::ast::negative_expression::NegativeExpression;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::semantic_analysis::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
|
|
||||||
/// N.b.: the parent_scope_id refers to the **parent** of the compilation unit scope, and must
|
/// N.b.: the parent_scope_id refers to the **parent** of the compilation unit scope, and must
|
||||||
/// be a valid (non-panicking) index of `scopes`.
|
/// be a valid (non-panicking) index of `scopes`.
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::ast::extern_function::ExternFunction;
|
|||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::semantic_analysis::AnalysisContext;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::symbol::{FunctionSymbol, ParameterSymbol, Symbol};
|
use crate::semantic_analysis::symbol::{FunctionSymbol, ParameterSymbol, Symbol};
|
||||||
|
|
||||||
pub struct SymbolCollectionResult(pub Diagnostics);
|
pub struct SymbolCollectionResult(pub Diagnostics);
|
||||||
|
|||||||
@ -1,54 +1,21 @@
|
|||||||
use crate::ast::NodeId;
|
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
use crate::ast::extern_function::ExternFunction;
|
use crate::ast::extern_function::ExternFunction;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::semantic_analysis::symbol::SymbolId;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::type_info::{FunctionTypeInfo, TypeInfo, TypeInfoId};
|
use crate::semantic_analysis::type_info::{FunctionTypeInfo, TypeInfo, TypeInfoId};
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
struct CollectTypesContext<'a> {
|
pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) {
|
||||||
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
|
||||||
type_infos: &'a mut Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CollectTypesContext<'a> {
|
|
||||||
pub fn new(
|
|
||||||
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
|
||||||
type_infos: &'a mut Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
nodes_to_symbols,
|
|
||||||
type_infos,
|
|
||||||
symbols_to_type_infos,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_type_info(&mut self, type_info: TypeInfo) -> TypeInfoId {
|
|
||||||
self.type_infos.push(type_info);
|
|
||||||
self.type_infos.len() - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn collect_types(
|
|
||||||
compilation_unit: &CompilationUnit,
|
|
||||||
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
|
||||||
type_infos: &mut Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: &mut HashMap<SymbolId, TypeInfoId>,
|
|
||||||
) {
|
|
||||||
let mut ctx = CollectTypesContext::new(nodes_to_symbols, type_infos, symbols_to_type_infos);
|
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
collect_types_function(function, &mut ctx);
|
collect_types_function(function, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
for extern_function in compilation_unit.extern_functions() {
|
for extern_function in compilation_unit.extern_functions() {
|
||||||
collect_types_extern_function(extern_function, &mut ctx);
|
collect_types_extern_function(extern_function, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_types_function(function: &Function, ctx: &mut CollectTypesContext) {
|
fn collect_types_function(function: &Function, ctx: &mut AnalysisContext) {
|
||||||
let parameter_type_info_ids =
|
let parameter_type_info_ids =
|
||||||
collect_and_get_parameter_type_info_ids(function.parameters(), ctx);
|
collect_and_get_parameter_type_info_ids(function.parameters(), ctx);
|
||||||
|
|
||||||
@ -64,9 +31,7 @@ fn collect_types_function(function: &Function, ctx: &mut CollectTypesContext) {
|
|||||||
));
|
));
|
||||||
let function_type_info_id = ctx.insert_type_info(function_type_info);
|
let function_type_info_id = ctx.insert_type_info(function_type_info);
|
||||||
|
|
||||||
let symbol_id = ctx.nodes_to_symbols[&function.node_id()];
|
ctx.associate_node_and_symbol_to_type(function.node_id(), function_type_info_id);
|
||||||
ctx.symbols_to_type_infos
|
|
||||||
.insert(symbol_id, function_type_info_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declared_name_to_type_info(declared_name: &str) -> TypeInfo {
|
fn declared_name_to_type_info(declared_name: &str) -> TypeInfo {
|
||||||
@ -82,7 +47,7 @@ fn declared_name_to_type_info(declared_name: &str) -> TypeInfo {
|
|||||||
|
|
||||||
fn collect_and_get_parameter_type_info_ids(
|
fn collect_and_get_parameter_type_info_ids(
|
||||||
parameters: &[Parameter],
|
parameters: &[Parameter],
|
||||||
ctx: &mut CollectTypesContext,
|
ctx: &mut AnalysisContext,
|
||||||
) -> Vec<TypeInfoId> {
|
) -> Vec<TypeInfoId> {
|
||||||
let mut parameter_type_info_ids: Vec<TypeInfoId> = Vec::new();
|
let mut parameter_type_info_ids: Vec<TypeInfoId> = Vec::new();
|
||||||
for parameter in parameters {
|
for parameter in parameters {
|
||||||
@ -91,13 +56,12 @@ fn collect_and_get_parameter_type_info_ids(
|
|||||||
parameter_type_info_ids.push(type_info_id);
|
parameter_type_info_ids.push(type_info_id);
|
||||||
|
|
||||||
// also associate the parameter symbol with the type info
|
// also associate the parameter symbol with the type info
|
||||||
let symbol_id = ctx.nodes_to_symbols[¶meter.node_id()];
|
ctx.associate_node_and_symbol_to_type(parameter.node_id(), type_info_id);
|
||||||
ctx.symbols_to_type_infos.insert(symbol_id, type_info_id);
|
|
||||||
}
|
}
|
||||||
parameter_type_info_ids
|
parameter_type_info_ids
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_types_extern_function(extern_function: &ExternFunction, ctx: &mut CollectTypesContext) {
|
fn collect_types_extern_function(extern_function: &ExternFunction, ctx: &mut AnalysisContext) {
|
||||||
let parameter_type_info_ids =
|
let parameter_type_info_ids =
|
||||||
collect_and_get_parameter_type_info_ids(extern_function.parameters(), ctx);
|
collect_and_get_parameter_type_info_ids(extern_function.parameters(), ctx);
|
||||||
|
|
||||||
@ -112,7 +76,5 @@ fn collect_types_extern_function(extern_function: &ExternFunction, ctx: &mut Col
|
|||||||
|
|
||||||
let function_type_info_id = ctx.insert_type_info(function_type_info);
|
let function_type_info_id = ctx.insert_type_info(function_type_info);
|
||||||
|
|
||||||
let symbol_id = ctx.nodes_to_symbols[&extern_function.node_id()];
|
ctx.associate_node_and_symbol_to_type(extern_function.node_id(), function_type_info_id);
|
||||||
ctx.symbols_to_type_infos
|
|
||||||
.insert(symbol_id, function_type_info_id);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use crate::ast::NodeId;
|
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::diagnostic::{Diagnostic, Diagnostics};
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::semantic_analysis::collect_scopes::{
|
use crate::semantic_analysis::collect_scopes::{
|
||||||
collect_scopes_compilation_unit, collect_scopes_statement,
|
collect_scopes_compilation_unit, collect_scopes_statement,
|
||||||
};
|
};
|
||||||
@ -9,19 +8,15 @@ use crate::semantic_analysis::collect_symbols::{
|
|||||||
SymbolCollectionResult, collect_symbols_compilation_unit,
|
SymbolCollectionResult, collect_symbols_compilation_unit,
|
||||||
};
|
};
|
||||||
use crate::semantic_analysis::collect_types::collect_types;
|
use crate::semantic_analysis::collect_types::collect_types;
|
||||||
use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared;
|
|
||||||
use crate::semantic_analysis::resolve_names::{
|
use crate::semantic_analysis::resolve_names::{
|
||||||
NameResolutionResult, resolve_names_in_compilation_unit, resolve_names_in_statement,
|
NameResolutionResult, resolve_names_in_compilation_unit, resolve_names_in_statement,
|
||||||
};
|
};
|
||||||
use crate::semantic_analysis::resolve_types::{
|
use crate::semantic_analysis::resolve_types::{
|
||||||
ResolveTypesResult, resolve_types_in_compilation_unit, resolve_types_in_statement,
|
ResolveTypesResult, resolve_types_in_compilation_unit, resolve_types_in_statement,
|
||||||
};
|
};
|
||||||
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
use analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::symbol::{Symbol, SymbolId};
|
|
||||||
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
|
pub mod analysis_context;
|
||||||
mod collect_scopes;
|
mod collect_scopes;
|
||||||
mod collect_symbols;
|
mod collect_symbols;
|
||||||
mod collect_types;
|
mod collect_types;
|
||||||
@ -32,195 +27,6 @@ pub mod scope;
|
|||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod type_info;
|
pub mod type_info;
|
||||||
|
|
||||||
pub struct AnalysisContext {
|
|
||||||
fqn_stack: Vec<Rc<str>>,
|
|
||||||
root_scope_id: ScopeId,
|
|
||||||
scopes: Vec<Scope>,
|
|
||||||
current_scope_id: Option<ScopeId>,
|
|
||||||
nodes_to_scopes: HashMap<NodeId, ScopeId>,
|
|
||||||
symbols: Vec<Symbol>,
|
|
||||||
nodes_to_symbols: HashMap<NodeId, SymbolId>,
|
|
||||||
type_infos: Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: HashMap<SymbolId, TypeInfoId>,
|
|
||||||
nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AnalysisContext {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
fqn_stack: Vec::new(),
|
|
||||||
root_scope_id: 0, // pushed in vec! below
|
|
||||||
scopes: vec![Scope::new(None)],
|
|
||||||
current_scope_id: None,
|
|
||||||
nodes_to_scopes: HashMap::new(),
|
|
||||||
symbols: Vec::new(),
|
|
||||||
nodes_to_symbols: HashMap::new(),
|
|
||||||
type_infos: Vec::new(),
|
|
||||||
symbols_to_type_infos: HashMap::new(),
|
|
||||||
nodes_to_type_infos: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit(&mut self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rollback(&mut self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_scope_id(&self) -> ScopeId {
|
|
||||||
self.root_scope_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scopes(&self) -> &[Scope] {
|
|
||||||
&self.scopes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scopes_mut(&mut self) -> &mut Vec<Scope> {
|
|
||||||
&mut self.scopes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn symbols(&self) -> &[Symbol] {
|
|
||||||
&self.symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> {
|
|
||||||
&self.nodes_to_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_infos(&self) -> &[TypeInfo] {
|
|
||||||
&self.type_infos
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn symbols_to_type_infos(&self) -> &HashMap<SymbolId, TypeInfoId> {
|
|
||||||
&self.symbols_to_type_infos
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nodes_to_type_infos(&self) -> &HashMap<NodeId, TypeInfoId> {
|
|
||||||
&self.nodes_to_type_infos
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_fqn_part(&mut self, part: Rc<str>) {
|
|
||||||
self.fqn_stack.push(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_fqn_part(&mut self) {
|
|
||||||
self.fqn_stack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_fqn(&self, suffix: &str) -> String {
|
|
||||||
let mut fqn = self.fqn_stack.clone();
|
|
||||||
fqn.push(suffix.into());
|
|
||||||
fqn.join("::")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_scope(&mut self, _debug_name: &str) {
|
|
||||||
let scope = Scope::new(self.current_scope_id);
|
|
||||||
self.scopes.push(scope);
|
|
||||||
self.current_scope_id = Some(self.scopes.len() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_scope(&self, scope_id: ScopeId) -> &Scope {
|
|
||||||
self.scopes.get(scope_id).expect(&format!(
|
|
||||||
"scope_id {} is not a valid index of self.scopes",
|
|
||||||
scope_id
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_scope_mut(&mut self, scope_id: ScopeId) -> &mut Scope {
|
|
||||||
self.scopes.get_mut(scope_id).expect(&format!(
|
|
||||||
"scope_id {} is not a valid index of self.scopes",
|
|
||||||
scope_id
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_current_scope(&self) -> &Scope {
|
|
||||||
self.get_scope(self.current_scope_id.expect("current_scope_id is None"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_current_scope_mut(&mut self) -> &mut Scope {
|
|
||||||
self.get_scope_mut(self.current_scope_id.expect("current_scope_id is None"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_scope(&mut self) {
|
|
||||||
self.current_scope_id = self.get_current_scope().parent_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn associate_node_to_current_scope(&mut self, node_id: NodeId) {
|
|
||||||
self.nodes_to_scopes.insert(
|
|
||||||
node_id,
|
|
||||||
self.current_scope_id.expect("current_scope_id is None"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_symbol_in_scope(&mut self, scope_id: ScopeId, symbol: Symbol) -> SymbolId {
|
|
||||||
// get declared name
|
|
||||||
let declared_name = symbol.declared_name_owned();
|
|
||||||
|
|
||||||
// push the symbol
|
|
||||||
self.symbols.push(symbol);
|
|
||||||
let symbol_id = self.symbols.len() - 1;
|
|
||||||
|
|
||||||
// put it in scope
|
|
||||||
self.get_scope_mut(scope_id)
|
|
||||||
.insert_symbol(declared_name, symbol_id);
|
|
||||||
|
|
||||||
symbol_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn associate_node_to_symbol(&mut self, node_id: NodeId, symbol_id: SymbolId) {
|
|
||||||
self.nodes_to_symbols.insert(node_id, symbol_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_symbol_in_scope(&self, scope: &Scope, declared_name: &str) -> Option<&Symbol> {
|
|
||||||
scope.get_symbol_id(declared_name).map(|symbol_id| {
|
|
||||||
self.symbols.get(symbol_id).expect(&format!(
|
|
||||||
"symbol_id {} is not a valid index of self.symbols",
|
|
||||||
symbol_id
|
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Use this function only when there is no node associated with the symbol. Otherwise use
|
|
||||||
/// `try_insert_symbol_in_node_scope`.
|
|
||||||
pub fn try_insert_symbol_in_scope(
|
|
||||||
&mut self,
|
|
||||||
to_insert: Symbol,
|
|
||||||
scope_id: ScopeId,
|
|
||||||
) -> Result<(), Diagnostic> {
|
|
||||||
let scope = self.get_scope(scope_id);
|
|
||||||
if let Some(already_declared) = self.get_symbol_in_scope(scope, to_insert.declared_name()) {
|
|
||||||
Err(symbol_already_declared(already_declared, &to_insert))
|
|
||||||
} else {
|
|
||||||
self.insert_symbol_in_scope(scope_id, to_insert);
|
|
||||||
// no associated node, so no need to update self.nodes_to_symbols
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_insert_associate_symbol_in_node_scope(
|
|
||||||
&mut self,
|
|
||||||
to_insert: Symbol,
|
|
||||||
owner_node_id: NodeId,
|
|
||||||
) -> Result<(), Diagnostic> {
|
|
||||||
let node_scope_id = self.nodes_to_scopes.get(&owner_node_id).expect(&format!(
|
|
||||||
"owner_node_id {} is not in self.nodes_to_scopes",
|
|
||||||
owner_node_id
|
|
||||||
));
|
|
||||||
let node_scope = self.get_scope(*node_scope_id);
|
|
||||||
if let Some(already_declared) =
|
|
||||||
self.get_symbol_in_scope(node_scope, to_insert.declared_name())
|
|
||||||
{
|
|
||||||
Err(symbol_already_declared(already_declared, &to_insert))
|
|
||||||
} else {
|
|
||||||
let symbol_id = self.insert_symbol_in_scope(*node_scope_id, to_insert);
|
|
||||||
self.associate_node_to_symbol(owner_node_id, symbol_id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn analyze_compilation_unit(
|
pub fn analyze_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
ctx: &mut AnalysisContext,
|
ctx: &mut AnalysisContext,
|
||||||
@ -233,29 +39,14 @@ pub fn analyze_compilation_unit(
|
|||||||
collect_symbols_compilation_unit(compilation_unit, ctx);
|
collect_symbols_compilation_unit(compilation_unit, ctx);
|
||||||
diagnostics.append(&mut collect_symbols_diagnostics);
|
diagnostics.append(&mut collect_symbols_diagnostics);
|
||||||
|
|
||||||
let NameResolutionResult(mut resolve_names_diagnostics) = resolve_names_in_compilation_unit(
|
let NameResolutionResult(mut resolve_names_diagnostics) =
|
||||||
compilation_unit,
|
resolve_names_in_compilation_unit(compilation_unit, ctx);
|
||||||
&mut ctx.scopes,
|
|
||||||
&mut ctx.symbols,
|
|
||||||
&mut ctx.nodes_to_scopes,
|
|
||||||
&mut ctx.nodes_to_symbols,
|
|
||||||
);
|
|
||||||
diagnostics.append(&mut resolve_names_diagnostics);
|
diagnostics.append(&mut resolve_names_diagnostics);
|
||||||
|
|
||||||
collect_types(
|
collect_types(compilation_unit, ctx);
|
||||||
compilation_unit,
|
|
||||||
&ctx.nodes_to_symbols,
|
|
||||||
&mut ctx.type_infos,
|
|
||||||
&mut ctx.symbols_to_type_infos,
|
|
||||||
);
|
|
||||||
|
|
||||||
let ResolveTypesResult(mut resolve_types_diagnostics) = resolve_types_in_compilation_unit(
|
let ResolveTypesResult(mut resolve_types_diagnostics) =
|
||||||
compilation_unit,
|
resolve_types_in_compilation_unit(compilation_unit, ctx);
|
||||||
&ctx.nodes_to_symbols,
|
|
||||||
&mut ctx.type_infos,
|
|
||||||
&mut ctx.symbols_to_type_infos,
|
|
||||||
&mut ctx.nodes_to_type_infos,
|
|
||||||
);
|
|
||||||
diagnostics.append(&mut resolve_types_diagnostics);
|
diagnostics.append(&mut resolve_types_diagnostics);
|
||||||
|
|
||||||
diagnostics
|
diagnostics
|
||||||
@ -268,24 +59,14 @@ pub fn analyze_statement(statement: &Statement, ctx: &mut AnalysisContext) -> Di
|
|||||||
|
|
||||||
// collect symbols for a statement is currently a no-op, so not needed here
|
// collect symbols for a statement is currently a no-op, so not needed here
|
||||||
|
|
||||||
let NameResolutionResult(mut resolve_names_diagnostics) = resolve_names_in_statement(
|
let NameResolutionResult(mut resolve_names_diagnostics) =
|
||||||
statement,
|
resolve_names_in_statement(statement, ctx);
|
||||||
&mut ctx.scopes,
|
|
||||||
&mut ctx.symbols,
|
|
||||||
&mut ctx.nodes_to_scopes,
|
|
||||||
&mut ctx.nodes_to_symbols,
|
|
||||||
);
|
|
||||||
diagnostics.append(&mut resolve_names_diagnostics);
|
diagnostics.append(&mut resolve_names_diagnostics);
|
||||||
|
|
||||||
// collect types for a statement is currently a no-op, so not needed here
|
// collect types for a statement is currently a no-op, so not needed here
|
||||||
|
|
||||||
let ResolveTypesResult(mut resolve_types_diagnostics) = resolve_types_in_statement(
|
let ResolveTypesResult(mut resolve_types_diagnostics) =
|
||||||
statement,
|
resolve_types_in_statement(statement, ctx);
|
||||||
&ctx.nodes_to_symbols,
|
|
||||||
&mut ctx.type_infos,
|
|
||||||
&mut ctx.symbols_to_type_infos,
|
|
||||||
&mut ctx.nodes_to_type_infos,
|
|
||||||
);
|
|
||||||
diagnostics.append(&mut resolve_types_diagnostics);
|
diagnostics.append(&mut resolve_types_diagnostics);
|
||||||
|
|
||||||
diagnostics
|
diagnostics
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
use crate::ast::NodeId;
|
|
||||||
use crate::ast::assign_statement::AssignStatement;
|
use crate::ast::assign_statement::AssignStatement;
|
||||||
use crate::ast::binary_expression::BinaryExpression;
|
use crate::ast::binary_expression::BinaryExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
@ -13,70 +12,11 @@ use crate::ast::negative_expression::NegativeExpression;
|
|||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::diagnostic::Diagnostics;
|
use crate::diagnostic::Diagnostics;
|
||||||
use crate::diagnostic_factories::symbol_not_found;
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::scope::{Scope, ScopeId};
|
use crate::semantic_analysis::symbol::{Symbol, VariableSymbol};
|
||||||
use crate::semantic_analysis::symbol::{Symbol, SymbolId, VariableSymbol};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct NameResolutionResult(pub Diagnostics);
|
pub struct NameResolutionResult(pub Diagnostics);
|
||||||
|
|
||||||
struct NameResolutionContext<'a> {
|
|
||||||
scopes: &'a mut Vec<Scope>,
|
|
||||||
symbols: &'a mut Vec<Symbol>,
|
|
||||||
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
|
||||||
nodes_to_symbols: &'a mut HashMap<NodeId, SymbolId>,
|
|
||||||
diagnostics: Diagnostics,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> NameResolutionContext<'a> {
|
|
||||||
pub fn new(
|
|
||||||
scopes: &'a mut Vec<Scope>,
|
|
||||||
symbols: &'a mut Vec<Symbol>,
|
|
||||||
nodes_to_scopes: &'a HashMap<NodeId, ScopeId>,
|
|
||||||
nodes_to_symbols: &'a mut HashMap<NodeId, SymbolId>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
scopes,
|
|
||||||
symbols,
|
|
||||||
nodes_to_scopes,
|
|
||||||
nodes_to_symbols,
|
|
||||||
diagnostics: Diagnostics::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scopes(&self) -> &[Scope] {
|
|
||||||
&self.scopes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scopes_mut(&mut self) -> &mut Vec<Scope> {
|
|
||||||
&mut self.scopes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn symbols(&self) -> &[Symbol] {
|
|
||||||
&self.symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn symbols_mut(&mut self) -> &mut Vec<Symbol> {
|
|
||||||
&mut self.symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nodes_to_scopes(&self) -> &HashMap<NodeId, ScopeId> {
|
|
||||||
&self.nodes_to_scopes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> {
|
|
||||||
&self.nodes_to_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nodes_to_symbols_mut(&mut self) -> &mut HashMap<NodeId, SymbolId> {
|
|
||||||
&mut self.nodes_to_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn diagnostics_mut(&mut self) -> &mut Diagnostics {
|
|
||||||
&mut self.diagnostics
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum StatementResolutionPhase {
|
enum StatementResolutionPhase {
|
||||||
Static,
|
Static,
|
||||||
}
|
}
|
||||||
@ -88,112 +28,98 @@ enum ExpressionResolutionPhase {
|
|||||||
|
|
||||||
pub fn resolve_names_in_compilation_unit(
|
pub fn resolve_names_in_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
scopes: &mut Vec<Scope>,
|
ctx: &mut AnalysisContext,
|
||||||
symbols: &mut Vec<Symbol>,
|
|
||||||
nodes_to_scopes: &HashMap<NodeId, ScopeId>,
|
|
||||||
nodes_to_symbols: &mut HashMap<NodeId, SymbolId>,
|
|
||||||
) -> NameResolutionResult {
|
) -> NameResolutionResult {
|
||||||
let mut ctx = NameResolutionContext::new(scopes, symbols, nodes_to_scopes, nodes_to_symbols);
|
let mut diagnostics = Diagnostics::new();
|
||||||
|
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
resolve_names_function(function, &mut ctx);
|
resolve_names_function(function, ctx, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
for extern_function in compilation_unit.extern_functions() {
|
for extern_function in compilation_unit.extern_functions() {
|
||||||
resolve_names_extern_function(extern_function, &mut ctx);
|
resolve_names_extern_function(extern_function, ctx, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
NameResolutionResult(ctx.diagnostics)
|
NameResolutionResult(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_names_in_statement(
|
pub fn resolve_names_in_statement(
|
||||||
statement: &Statement,
|
statement: &Statement,
|
||||||
scopes: &mut Vec<Scope>,
|
ctx: &mut AnalysisContext,
|
||||||
symbols: &mut Vec<Symbol>,
|
|
||||||
nodes_to_scopes: &HashMap<NodeId, ScopeId>,
|
|
||||||
nodes_to_symbols: &mut HashMap<NodeId, SymbolId>,
|
|
||||||
) -> NameResolutionResult {
|
) -> NameResolutionResult {
|
||||||
let mut ctx = NameResolutionContext::new(scopes, symbols, nodes_to_scopes, nodes_to_symbols);
|
let mut diagnostics = Diagnostics::new();
|
||||||
resolve_names_statement(statement, &mut ctx, StatementResolutionPhase::Static);
|
resolve_names_statement(
|
||||||
NameResolutionResult(ctx.diagnostics)
|
statement,
|
||||||
|
ctx,
|
||||||
|
&mut diagnostics,
|
||||||
|
StatementResolutionPhase::Static,
|
||||||
|
);
|
||||||
|
NameResolutionResult(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_function(function: &Function, ctx: &mut NameResolutionContext) {
|
fn resolve_names_function(
|
||||||
|
function: &Function,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) {
|
||||||
for parameter in function.parameters() {
|
for parameter in function.parameters() {
|
||||||
resolve_names_parameter(parameter, ctx);
|
resolve_names_parameter(parameter, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
for statement in function.statements() {
|
for statement in function.statements() {
|
||||||
resolve_names_statement(statement, ctx, StatementResolutionPhase::Static);
|
resolve_names_statement(
|
||||||
|
statement,
|
||||||
|
ctx,
|
||||||
|
diagnostics,
|
||||||
|
StatementResolutionPhase::Static,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// point this function's node_id to the symbol_id for the function symbol
|
// point this function's node_id to the symbol_id for the function symbol
|
||||||
let scope_id = ctx.nodes_to_scopes[&function.node_id()];
|
ctx.associate_node_with_self_symbol(function.node_id(), function.declared_name());
|
||||||
let scope = &ctx.scopes[scope_id];
|
|
||||||
let symbol_id = scope
|
|
||||||
.get_symbol_id(function.declared_name())
|
|
||||||
.expect(&format!(
|
|
||||||
"function's symbol_id could not be found for {}",
|
|
||||||
function.declared_name()
|
|
||||||
));
|
|
||||||
ctx.nodes_to_symbols.insert(function.node_id(), symbol_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_extern_function(
|
fn resolve_names_extern_function(
|
||||||
extern_function: &ExternFunction,
|
extern_function: &ExternFunction,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
) {
|
) {
|
||||||
for parameter in extern_function.parameters() {
|
for parameter in extern_function.parameters() {
|
||||||
resolve_names_parameter(parameter, ctx);
|
resolve_names_parameter(parameter, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// point this extern function's node_id to the symbol_id for this function symbol
|
// point this extern function's node_id to the symbol_id for this function symbol
|
||||||
let scope_id = ctx.nodes_to_scopes[&extern_function.node_id()];
|
ctx.associate_node_with_self_symbol(extern_function.node_id(), extern_function.declared_name());
|
||||||
let scope = &ctx.scopes[scope_id];
|
|
||||||
let symbol_id = scope
|
|
||||||
.get_symbol_id(extern_function.declared_name())
|
|
||||||
.expect(&format!(
|
|
||||||
"extern function's symbol_id could not be found for {}",
|
|
||||||
extern_function.declared_name()
|
|
||||||
));
|
|
||||||
ctx.nodes_to_symbols
|
|
||||||
.insert(extern_function.node_id(), symbol_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_parameter(parameter: &Parameter, ctx: &mut NameResolutionContext) {
|
fn resolve_names_parameter(parameter: &Parameter, ctx: &mut AnalysisContext) {
|
||||||
// point this parameter's node_id to the symbol_id for the parameter symbol
|
// point this parameter's node_id to the symbol_id for this parameter symbol
|
||||||
let scope_id = ctx.nodes_to_scopes[¶meter.node_id()];
|
ctx.associate_node_with_self_symbol(parameter.node_id(), parameter.declared_name());
|
||||||
let scope = &ctx.scopes[scope_id];
|
|
||||||
let symbol_id = scope
|
|
||||||
.get_symbol_id(parameter.declared_name())
|
|
||||||
.expect(&format!(
|
|
||||||
"parameter's symbol_id could not be found for {}",
|
|
||||||
parameter.declared_name()
|
|
||||||
));
|
|
||||||
ctx.nodes_to_symbols.insert(parameter.node_id(), symbol_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_statement(
|
fn resolve_names_statement(
|
||||||
statement: &Statement,
|
statement: &Statement,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
phase: StatementResolutionPhase,
|
phase: StatementResolutionPhase,
|
||||||
) {
|
) {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Let(let_statement) => {
|
Statement::Let(let_statement) => {
|
||||||
resolve_names_let_statement(let_statement, ctx, phase);
|
resolve_names_let_statement(let_statement, ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
resolve_names_expression_statement(expression_statement, ctx);
|
resolve_names_expression_statement(expression_statement, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
Statement::Assign(assign_statement) => {
|
Statement::Assign(assign_statement) => {
|
||||||
resolve_names_assign_statement(assign_statement, ctx);
|
resolve_names_assign_statement(assign_statement, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_let_statement(
|
fn resolve_names_let_statement(
|
||||||
let_statement: &LetStatement,
|
let_statement: &LetStatement,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
phase: StatementResolutionPhase,
|
phase: StatementResolutionPhase,
|
||||||
) {
|
) {
|
||||||
match phase {
|
match phase {
|
||||||
@ -202,72 +128,75 @@ fn resolve_names_let_statement(
|
|||||||
resolve_names_expression(
|
resolve_names_expression(
|
||||||
let_statement.initializer(),
|
let_statement.initializer(),
|
||||||
ctx,
|
ctx,
|
||||||
|
diagnostics,
|
||||||
ExpressionResolutionPhase::Static,
|
ExpressionResolutionPhase::Static,
|
||||||
);
|
);
|
||||||
// now add the declared name to the ctx so later usages can access it
|
// now add the declared name to the ctx so later usages can access it
|
||||||
let scope_id = ctx.nodes_to_scopes()[&let_statement.node_id()];
|
let insert_result = ctx.try_insert_associate_symbol_in_node_scope(
|
||||||
let symbol = Symbol::Variable(VariableSymbol::new(
|
Symbol::Variable(VariableSymbol::new(
|
||||||
let_statement.declared_name_owned(),
|
let_statement.declared_name_owned(),
|
||||||
Some(let_statement.declared_name_source_range()),
|
Some(let_statement.declared_name_source_range()),
|
||||||
let_statement.is_mut(),
|
let_statement.is_mut(),
|
||||||
));
|
)),
|
||||||
// the following could be a method, but this is probably the only place in this phase
|
let_statement.node_id(),
|
||||||
// where we are pushing symbols still
|
);
|
||||||
ctx.symbols_mut().push(symbol);
|
if let Err(diagnostic) = insert_result {
|
||||||
let symbol_id = ctx.symbols().len() - 1;
|
diagnostics.push(diagnostic);
|
||||||
let scope = &mut ctx.scopes_mut()[scope_id];
|
}
|
||||||
scope.insert_symbol(let_statement.declared_name_owned(), symbol_id);
|
|
||||||
// associate the let statement with the symbol id
|
|
||||||
ctx.nodes_to_symbols
|
|
||||||
.insert(let_statement.node_id(), symbol_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_expression_statement(
|
fn resolve_names_expression_statement(
|
||||||
expression_statement: &ExpressionStatement,
|
expression_statement: &ExpressionStatement,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
) {
|
) {
|
||||||
resolve_names_expression(
|
resolve_names_expression(
|
||||||
expression_statement.expression(),
|
expression_statement.expression(),
|
||||||
ctx,
|
ctx,
|
||||||
|
diagnostics,
|
||||||
ExpressionResolutionPhase::Static,
|
ExpressionResolutionPhase::Static,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_assign_statement(
|
fn resolve_names_assign_statement(
|
||||||
assign_statement: &AssignStatement,
|
assign_statement: &AssignStatement,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
) {
|
) {
|
||||||
resolve_names_expression(
|
resolve_names_expression(
|
||||||
assign_statement.value(),
|
assign_statement.value(),
|
||||||
ctx,
|
ctx,
|
||||||
|
diagnostics,
|
||||||
ExpressionResolutionPhase::Static,
|
ExpressionResolutionPhase::Static,
|
||||||
);
|
);
|
||||||
resolve_names_expression(
|
resolve_names_expression(
|
||||||
assign_statement.destination(),
|
assign_statement.destination(),
|
||||||
ctx,
|
ctx,
|
||||||
|
diagnostics,
|
||||||
ExpressionResolutionPhase::Static,
|
ExpressionResolutionPhase::Static,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_expression(
|
fn resolve_names_expression(
|
||||||
expression: &Expression,
|
expression: &Expression,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
phase: ExpressionResolutionPhase,
|
phase: ExpressionResolutionPhase,
|
||||||
) {
|
) {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::Binary(binary_expression) => {
|
Expression::Binary(binary_expression) => {
|
||||||
resolve_names_binary_expression(binary_expression, ctx, phase);
|
resolve_names_binary_expression(binary_expression, ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
Expression::Negative(negative_expression) => {
|
Expression::Negative(negative_expression) => {
|
||||||
resolve_names_negative_expression(negative_expression, ctx, phase);
|
resolve_names_negative_expression(negative_expression, ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
Expression::Call(call) => {
|
Expression::Call(call) => {
|
||||||
resolve_names_call(call, ctx, phase);
|
resolve_names_call(call, ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
resolve_names_identifier(identifier, ctx, phase);
|
resolve_names_identifier(identifier, ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
Expression::Integer(_) => {}
|
Expression::Integer(_) => {}
|
||||||
Expression::Double(_) => {}
|
Expression::Double(_) => {}
|
||||||
@ -277,71 +206,50 @@ fn resolve_names_expression(
|
|||||||
|
|
||||||
fn resolve_names_binary_expression(
|
fn resolve_names_binary_expression(
|
||||||
binary_expression: &BinaryExpression,
|
binary_expression: &BinaryExpression,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
phase: ExpressionResolutionPhase,
|
phase: ExpressionResolutionPhase,
|
||||||
) {
|
) {
|
||||||
resolve_names_expression(binary_expression.lhs(), ctx, phase);
|
resolve_names_expression(binary_expression.lhs(), ctx, diagnostics, phase);
|
||||||
resolve_names_expression(binary_expression.rhs(), ctx, phase);
|
resolve_names_expression(binary_expression.rhs(), ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_negative_expression(
|
fn resolve_names_negative_expression(
|
||||||
negative_expression: &NegativeExpression,
|
negative_expression: &NegativeExpression,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
phase: ExpressionResolutionPhase,
|
phase: ExpressionResolutionPhase,
|
||||||
) {
|
) {
|
||||||
resolve_names_expression(negative_expression.operand(), ctx, phase);
|
resolve_names_expression(negative_expression.operand(), ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_call(
|
fn resolve_names_call(
|
||||||
call: &Call,
|
call: &Call,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
phase: ExpressionResolutionPhase,
|
phase: ExpressionResolutionPhase,
|
||||||
) {
|
) {
|
||||||
for argument in call.arguments() {
|
for argument in call.arguments() {
|
||||||
resolve_names_expression(argument, ctx, phase);
|
resolve_names_expression(argument, ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
resolve_names_expression(call.callee(), ctx, phase);
|
resolve_names_expression(call.callee(), ctx, diagnostics, phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_names_identifier(
|
fn resolve_names_identifier(
|
||||||
identifier: &Identifier,
|
identifier: &Identifier,
|
||||||
ctx: &mut NameResolutionContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
phase: ExpressionResolutionPhase,
|
phase: ExpressionResolutionPhase,
|
||||||
) {
|
) {
|
||||||
match phase {
|
match phase {
|
||||||
ExpressionResolutionPhase::Static => {
|
ExpressionResolutionPhase::Static => {
|
||||||
let scope_id = ctx.nodes_to_scopes()[&identifier.node_id()];
|
let lookup_result = ctx.lookup_and_associate_symbol_to_node(
|
||||||
let mut maybe_scope = Some(&ctx.scopes()[scope_id]);
|
identifier.node_id(),
|
||||||
let mut found_symbol_id: Option<SymbolId> = None;
|
identifier.name(),
|
||||||
while let Some(scope) = maybe_scope {
|
identifier.source_range(),
|
||||||
let maybe_symbol_id = scope.get_symbol_id(identifier.name()); // cloned because ctx cannot be borrowed both immutably and mutably
|
);
|
||||||
match maybe_symbol_id {
|
if let Err(diagnostic) = lookup_result {
|
||||||
None => {
|
diagnostics.push(diagnostic);
|
||||||
maybe_scope = match scope.parent_id() {
|
|
||||||
None => None,
|
|
||||||
Some(parent_id) => Some(&ctx.scopes()[parent_id]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(symbol_id) => {
|
|
||||||
found_symbol_id = Some(symbol_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match found_symbol_id {
|
|
||||||
None => {
|
|
||||||
ctx.diagnostics_mut().push(symbol_not_found(
|
|
||||||
identifier.name(),
|
|
||||||
identifier.source_range(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Some(symbol_id) => {
|
|
||||||
// In the future, we may want to differentiate between different types of
|
|
||||||
// symbols, but for now, let's just assume that we always refer to the
|
|
||||||
// nearest symbol in the ancestor scope chain.
|
|
||||||
ctx.nodes_to_symbols_mut()
|
|
||||||
.insert(identifier.node_id(), symbol_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
mod type_analysis;
|
mod type_analysis;
|
||||||
|
|
||||||
use crate::ast::NodeId;
|
|
||||||
use crate::ast::assign_statement::AssignStatement;
|
use crate::ast::assign_statement::AssignStatement;
|
||||||
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
|
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
@ -14,138 +13,101 @@ use crate::ast::parameter::Parameter;
|
|||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::diagnostic::{Diagnostic, Diagnostics};
|
use crate::diagnostic::{Diagnostic, Diagnostics};
|
||||||
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
|
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
|
||||||
|
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use crate::semantic_analysis::resolve_types::type_analysis::{
|
use crate::semantic_analysis::resolve_types::type_analysis::{
|
||||||
are_binary_op_compatible, binary_op_result, can_assign_right_to_left, can_negate, negate_result,
|
are_binary_op_compatible, binary_op_result, can_assign_right_to_left, can_negate, negate_result,
|
||||||
};
|
};
|
||||||
use crate::semantic_analysis::symbol::SymbolId;
|
use crate::semantic_analysis::type_info::TypeInfo;
|
||||||
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct ResolveTypesResult(pub Diagnostics);
|
pub struct ResolveTypesResult(pub Diagnostics);
|
||||||
|
|
||||||
struct ResolveTypesContext<'a> {
|
|
||||||
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
|
||||||
type_infos: &'a mut Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
|
||||||
nodes_to_type_infos: &'a mut HashMap<NodeId, TypeInfoId>,
|
|
||||||
diagnostics: Diagnostics,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ResolveTypesContext<'a> {
|
|
||||||
pub fn new(
|
|
||||||
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
|
|
||||||
type_infos: &'a mut Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: &'a mut HashMap<SymbolId, TypeInfoId>,
|
|
||||||
nodes_to_type_infos: &'a mut HashMap<NodeId, TypeInfoId>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
nodes_to_symbols,
|
|
||||||
type_infos,
|
|
||||||
symbols_to_type_infos,
|
|
||||||
nodes_to_type_infos,
|
|
||||||
diagnostics: Diagnostics::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_types_in_compilation_unit(
|
pub fn resolve_types_in_compilation_unit(
|
||||||
compilation_unit: &CompilationUnit,
|
compilation_unit: &CompilationUnit,
|
||||||
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
ctx: &mut AnalysisContext,
|
||||||
type_infos: &mut Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: &mut HashMap<SymbolId, TypeInfoId>,
|
|
||||||
nodes_to_type_infos: &mut HashMap<NodeId, TypeInfoId>,
|
|
||||||
) -> ResolveTypesResult {
|
) -> ResolveTypesResult {
|
||||||
let mut ctx = ResolveTypesContext::new(
|
let mut diagnostics = Diagnostics::new();
|
||||||
nodes_to_symbols,
|
|
||||||
type_infos,
|
|
||||||
symbols_to_type_infos,
|
|
||||||
nodes_to_type_infos,
|
|
||||||
);
|
|
||||||
|
|
||||||
for function in compilation_unit.functions() {
|
for function in compilation_unit.functions() {
|
||||||
resolve_types_function(function, &mut ctx);
|
resolve_types_function(function, ctx, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolveTypesResult(ctx.diagnostics)
|
ResolveTypesResult(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_types_in_statement(
|
pub fn resolve_types_in_statement(
|
||||||
statement: &Statement,
|
statement: &Statement,
|
||||||
nodes_to_symbols: &HashMap<NodeId, SymbolId>,
|
ctx: &mut AnalysisContext,
|
||||||
type_infos: &mut Vec<TypeInfo>,
|
|
||||||
symbols_to_type_infos: &mut HashMap<SymbolId, TypeInfoId>,
|
|
||||||
nodes_to_type_infos: &mut HashMap<NodeId, TypeInfoId>,
|
|
||||||
) -> ResolveTypesResult {
|
) -> ResolveTypesResult {
|
||||||
let mut ctx = ResolveTypesContext::new(
|
let mut diagnostics = Diagnostics::new();
|
||||||
nodes_to_symbols,
|
resolve_types_statement(statement, ctx, &mut diagnostics);
|
||||||
type_infos,
|
ResolveTypesResult(diagnostics)
|
||||||
symbols_to_type_infos,
|
|
||||||
nodes_to_type_infos,
|
|
||||||
);
|
|
||||||
resolve_types_statement(statement, &mut ctx);
|
|
||||||
ResolveTypesResult(ctx.diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_function(function: &Function, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_function(
|
||||||
|
function: &Function,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) {
|
||||||
for parameter in function.parameters() {
|
for parameter in function.parameters() {
|
||||||
resolve_types_parameter(parameter, ctx);
|
resolve_types_parameter(parameter, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
for statement in function.statements() {
|
for statement in function.statements() {
|
||||||
resolve_types_statement(statement, ctx);
|
resolve_types_statement(statement, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_parameter(parameter: &Parameter, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_parameter(
|
||||||
// point the parameter's node_id to the associated type_info
|
_parameter: &Parameter,
|
||||||
let symbol_id = ctx.nodes_to_symbols[¶meter.node_id()];
|
_ctx: &mut AnalysisContext,
|
||||||
let type_info_id = ctx.symbols_to_type_infos[&symbol_id];
|
_diagnostics: &mut Diagnostics,
|
||||||
ctx.nodes_to_type_infos
|
) {
|
||||||
.insert(parameter.node_id(), type_info_id);
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_statement(statement: &Statement, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_statement(
|
||||||
|
statement: &Statement,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Let(let_statement) => {
|
Statement::Let(let_statement) => {
|
||||||
resolve_types_let_statement(let_statement, ctx);
|
resolve_types_let_statement(let_statement, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
resolve_types_expression(expression_statement.expression(), ctx);
|
resolve_types_expression(expression_statement.expression(), ctx, diagnostics);
|
||||||
}
|
}
|
||||||
Statement::Assign(assign_statement) => {
|
Statement::Assign(assign_statement) => {
|
||||||
resolve_types_assign_statement(assign_statement, ctx);
|
resolve_types_assign_statement(assign_statement, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_let_statement(let_statement: &LetStatement, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_let_statement(
|
||||||
resolve_types_expression(let_statement.initializer(), ctx);
|
let_statement: &LetStatement,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) {
|
||||||
|
resolve_types_expression(let_statement.initializer(), ctx, diagnostics);
|
||||||
|
|
||||||
let initializer_type_info_id = ctx.nodes_to_type_infos[&let_statement.initializer().node_id()];
|
let initializer_type_info_id =
|
||||||
|
ctx.get_type_info_id_for_node(let_statement.initializer().node_id());
|
||||||
// update symbol's type
|
// "bubble up" to let statement and symbol
|
||||||
let symbol_id = ctx.nodes_to_symbols[&let_statement.node_id()];
|
ctx.associate_node_and_symbol_to_type(let_statement.node_id(), initializer_type_info_id);
|
||||||
ctx.symbols_to_type_infos
|
|
||||||
.insert(symbol_id, initializer_type_info_id);
|
|
||||||
// also save it as the let statement's type info
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(let_statement.node_id(), initializer_type_info_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_assign_statement(
|
fn resolve_types_assign_statement(
|
||||||
assign_statement: &AssignStatement,
|
assign_statement: &AssignStatement,
|
||||||
ctx: &mut ResolveTypesContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
) {
|
) {
|
||||||
resolve_types_expression(assign_statement.value(), ctx);
|
resolve_types_expression(assign_statement.value(), ctx, diagnostics);
|
||||||
resolve_types_expression(assign_statement.destination(), ctx);
|
resolve_types_expression(assign_statement.destination(), ctx, diagnostics);
|
||||||
|
|
||||||
// check assignability
|
// check assignability
|
||||||
let value_type_info_id = ctx.nodes_to_type_infos[&assign_statement.value().node_id()];
|
let value_type_info = ctx.get_type_info_for_node(assign_statement.value().node_id());
|
||||||
let value_type_info = &ctx.type_infos[value_type_info_id];
|
let destination_type_info =
|
||||||
|
ctx.get_type_info_for_node(assign_statement.destination().node_id());
|
||||||
let destination_type_info_id =
|
|
||||||
ctx.nodes_to_type_infos[&assign_statement.destination().node_id()];
|
|
||||||
let destination_type_info = &ctx.type_infos[destination_type_info_id];
|
|
||||||
|
|
||||||
if !can_assign_right_to_left(destination_type_info, value_type_info) {
|
if !can_assign_right_to_left(destination_type_info, value_type_info) {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
@ -157,66 +119,55 @@ fn resolve_types_assign_statement(
|
|||||||
assign_statement.destination().source_range().start(),
|
assign_statement.destination().source_range().start(),
|
||||||
assign_statement.destination().source_range().end(),
|
assign_statement.destination().source_range().end(),
|
||||||
);
|
);
|
||||||
ctx.diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_expression(expression: &Expression, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_expression(
|
||||||
|
expression: &Expression,
|
||||||
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
|
) {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::Binary(binary_expression) => {
|
Expression::Binary(binary_expression) => {
|
||||||
resolve_types_binary_expression(binary_expression, ctx);
|
resolve_types_binary_expression(binary_expression, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
Expression::Negative(negative_expression) => {
|
Expression::Negative(negative_expression) => {
|
||||||
resolve_types_negative_expression(negative_expression, ctx);
|
resolve_types_negative_expression(negative_expression, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
Expression::Call(call) => {
|
Expression::Call(call) => {
|
||||||
resolve_types_call(call, ctx);
|
resolve_types_call(call, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
resolve_types_identifier(identifier, ctx);
|
resolve_types_identifier(identifier, ctx);
|
||||||
}
|
}
|
||||||
Expression::Integer(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
// yes, this is slightly wasteful now, but keeping it simple for mental model.
|
ctx.insert_type_info_for_node(TypeInfo::Int, integer_literal.node_id());
|
||||||
ctx.type_infos.push(TypeInfo::Int);
|
|
||||||
let int_literal_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(integer_literal.node_id(), int_literal_type_info_id);
|
|
||||||
}
|
}
|
||||||
Expression::Double(double_literal) => {
|
Expression::Double(double_literal) => {
|
||||||
ctx.type_infos.push(TypeInfo::Double);
|
ctx.insert_type_info_for_node(TypeInfo::Double, double_literal.node_id());
|
||||||
let double_literal_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(double_literal.node_id(), double_literal_type_info_id);
|
|
||||||
}
|
}
|
||||||
Expression::String(string_literal) => {
|
Expression::String(string_literal) => {
|
||||||
ctx.type_infos.push(TypeInfo::String);
|
ctx.insert_type_info_for_node(TypeInfo::String, string_literal.node_id());
|
||||||
let string_literal_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(string_literal.node_id(), string_literal_type_info_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_binary_expression(
|
fn resolve_types_binary_expression(
|
||||||
binary_expression: &BinaryExpression,
|
binary_expression: &BinaryExpression,
|
||||||
ctx: &mut ResolveTypesContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
) {
|
) {
|
||||||
resolve_types_expression(binary_expression.lhs(), ctx);
|
resolve_types_expression(binary_expression.lhs(), ctx, diagnostics);
|
||||||
resolve_types_expression(binary_expression.rhs(), ctx);
|
resolve_types_expression(binary_expression.rhs(), ctx, diagnostics);
|
||||||
|
|
||||||
let lhs_type_info_id = ctx.nodes_to_type_infos[&binary_expression.lhs().node_id()];
|
let lhs_type_info = ctx.get_type_info_for_node(binary_expression.lhs().node_id());
|
||||||
let lhs_type_info = &ctx.type_infos[lhs_type_info_id];
|
let rhs_type_info = ctx.get_type_info_for_node(binary_expression.rhs().node_id());
|
||||||
|
|
||||||
let rhs_type_info_id = ctx.nodes_to_type_infos[&binary_expression.rhs().node_id()];
|
|
||||||
let rhs_type_info = &ctx.type_infos[rhs_type_info_id];
|
|
||||||
|
|
||||||
if are_binary_op_compatible(binary_expression.op(), lhs_type_info, rhs_type_info) {
|
if are_binary_op_compatible(binary_expression.op(), lhs_type_info, rhs_type_info) {
|
||||||
let result_type_info =
|
let result_type_info =
|
||||||
binary_op_result(binary_expression.op(), lhs_type_info, rhs_type_info);
|
binary_op_result(binary_expression.op(), lhs_type_info, rhs_type_info);
|
||||||
ctx.type_infos.push(result_type_info);
|
ctx.insert_type_info_for_node(result_type_info, binary_expression.node_id());
|
||||||
let result_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(binary_expression.node_id(), result_type_info_id);
|
|
||||||
} else {
|
} else {
|
||||||
let op_name = match binary_expression.op() {
|
let op_name = match binary_expression.op() {
|
||||||
BinaryOperation::Multiply => "multiply",
|
BinaryOperation::Multiply => "multiply",
|
||||||
@ -240,31 +191,25 @@ fn resolve_types_binary_expression(
|
|||||||
binary_expression.source_range().end(),
|
binary_expression.source_range().end(),
|
||||||
)
|
)
|
||||||
.with_error_code(BINARY_INCOMPATIBLE_TYPES);
|
.with_error_code(BINARY_INCOMPATIBLE_TYPES);
|
||||||
ctx.diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|
||||||
// push error type so it bubbles up
|
// push error type so it bubbles up
|
||||||
ctx.type_infos.push(TypeInfo::__Error);
|
ctx.insert_type_info_for_node(TypeInfo::__Error, binary_expression.node_id());
|
||||||
let result_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(binary_expression.node_id(), result_type_info_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_negative_expression(
|
fn resolve_types_negative_expression(
|
||||||
negative_expression: &NegativeExpression,
|
negative_expression: &NegativeExpression,
|
||||||
ctx: &mut ResolveTypesContext,
|
ctx: &mut AnalysisContext,
|
||||||
|
diagnostics: &mut Diagnostics,
|
||||||
) {
|
) {
|
||||||
resolve_types_expression(negative_expression.operand(), ctx);
|
resolve_types_expression(negative_expression.operand(), ctx, diagnostics);
|
||||||
|
|
||||||
let operand_type_info_id = ctx.nodes_to_type_infos[&negative_expression.operand().node_id()];
|
let operand_type_info = ctx.get_type_info_for_node(negative_expression.operand().node_id());
|
||||||
let operand_type_info = &ctx.type_infos[operand_type_info_id];
|
|
||||||
|
|
||||||
if can_negate(operand_type_info) {
|
if can_negate(operand_type_info) {
|
||||||
let result_type_info = negate_result(operand_type_info);
|
let result_type_info = negate_result(operand_type_info);
|
||||||
ctx.type_infos.push(result_type_info);
|
ctx.insert_type_info_for_node(result_type_info, negative_expression.node_id());
|
||||||
let result_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(negative_expression.node_id(), result_type_info_id);
|
|
||||||
} else {
|
} else {
|
||||||
let message = format!("Incompatible type: cannot negate {}", operand_type_info);
|
let message = format!("Incompatible type: cannot negate {}", operand_type_info);
|
||||||
let diagnostic = Diagnostic::new(
|
let diagnostic = Diagnostic::new(
|
||||||
@ -272,26 +217,22 @@ fn resolve_types_negative_expression(
|
|||||||
negative_expression.source_range().start(),
|
negative_expression.source_range().start(),
|
||||||
negative_expression.source_range().end(),
|
negative_expression.source_range().end(),
|
||||||
);
|
);
|
||||||
ctx.diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|
||||||
// bubble up error type
|
// bubble up error type
|
||||||
ctx.type_infos.push(TypeInfo::__Error);
|
ctx.insert_type_info_for_node(TypeInfo::__Error, negative_expression.node_id());
|
||||||
let result_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(negative_expression.node_id(), result_type_info_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_call(call: &Call, ctx: &mut AnalysisContext, diagnostics: &mut Diagnostics) {
|
||||||
resolve_types_expression(call.callee(), ctx);
|
resolve_types_expression(call.callee(), ctx, diagnostics);
|
||||||
|
|
||||||
// get types of arguments
|
// get types of arguments
|
||||||
for argument in call.arguments() {
|
for argument in call.arguments() {
|
||||||
resolve_types_expression(argument, ctx);
|
resolve_types_expression(argument, ctx, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
let callee_type_info_id = ctx.nodes_to_type_infos[&call.callee().node_id()];
|
let callee_type_info = ctx.get_type_info_for_node(call.callee().node_id());
|
||||||
let callee_type_info = &ctx.type_infos[callee_type_info_id];
|
|
||||||
|
|
||||||
match callee_type_info {
|
match callee_type_info {
|
||||||
TypeInfo::Function(function_type_info) => {
|
TypeInfo::Function(function_type_info) => {
|
||||||
@ -308,7 +249,7 @@ fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
|||||||
call.source_range().start(),
|
call.source_range().start(),
|
||||||
call.source_range().end(),
|
call.source_range().end(),
|
||||||
);
|
);
|
||||||
ctx.diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|
||||||
// do not push an error type because the result of the whole call is the return type
|
// do not push an error type because the result of the whole call is the return type
|
||||||
// of the function
|
// of the function
|
||||||
@ -317,9 +258,8 @@ fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
|||||||
// check argument types
|
// check argument types
|
||||||
let parameter_type_ids = function_type_info.parameter_type_ids();
|
let parameter_type_ids = function_type_info.parameter_type_ids();
|
||||||
for i in 0..parameter_type_ids.len() {
|
for i in 0..parameter_type_ids.len() {
|
||||||
let argument_type_info_id = ctx.nodes_to_type_infos[&arguments[i].node_id()];
|
let argument_type_info = ctx.get_type_info_for_node(arguments[i].node_id());
|
||||||
let argument_type_info = &ctx.type_infos[argument_type_info_id];
|
let parameter_type_info = ctx.get_type_info_by_id(parameter_type_ids[i]); // n.b. different method
|
||||||
let parameter_type_info = &ctx.type_infos[parameter_type_ids[i]];
|
|
||||||
if !can_assign_right_to_left(parameter_type_info, argument_type_info) {
|
if !can_assign_right_to_left(parameter_type_info, argument_type_info) {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"Incompatible types: cannot assign {} to {}",
|
"Incompatible types: cannot assign {} to {}",
|
||||||
@ -330,7 +270,7 @@ fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
|||||||
arguments[i].source_range().start(),
|
arguments[i].source_range().start(),
|
||||||
arguments[i].source_range().end(),
|
arguments[i].source_range().end(),
|
||||||
);
|
);
|
||||||
ctx.diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|
||||||
// do not push an error type because the result of the whole call is the return type
|
// do not push an error type because the result of the whole call is the return type
|
||||||
// of the function
|
// of the function
|
||||||
@ -339,15 +279,11 @@ fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
|||||||
|
|
||||||
// set return type as type of call expression
|
// set return type as type of call expression
|
||||||
let return_type_info_id = function_type_info.return_type_id();
|
let return_type_info_id = function_type_info.return_type_id();
|
||||||
ctx.nodes_to_type_infos
|
ctx.associate_node_to_type(call.node_id(), return_type_info_id);
|
||||||
.insert(call.node_id(), return_type_info_id);
|
|
||||||
}
|
}
|
||||||
TypeInfo::__Error => {
|
TypeInfo::__Error => {
|
||||||
// bubble it up
|
// bubble it up
|
||||||
ctx.type_infos.push(TypeInfo::__Error);
|
ctx.insert_type_info_for_node(TypeInfo::__Error, call.node_id());
|
||||||
let error_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(call.node_id(), error_type_info_id);
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let message = format!("Incompatible type: cannot call type {}", callee_type_info);
|
let message = format!("Incompatible type: cannot call type {}", callee_type_info);
|
||||||
@ -356,21 +292,15 @@ fn resolve_types_call(call: &Call, ctx: &mut ResolveTypesContext) {
|
|||||||
call.callee().source_range().start(),
|
call.callee().source_range().start(),
|
||||||
call.callee().source_range().end(),
|
call.callee().source_range().end(),
|
||||||
);
|
);
|
||||||
ctx.diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|
||||||
// bubble up error type
|
// bubble up error type
|
||||||
ctx.type_infos.push(TypeInfo::__Error);
|
ctx.insert_type_info_for_node(TypeInfo::__Error, call.node_id());
|
||||||
let error_type_info_id = ctx.type_infos.len() - 1;
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(call.node_id(), error_type_info_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_types_identifier(identifier: &Identifier, ctx: &mut ResolveTypesContext) {
|
fn resolve_types_identifier(identifier: &Identifier, ctx: &mut AnalysisContext) {
|
||||||
let symbol_id = ctx.nodes_to_symbols[&identifier.node_id()];
|
let type_info_id = ctx.lookup_type_for_node_via_symbol(identifier.node_id());
|
||||||
let symbol_type_info_id = ctx.symbols_to_type_infos[&symbol_id];
|
ctx.associate_node_to_type(identifier.node_id(), type_info_id);
|
||||||
// bubble up
|
|
||||||
ctx.nodes_to_type_infos
|
|
||||||
.insert(identifier.node_id(), symbol_type_info_id);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ mod e2e_tests {
|
|||||||
use dmc_lib::compile_compilation_unit;
|
use dmc_lib::compile_compilation_unit;
|
||||||
use dmc_lib::constants_table::ConstantsTable;
|
use dmc_lib::constants_table::ConstantsTable;
|
||||||
use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
|
use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
|
||||||
use dmc_lib::semantic_analysis::AnalysisContext;
|
use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::value::Value;
|
use dvm_lib::vm::value::Value;
|
||||||
use dvm_lib::vm::{DvmContext, call};
|
use dvm_lib::vm::{DvmContext, call};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user