rustre_core/
name_resolution.rsuse crate::diagnostics::{Diagnostic, Level, Span};
use crate::engine::Engine;
use crate::id::{Id, IdRef};
use crate::static_args::{NodeInstance, StaticArgs};
use comemo::TrackedMut;
use rustre_parser::ast::*;
#[memoize]
pub fn resolve_type_decl(engine: TrackedMut<Engine>, name: IdRefNode) -> Option<OneTypeDeclNode> {
let name = name.member();
let name = name.text();
let files = super::all_roots(engine);
files
.iter()
.flat_map(Root::all_type_decl_node)
.flat_map(|decl| decl.all_one_type_decl_node())
.find(|decl| matches!(decl.ident(), Some(n) if n.text() == name))
}
#[memoize]
pub fn find_node<'sa, 'p, 'm>(
mut engine: TrackedMut<Engine>,
caller_static_args: &'sa Option<StaticArgs>,
id_ref_node: IdRefNode,
) -> Option<NodeNode> {
let callee_name = id_ref_node.member();
let node_name = IdRef::new_implicit(<&Id>::from(&callee_name));
if node_name.as_package().is_some() {
todo!("nodes can't be referred to with an explicit package yet");
}
if let Some(caller_static_args) = caller_static_args {
if let Some(node) = caller_static_args.resolve_node(node_name.as_member()) {
return Some(node.node.clone());
}
}
for file in super::all_roots(TrackedMut::reborrow_mut(&mut engine)).as_slice() {
for node in file.all_node_node() {
if let Some(id_node) = node.id_node() {
if let Some(ident) = id_node.ident() {
if node_name.member_eq(<&Id>::from(&ident)) {
return Some(node);
}
}
}
}
}
let span = Span::of_node(id_ref_node.syntax());
Diagnostic::build(Level::Error, format!("unknown node {node_name:?}"))
.with_attachment(span, "not found in this scope")
.emit(&mut engine);
None
}
#[derive(Clone, Debug, Hash)]
pub struct NameResolveQuery {
pub ident: Ident,
pub in_node: Option<NodeInstance>,
}
#[derive(Clone, Debug)]
pub enum ResolvedRuntimeNode<Var, Input = Var> {
Const(OneConstantDeclNode),
Param(Input),
ReturnParam(Var),
Var(Var),
}
#[memoize]
pub fn resolve_const_node(
engine: TrackedMut<Engine>,
query: NameResolveQuery,
) -> Option<OneConstantDeclNode> {
let local_scope = query
.in_node
.iter()
.map(|i| &i.node)
.flat_map(NodeNode::all_one_constant_decl_node);
let files = super::all_roots(engine);
let global_scope = files
.iter()
.flat_map(Root::all_constant_decl_node)
.flat_map(|const_decl| const_decl.all_one_constant_decl_node());
local_scope.chain(global_scope).find(|one_const| {
one_const
.all_id_node()
.any(|i| i.ident().unwrap().text() == query.ident.text())
})
}
#[memoize]
pub fn resolve_const_expr_node(
engine: TrackedMut<Engine>,
query: NameResolveQuery,
) -> Option<ExpressionNode> {
resolve_const_node(engine, query)
.as_ref()
.and_then(OneConstantDeclNode::expression_node)
}
#[memoize]
pub fn resolve_runtime_node(
mut engine: TrackedMut<Engine>,
query: NameResolveQuery,
) -> Option<ResolvedRuntimeNode<TypedIdsNode>> {
if let (ident, Some(in_node)) = (&query.ident, &query.in_node) {
let sig = super::get_signature(TrackedMut::reborrow_mut(&mut engine), in_node.clone());
let params_c = std::iter::repeat(ResolvedRuntimeNode::Param as fn(_) -> _);
let params = sig.params.iter().cloned().zip(params_c);
let return_params_c = std::iter::repeat(ResolvedRuntimeNode::ReturnParam as fn(_) -> _);
let return_params = sig.return_params.iter().cloned().zip(return_params_c);
let local_vars_c = std::iter::repeat(ResolvedRuntimeNode::Var as fn(_) -> _);
let local_vars = query
.in_node
.iter()
.filter_map(|in_node| in_node.node.all_var_decl_node().next())
.flat_map(|var| var.all_typed_ids_node())
.zip(local_vars_c);
let local = params
.chain(return_params)
.chain(local_vars)
.find(|(ids, _)| {
ids.all_id_node()
.map(|id| id.ident().unwrap())
.any(|i| i.text() == ident.text())
});
if let Some((local, constructor)) = local {
return Some(constructor(local));
}
}
resolve_const_node(engine, query).map(ResolvedRuntimeNode::Const)
}