New type analysis WIP.
This commit is contained in:
parent
d07135b3c6
commit
21fa082b44
@ -10,7 +10,7 @@ pub fn get_name_for_type<'ctx>(type_info: &TypeInfo, ctx: &'ctx AnalysisContext)
|
||||
TypeInfo::Constructor(_constructor_type_info) => {
|
||||
todo!()
|
||||
}
|
||||
TypeInfo::TypeConstructor(type_constructor_info) => {
|
||||
TypeInfo::Class(type_constructor_info) => {
|
||||
let class_symbol = &ctx.symbols()[type_constructor_info.class_symbol_id()];
|
||||
class_symbol.declared_name()
|
||||
}
|
||||
|
||||
@ -6,12 +6,13 @@ 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::semantic_analysis::type_info::{ClassTypeInfo, TypeInfo, TypeInfoId};
|
||||
use crate::source_range::SourceRange;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct AnalysisContext {
|
||||
#[derive(Debug, Clone)]
|
||||
struct AnalysisState {
|
||||
fqn_stack: Vec<Rc<str>>,
|
||||
scopes: Vec<Scope>,
|
||||
current_scope_id: Option<ScopeId>,
|
||||
@ -23,8 +24,8 @@ pub struct AnalysisContext {
|
||||
nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
|
||||
}
|
||||
|
||||
impl AnalysisContext {
|
||||
pub fn new() -> Self {
|
||||
impl Default for AnalysisState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
fqn_stack: Vec::new(),
|
||||
scopes: Vec::new(),
|
||||
@ -37,101 +38,129 @@ impl AnalysisContext {
|
||||
nodes_to_type_infos: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnalysisContext {
|
||||
state: Box<AnalysisState>,
|
||||
previous_state: Option<Box<AnalysisState>>,
|
||||
}
|
||||
|
||||
impl AnalysisContext {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: AnalysisState::default().into(),
|
||||
previous_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit(&mut self) {
|
||||
todo!()
|
||||
self.previous_state = Some(self.state.clone());
|
||||
}
|
||||
|
||||
pub fn rollback(&mut self) {
|
||||
todo!()
|
||||
self.state = self.previous_state.take().unwrap_or_default();
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn symbols(&self) -> &[Symbol] {
|
||||
&self.symbols
|
||||
&self.state.symbols
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> {
|
||||
&self.nodes_to_symbols
|
||||
&self.state.nodes_to_symbols
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn type_infos(&self) -> &[TypeInfo] {
|
||||
&self.type_infos
|
||||
&self.state.type_infos
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn symbols_to_type_infos(&self) -> &HashMap<SymbolId, TypeInfoId> {
|
||||
&self.symbols_to_type_infos
|
||||
&self.state.symbols_to_type_infos
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn nodes_to_type_infos(&self) -> &HashMap<NodeId, TypeInfoId> {
|
||||
&self.nodes_to_type_infos
|
||||
&self.state.nodes_to_type_infos
|
||||
}
|
||||
|
||||
pub fn push_fqn_part(&mut self, part: Rc<str>) {
|
||||
self.fqn_stack.push(part);
|
||||
self.state.fqn_stack.push(part);
|
||||
}
|
||||
|
||||
pub fn pop_fqn_part(&mut self) {
|
||||
self.fqn_stack.pop();
|
||||
self.state.fqn_stack.pop();
|
||||
}
|
||||
|
||||
pub fn resolve_fqn(&self, suffix: &str) -> String {
|
||||
let mut fqn = self.fqn_stack.clone();
|
||||
let mut fqn = self.state.fqn_stack.clone();
|
||||
fqn.push(suffix.into());
|
||||
fqn.join("::")
|
||||
}
|
||||
|
||||
pub fn push_scope(&mut self, _debug_name: &str) -> ScopeId {
|
||||
let scope = Scope::new(self.current_scope_id);
|
||||
self.scopes.push(scope);
|
||||
self.current_scope_id = Some(self.scopes.len() - 1);
|
||||
self.current_scope_id.unwrap()
|
||||
}
|
||||
|
||||
fn get_scope(&self, scope_id: ScopeId) -> &Scope {
|
||||
self.scopes.get(scope_id).expect(&format!(
|
||||
self.state.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!(
|
||||
self.state.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"))
|
||||
/// Pushes a new `Scope` on top of the scope stack, returning the `ScopeId` for the newly pushed
|
||||
/// scope.
|
||||
pub fn push_scope(&mut self, _debug_name: &str) -> ScopeId {
|
||||
let scope = Scope::new(self.state.current_scope_id);
|
||||
self.state.scopes.push(scope);
|
||||
self.state.current_scope_id = Some(self.state.scopes.len() - 1);
|
||||
self.state.current_scope_id.unwrap()
|
||||
}
|
||||
|
||||
pub fn pop_scope(&mut self) {
|
||||
self.current_scope_id = self.get_current_scope().parent_id();
|
||||
self.state.current_scope_id = self
|
||||
.state
|
||||
.current_scope_id
|
||||
.and_then(|current_scope_id| self.state.scopes.get(current_scope_id))
|
||||
.and_then(|current_scope| current_scope.parent_id())
|
||||
}
|
||||
|
||||
/// Designates the given `node_id` as belonging to the current scope.
|
||||
pub fn associate_node_to_current_scope(&mut self, node_id: NodeId) {
|
||||
self.nodes_to_scopes.insert(
|
||||
self.state.nodes_to_scopes.insert(
|
||||
node_id,
|
||||
self.current_scope_id.expect("current_scope_id is None"),
|
||||
self.state
|
||||
.current_scope_id
|
||||
.expect("current_scope_id is None"),
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts the given symbol into the Scope corresponding to the given ScopeId. **This is a low
|
||||
/// level operation and alternate methods should be preferred.**
|
||||
/// Inserts the given symbol into the Scope corresponding to the given ScopeId.
|
||||
///
|
||||
/// Danger: If a symbol already exists in the corresponding Scope with the same declared name,
|
||||
/// it will be overwritten, leading to dangling symbols/symbol ids.
|
||||
/// ## Panics
|
||||
/// - If the scope identified by `scope_id` already contains a symbol with the `declared_name`
|
||||
/// obtained from the given `Symbol`.
|
||||
fn insert_symbol_in_scope(&mut self, scope_id: ScopeId, symbol: Symbol) -> SymbolId {
|
||||
// get declared name
|
||||
let declared_name = symbol.declared_name_owned();
|
||||
|
||||
if self.get_scope(scope_id).has_symbol(symbol.declared_name()) {
|
||||
panic!(
|
||||
"Symbol with declared_name {} already exists in scope_id {}",
|
||||
symbol.declared_name(),
|
||||
scope_id
|
||||
);
|
||||
}
|
||||
|
||||
// push the symbol
|
||||
self.symbols.push(symbol);
|
||||
let symbol_id = self.symbols.len() - 1;
|
||||
self.state.symbols.push(symbol);
|
||||
let symbol_id = self.state.symbols.len() - 1;
|
||||
|
||||
// put it in scope
|
||||
self.get_scope_mut(scope_id)
|
||||
@ -140,28 +169,46 @@ impl AnalysisContext {
|
||||
symbol_id
|
||||
}
|
||||
|
||||
/// Sets the symbol identified by `symbol_id` for the node identified by `node_id`.
|
||||
pub fn associate_node_to_symbol(&mut self, node_id: NodeId, symbol_id: SymbolId) {
|
||||
self.nodes_to_symbols.insert(node_id, symbol_id);
|
||||
self.state.nodes_to_symbols.insert(node_id, symbol_id);
|
||||
}
|
||||
|
||||
fn get_symbol_in_scope(&self, scope: &Scope, declared_name: &str) -> Option<&Symbol> {
|
||||
/// Finds a symbol with a matching name to `declared_name` in the provided `Scope`. Returns an
|
||||
/// `Option` maybe containing a reference to that `Symbol`.
|
||||
///
|
||||
/// ## Panics
|
||||
/// - If the `symbol_id` for the matching `Symbol` is not a valid index of `self.state.symbols`.
|
||||
fn find_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!(
|
||||
self.state.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`.
|
||||
/// Inserts the given `Symbol` into the scope identified by `scope_id`.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
|
||||
/// use dmc_lib::semantic_analysis::symbol::{Symbol, VariableSymbol};
|
||||
///
|
||||
/// let mut analysis_context = AnalysisContext::new();
|
||||
/// let scope_id = analysis_context.push_scope("some scope");
|
||||
/// let symbol = Symbol::Variable(VariableSymbol::new("my_variable".into(), None, false));
|
||||
/// let result = analysis_context.try_insert_symbol_in_scope(symbol, scope_id);
|
||||
/// assert!(matches!(result, Ok(_)));
|
||||
/// ```
|
||||
pub fn try_insert_symbol_in_scope(
|
||||
&mut self,
|
||||
to_insert: Symbol,
|
||||
scope_id: ScopeId,
|
||||
) -> Result<SymbolId, Diagnostic> {
|
||||
let scope = self.get_scope(scope_id);
|
||||
if let Some(already_declared) = self.get_symbol_in_scope(scope, to_insert.declared_name()) {
|
||||
if let Some(already_declared) = self.find_symbol_in_scope(scope, to_insert.declared_name())
|
||||
{
|
||||
Err(symbol_already_declared(already_declared, &to_insert))
|
||||
} else {
|
||||
let symbol_id = self.insert_symbol_in_scope(scope_id, to_insert);
|
||||
@ -170,18 +217,39 @@ impl AnalysisContext {
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts the given symbol into the scope belonging to the given node_id, and sets the node's
|
||||
/// associated symbol id to the resultant symbol id. Returns `Ok(SymbolId)` if the insert was
|
||||
/// successful, else `Err(Diagnostic)`.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
|
||||
/// use dmc_lib::semantic_analysis::symbol::{Symbol, VariableSymbol};
|
||||
///
|
||||
/// let mut analysis_context = AnalysisContext::new();
|
||||
/// analysis_context.push_scope("some scope");
|
||||
/// let node_id = 0;
|
||||
/// analysis_context.associate_node_to_current_scope(node_id);
|
||||
/// let symbol = Symbol::Variable(VariableSymbol::new("my_variable".into(), None, false));
|
||||
/// let result = analysis_context.try_insert_associate_symbol_in_node_scope(symbol, node_id);
|
||||
/// assert!(matches!(result, Ok(_)));
|
||||
/// ```
|
||||
pub fn try_insert_associate_symbol_in_node_scope(
|
||||
&mut self,
|
||||
to_insert: Symbol,
|
||||
owner_node_id: NodeId,
|
||||
) -> Result<SymbolId, 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",
|
||||
let node_scope_id = self
|
||||
.state
|
||||
.nodes_to_scopes
|
||||
.get(&owner_node_id)
|
||||
.expect(&format!(
|
||||
"owner_node_id {} is not in self.state.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())
|
||||
self.find_symbol_in_scope(node_scope, to_insert.declared_name())
|
||||
{
|
||||
Err(symbol_already_declared(already_declared, &to_insert))
|
||||
} else {
|
||||
@ -191,12 +259,15 @@ impl AnalysisContext {
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the `SymbolId` of the node with the declared name in the containing scope of the node
|
||||
/// with the given `NodeId`.
|
||||
fn get_symbol_id_by_declared_name_in_node_scope(
|
||||
&self,
|
||||
node_id: NodeId,
|
||||
declared_name: &str,
|
||||
) -> Option<SymbolId> {
|
||||
let scope_id = self
|
||||
.state
|
||||
.nodes_to_scopes
|
||||
.get(&node_id)
|
||||
.expect(&format!("node_id {} has no associated scope", node_id));
|
||||
@ -204,6 +275,8 @@ impl AnalysisContext {
|
||||
scope.get_symbol_id(declared_name)
|
||||
}
|
||||
|
||||
/// Finds the symbol for the node with the given node id and declared name and sets the node's
|
||||
/// symbol to that result.
|
||||
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)
|
||||
@ -221,6 +294,7 @@ impl AnalysisContext {
|
||||
node_source_range: &SourceRange,
|
||||
) -> Result<(), Diagnostic> {
|
||||
let scope_id = self
|
||||
.state
|
||||
.nodes_to_scopes
|
||||
.get(&node_id)
|
||||
.expect(&format!("node_id {} has no associated scope", node_id));
|
||||
@ -250,37 +324,43 @@ impl AnalysisContext {
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn insert_type_info(&mut self, type_info: TypeInfo) -> TypeInfoId {
|
||||
self.type_infos.push(type_info);
|
||||
self.type_infos.len() - 1
|
||||
self.state.type_infos.push(type_info);
|
||||
self.state.type_infos.len() - 1
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn insert_type_info_for_node(
|
||||
&mut self,
|
||||
type_info: TypeInfo,
|
||||
node_id: NodeId,
|
||||
) -> TypeInfoId {
|
||||
self.type_infos.push(type_info);
|
||||
let type_info_id = self.type_infos.len() - 1;
|
||||
self.nodes_to_type_infos.insert(node_id, type_info_id);
|
||||
self.state.type_infos.push(type_info);
|
||||
let type_info_id = self.state.type_infos.len() - 1;
|
||||
self.state.nodes_to_type_infos.insert(node_id, type_info_id);
|
||||
type_info_id
|
||||
}
|
||||
|
||||
pub fn associate_symbol_to_type(&mut self, symbol_id: SymbolId, type_info_id: TypeInfoId) {
|
||||
self.symbols_to_type_infos.insert(symbol_id, type_info_id);
|
||||
self.state
|
||||
.symbols_to_type_infos
|
||||
.insert(symbol_id, type_info_id);
|
||||
}
|
||||
|
||||
pub fn associate_node_and_symbol_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) {
|
||||
let symbol_id = self
|
||||
.state
|
||||
.nodes_to_symbols
|
||||
.get(&node_id)
|
||||
.expect(&format!("node_id {} has no associated symbol", node_id));
|
||||
self.associate_symbol_to_type(*symbol_id, type_info_id);
|
||||
self.nodes_to_type_infos.insert(node_id, type_info_id);
|
||||
self.state.nodes_to_type_infos.insert(node_id, type_info_id);
|
||||
}
|
||||
|
||||
pub fn get_type_info_id_for_node(&self, node_id: NodeId) -> TypeInfoId {
|
||||
*self
|
||||
.state
|
||||
.nodes_to_type_infos
|
||||
.get(&node_id)
|
||||
.expect(&format!("node_id {} has no associated type", node_id))
|
||||
@ -288,27 +368,34 @@ impl AnalysisContext {
|
||||
|
||||
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
|
||||
self.state
|
||||
.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
|
||||
self.state
|
||||
.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);
|
||||
self.state.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
|
||||
.state
|
||||
.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!(
|
||||
let symbol_type_info_id = self
|
||||
.state
|
||||
.symbols_to_type_infos
|
||||
.get(symbol_id)
|
||||
.expect(&format!(
|
||||
"symbol_id {} has no associated type_info",
|
||||
symbol_id
|
||||
));
|
||||
@ -318,7 +405,7 @@ impl AnalysisContext {
|
||||
pub fn find_symbol_by_fqn(&self, fqn: &str) -> Option<SymbolId> {
|
||||
// This is quite naive and probably very slow; we will certainly use trees of HashMaps (or
|
||||
// structs with a HashMap and children) to represent the fqn hierarchy.
|
||||
for (id, symbol) in self.symbols.iter().enumerate() {
|
||||
for (id, symbol) in self.state.symbols.iter().enumerate() {
|
||||
match symbol {
|
||||
Symbol::Class(class_symbol) => {
|
||||
if class_symbol.fqn() == fqn {
|
||||
@ -335,4 +422,43 @@ impl AnalysisContext {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_symbol_id(&self, node_id: NodeId) -> Option<SymbolId> {
|
||||
self.state.nodes_to_scopes.get(&node_id).cloned()
|
||||
}
|
||||
|
||||
pub fn make_class_type(
|
||||
&mut self,
|
||||
class_symbol_id: SymbolId,
|
||||
constructor_symbol_id: Option<SymbolId>,
|
||||
) -> TypeInfoId {
|
||||
if let Some(type_info_id) = self.state.symbols_to_type_infos.get(&class_symbol_id) {
|
||||
*type_info_id
|
||||
} else {
|
||||
let type_info =
|
||||
TypeInfo::Class(ClassTypeInfo::new(class_symbol_id, constructor_symbol_id));
|
||||
self.state.type_infos.push(type_info);
|
||||
let type_info_id = self.state.type_infos.len() - 1;
|
||||
self.state
|
||||
.symbols_to_type_infos
|
||||
.insert(class_symbol_id, type_info_id);
|
||||
type_info_id
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_type_info_id(&mut self, node_id: NodeId, declared_name: &str) -> TypeInfoId {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn int_type(&mut self) -> &TypeInfoId {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn double_type(&mut self) -> &TypeInfoId {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn type_by_fqn(&mut self, fqn: &str) -> &TypeInfoId {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,8 +7,7 @@ use crate::ast::parameter::Parameter;
|
||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||
use crate::semantic_analysis::symbol::SymbolId;
|
||||
use crate::semantic_analysis::type_info::{
|
||||
ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeConstructorInfo, TypeInfo,
|
||||
TypeInfoId,
|
||||
ClassTypeInfo, ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeInfo, TypeInfoId,
|
||||
};
|
||||
|
||||
pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) {
|
||||
@ -148,7 +147,7 @@ fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
|
||||
// todo: fields, methods
|
||||
|
||||
// Self type constructor
|
||||
let type_constructor_type_info = TypeInfo::TypeConstructor(TypeConstructorInfo::new(
|
||||
let type_constructor_type_info = TypeInfo::Class(ClassTypeInfo::new(
|
||||
ctx.nodes_to_symbols()[&class.node_id()],
|
||||
constructor_type_info_id,
|
||||
));
|
||||
|
||||
@ -255,7 +255,7 @@ fn resolve_types_call(call: &Call, ctx: &mut AnalysisContext, diagnostics: &mut
|
||||
let callee_type_info = ctx.get_type_info_for_node(call.callee().node_id());
|
||||
|
||||
match callee_type_info {
|
||||
TypeInfo::TypeConstructor(type_constructor_info) => {
|
||||
TypeInfo::Class(type_constructor_info) => {
|
||||
let class_symbol =
|
||||
ctx.symbols()[type_constructor_info.class_symbol_id()].unwrap_class_symbol();
|
||||
match class_symbol.constructor_symbol_id() {
|
||||
|
||||
@ -150,7 +150,7 @@ pub fn can_assign_right_to_left(left: &TypeInfo, right: &TypeInfo, ctx: &Analysi
|
||||
TypeInfo::Constructor(_) => {
|
||||
panic!()
|
||||
}
|
||||
TypeInfo::TypeConstructor(_) => {
|
||||
TypeInfo::Class(_) => {
|
||||
panic!()
|
||||
}
|
||||
TypeInfo::Instance(left_instance_type_info) => match right {
|
||||
|
||||
@ -4,6 +4,7 @@ use std::rc::Rc;
|
||||
|
||||
pub type ScopeId = usize;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Scope {
|
||||
parent_id: Option<ScopeId>,
|
||||
symbols: HashMap<Rc<str>, SymbolId>,
|
||||
@ -21,6 +22,10 @@ impl Scope {
|
||||
self.parent_id
|
||||
}
|
||||
|
||||
pub fn has_symbol(&self, declared_name: &str) -> bool {
|
||||
self.symbols.contains_key(declared_name)
|
||||
}
|
||||
|
||||
pub fn insert_symbol(&mut self, declared_name: Rc<str>, symbol_id: SymbolId) {
|
||||
self.symbols.insert(declared_name, symbol_id);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ use std::rc::Rc;
|
||||
|
||||
pub type SymbolId = usize;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Symbol {
|
||||
Class(ClassSymbol),
|
||||
Field(FieldSymbol),
|
||||
@ -60,7 +60,7 @@ impl Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClassSymbol {
|
||||
declared_name: Rc<str>,
|
||||
source_range: Option<SourceRange>,
|
||||
@ -129,7 +129,7 @@ impl ClassSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FieldSymbol {
|
||||
declared_name: Rc<str>,
|
||||
declared_name_source_range: Option<SourceRange>,
|
||||
@ -156,7 +156,7 @@ impl FieldSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FunctionType {
|
||||
Function,
|
||||
Constructor,
|
||||
@ -164,7 +164,7 @@ pub enum FunctionType {
|
||||
StaticMethod,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionSymbol {
|
||||
declared_name: Rc<str>,
|
||||
declared_name_source_range: Option<SourceRange>,
|
||||
@ -219,7 +219,7 @@ impl FunctionSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParameterSymbol {
|
||||
name: Rc<str>,
|
||||
source_range: Option<SourceRange>,
|
||||
@ -243,7 +243,7 @@ impl ParameterSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VariableSymbol {
|
||||
name: Rc<str>,
|
||||
source_range: Option<SourceRange>,
|
||||
|
||||
@ -10,16 +10,14 @@ pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisConte
|
||||
}
|
||||
|
||||
fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
|
||||
let class_symbol_id = *ctx
|
||||
.nodes_to_symbols()
|
||||
.get(&class.node_id())
|
||||
.expect(&format!(
|
||||
"Could not find class symbol for {} {}",
|
||||
let maybe_constructor_type_info_id = class
|
||||
.constructor()
|
||||
.and_then(|constructor| ctx.get_symbol_id(constructor.node_id()));
|
||||
|
||||
let class_symbol_id = ctx.get_symbol_id(class.node_id()).expect(&format!(
|
||||
"Could not find symbol for {} {}",
|
||||
class.node_id(),
|
||||
class.declared_name()
|
||||
));
|
||||
|
||||
let self_instance_type_info = TypeInfo::Instance(InstanceTypeInfo::new(class_symbol_id));
|
||||
let self_instance_type_info_id = ctx.insert_type_info(self_instance_type_info);
|
||||
ctx.associate_symbol_to_type(class_symbol_id, self_instance_type_info_id)
|
||||
ctx.make_class_type(class_symbol_id, maybe_constructor_type_info_id);
|
||||
}
|
||||
|
||||
@ -1,3 +1,13 @@
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||
use crate::semantic_analysis::type_analysis::collect::collect_types;
|
||||
use crate::semantic_analysis::type_analysis::resolve::resolve_types;
|
||||
|
||||
mod collect;
|
||||
mod infer;
|
||||
mod resolve;
|
||||
|
||||
pub fn analyze_types(compilation_unit: &CompilationUnit, analysis_context: &mut AnalysisContext) {
|
||||
collect_types(compilation_unit, analysis_context);
|
||||
resolve_types(compilation_unit, analysis_context);
|
||||
}
|
||||
|
||||
@ -1 +1,31 @@
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::ast::function::Function;
|
||||
use crate::ast::parameter::Parameter;
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::semantic_analysis::analysis_context::AnalysisContext;
|
||||
|
||||
pub fn resolve_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) {
|
||||
for function in compilation_unit.functions() {
|
||||
resolve_types_function(function, ctx);
|
||||
}
|
||||
for extern_function in compilation_unit.extern_functions() {}
|
||||
for class in compilation_unit.classes() {}
|
||||
}
|
||||
|
||||
fn resolve_types_function(function: &Function, ctx: &mut AnalysisContext) {
|
||||
for parameter in function.parameters() {
|
||||
resolve_types_parameter(parameter, ctx);
|
||||
}
|
||||
if let Some(return_type) = function.return_type() {
|
||||
resolve_types_type_use(return_type, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_types_parameter(parameter: &Parameter, ctx: &mut AnalysisContext) {
|
||||
resolve_types_type_use(parameter.type_use(), ctx);
|
||||
}
|
||||
|
||||
fn resolve_types_type_use(type_use: &TypeUse, ctx: &mut AnalysisContext) {
|
||||
let type_info_id = ctx.resolve_type_info_id(type_use.node_id(), type_use.declared_name());
|
||||
todo!()
|
||||
}
|
||||
|
||||
@ -6,9 +6,9 @@ pub type TypeInfoId = usize;
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TypeInfo {
|
||||
Any,
|
||||
Function(FunctionTypeInfo),
|
||||
Class(ClassTypeInfo),
|
||||
Constructor(ConstructorTypeInfo),
|
||||
TypeConstructor(TypeConstructorInfo),
|
||||
Function(FunctionTypeInfo),
|
||||
Instance(InstanceTypeInfo),
|
||||
Int,
|
||||
Double,
|
||||
@ -24,9 +24,9 @@ impl TypeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_type_constructor(&self) -> &TypeConstructorInfo {
|
||||
pub fn unwrap_class(&self) -> &ClassTypeInfo {
|
||||
match self {
|
||||
TypeInfo::TypeConstructor(type_constructor_info) => type_constructor_info,
|
||||
TypeInfo::Class(type_constructor_info) => type_constructor_info,
|
||||
_ => panic!("Attempt to unwrap {:?} as TypeConstructor", self),
|
||||
}
|
||||
}
|
||||
@ -89,16 +89,16 @@ impl ConstructorTypeInfo {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TypeConstructorInfo {
|
||||
pub struct ClassTypeInfo {
|
||||
class_symbol_id: SymbolId,
|
||||
constructor_type_info_id: Option<TypeInfoId>,
|
||||
constructor_symbol_id: Option<SymbolId>,
|
||||
}
|
||||
|
||||
impl TypeConstructorInfo {
|
||||
pub fn new(class_symbol_id: SymbolId, constructor_type_info_id: Option<TypeInfoId>) -> Self {
|
||||
impl ClassTypeInfo {
|
||||
pub fn new(class_symbol_id: SymbolId, constructor_symbol_id: Option<SymbolId>) -> Self {
|
||||
Self {
|
||||
class_symbol_id,
|
||||
constructor_type_info_id,
|
||||
constructor_symbol_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,8 +106,8 @@ impl TypeConstructorInfo {
|
||||
self.class_symbol_id
|
||||
}
|
||||
|
||||
pub fn constructor_type_info_id(&self) -> Option<TypeInfoId> {
|
||||
self.constructor_type_info_id
|
||||
pub fn constructor_type_info_id(&self) -> Option<SymbolId> {
|
||||
self.constructor_symbol_id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user