use std::rc::Rc;
use super::super::IdentifierPathStruct;
use super::{Definition, Type};
use crate::backend::binder::Resolution;
use crate::backend::built_ins::BuiltIn;
use crate::backend::SemanticAnalysis;
use crate::cst::{NodeId, TerminalKind, TerminalNode, TextIndex};
pub type Identifier = Rc<IdentifierStruct>;
pub(crate) fn create_identifier(
ir_node: &Rc<TerminalNode>,
semantic: &Rc<SemanticAnalysis>,
) -> Identifier {
assert!(ir_node.kind == TerminalKind::Identifier);
Rc::new(IdentifierStruct {
ir_node: Rc::clone(ir_node),
semantic: Rc::clone(semantic),
})
}
pub struct IdentifierStruct {
ir_node: Rc<TerminalNode>,
semantic: Rc<SemanticAnalysis>,
}
impl IdentifierStruct {
pub fn node_id(&self) -> NodeId {
self.ir_node.id()
}
pub fn name(&self) -> String {
self.ir_node.unparse()
}
pub fn is_reference(&self) -> bool {
self.semantic
.binder()
.find_reference_by_identifier_node_id(self.ir_node.id())
.is_some()
}
pub fn resolve_to_definition(&self) -> Option<Definition> {
let definition_id = self
.semantic
.resolve_reference_identifier_to_definition_id(self.ir_node.id())?;
Definition::try_create(definition_id, &self.semantic)
}
pub fn resolve_to_immediate_definition(&self) -> Option<Definition> {
let definition_id = self
.semantic
.resolve_reference_identifier_to_immediate_definition_id(self.ir_node.id())?;
Definition::try_create(definition_id, &self.semantic)
}
pub fn is_definition(&self) -> bool {
self.as_definition().is_some()
}
pub fn as_definition(&self) -> Option<Definition> {
Definition::try_create(self.ir_node.id(), &self.semantic)
}
pub fn is_name_of_definition(&self) -> bool {
self.semantic
.binder()
.find_definition_by_identifier_node_id(self.ir_node.id())
.is_some()
}
pub fn references(&self) -> Vec<Reference> {
self.semantic.references_binding_to(self.ir_node.id())
}
pub fn get_type(&self) -> Option<Type> {
self.semantic.get_type_from_node_id(self.ir_node.id())
}
pub fn resolved_built_in(&self) -> Option<BuiltIn> {
let reference = self
.semantic
.binder
.find_reference_by_identifier_node_id(self.ir_node.id())?;
match &reference.resolution {
Resolution::BuiltIn(built_in) => Some(*built_in),
_ => None,
}
}
pub fn text_offset(&self) -> TextIndex {
self.semantic
.get_text_offset_by_node_id(self.ir_node.id())
.unwrap()
}
}
pub type YulIdentifierStruct = IdentifierStruct;
pub type YulIdentifier = Rc<YulIdentifierStruct>;
pub(crate) fn create_yul_identifier(
ir_node: &Rc<TerminalNode>,
semantic: &Rc<SemanticAnalysis>,
) -> YulIdentifier {
assert!(ir_node.kind == TerminalKind::YulIdentifier);
Rc::new(YulIdentifierStruct {
ir_node: Rc::clone(ir_node),
semantic: Rc::clone(semantic),
})
}
pub enum Reference {
Identifier(Identifier),
YulIdentifier(YulIdentifier),
}
impl Reference {
pub(crate) fn try_create(
node: &Rc<TerminalNode>,
semantic: &Rc<SemanticAnalysis>,
) -> Option<Self> {
semantic
.binder()
.find_reference_by_identifier_node_id(node.id())?;
match node.kind {
TerminalKind::Identifier => {
Some(Reference::Identifier(create_identifier(node, semantic)))
}
TerminalKind::YulIdentifier => Some(Reference::YulIdentifier(create_yul_identifier(
node, semantic,
))),
_ => None,
}
}
pub fn name(&self) -> String {
match self {
Reference::Identifier(identifier) | Reference::YulIdentifier(identifier) => {
identifier.name()
}
}
}
pub fn resolve_to_definition(&self) -> Option<Definition> {
match self {
Reference::Identifier(identifier) | Reference::YulIdentifier(identifier) => {
identifier.resolve_to_definition()
}
}
}
pub fn resolve_to_immediate_definition(&self) -> Option<Definition> {
match self {
Reference::Identifier(identifier) | Reference::YulIdentifier(identifier) => {
identifier.resolve_to_immediate_definition()
}
}
}
}
impl SemanticAnalysis {
pub(crate) fn references_binding_to(self: &Rc<Self>, node_id: NodeId) -> Vec<Reference> {
let node_ids = self.binder().get_references_by_definition_id(node_id);
node_ids
.iter()
.filter_map(|node_id| {
self.binder()
.find_reference_by_identifier_node_id(*node_id)
.and_then(|reference| Reference::try_create(&reference.identifier, self))
})
.collect()
}
fn resolve_reference_identifier_to_definition_id(&self, node_id: NodeId) -> Option<NodeId> {
let reference = self
.binder()
.find_reference_by_identifier_node_id(node_id)?;
self.binder()
.follow_symbol_aliases(&reference.resolution)
.as_definition_id()
}
fn resolve_reference_identifier_to_immediate_definition_id(
&self,
node_id: NodeId,
) -> Option<NodeId> {
let reference = self
.binder()
.find_reference_by_identifier_node_id(node_id)?;
reference.resolution.as_definition_id()
}
}
impl IdentifierPathStruct {
pub fn name(&self) -> String {
self.ir_nodes
.iter()
.map(|ir_node| ir_node.unparse())
.collect::<Vec<_>>()
.join(".")
}
pub fn resolve_to_definition(&self) -> Option<Definition> {
let ir_node = self.ir_nodes.last()?;
let definition_id = self
.semantic
.resolve_reference_identifier_to_definition_id(ir_node.id())?;
Definition::try_create(definition_id, &self.semantic)
}
pub fn resolve_to_immediate_definition(&self) -> Option<Definition> {
let ir_node = self.ir_nodes.last()?;
let definition_id = self
.semantic
.resolve_reference_identifier_to_immediate_definition_id(ir_node.id())?;
Definition::try_create(definition_id, &self.semantic)
}
}