galvan_resolver/
lookup.rs1use galvan_ast::{
2 FnDecl, Ident, MainDecl, SegmentedAsts, ToplevelItem, TypeDecl, TypeElement, TypeIdent,
3};
4use std::collections::HashMap;
5use thiserror::Error;
6
7#[derive(Clone, Debug, Default)]
8pub struct LookupContext<'a> {
9 pub types: HashMap<TypeIdent, &'a ToplevelItem<TypeDecl>>,
11 pub functions: HashMap<FunctionId, &'a ToplevelItem<FnDecl>>,
17 pub main: Option<&'a ToplevelItem<MainDecl>>,
20}
21
22pub trait Lookup {
23 fn resolve_type(&self, name: &TypeIdent) -> Option<&ToplevelItem<TypeDecl>>;
24
25 fn resolve_function(
26 &self,
27 receiver: Option<&TypeIdent>,
28 name: &Ident,
29 labels: &[&str],
30 ) -> Option<&ToplevelItem<FnDecl>>;
31}
32
33#[derive(Debug, Error)]
35pub enum LookupError {
36 #[error("Type not found")]
37 TypeNotFound,
38 #[error("Function not found")]
39 FunctionNotFound,
40 #[error("Duplicate type")]
41 DuplicateType(TypeIdent),
42 #[error("Duplicate function")]
43 DuplicateFunction,
44}
45
46impl<'a> LookupContext<'a> {
47 pub fn new() -> Self {
48 Self::default()
49 }
50 pub fn add_from(&mut self, asts: &'a SegmentedAsts) -> Result<(), LookupError> {
51 for func in &asts.functions {
52 let receiver = func.item.signature.parameters.params.first().and_then(|p| {
53 if p.identifier.as_str() == "self" {
54 match p.param_type {
56 TypeElement::Plain(ref ty) => Some(&ty.ident),
57 _ => None,
58 }
59 } else {
60 None
61 }
62 });
63 let func_id = FunctionId::new(receiver, &func.signature.identifier, &[]);
64 if self.functions.insert(func_id, func).is_some() {
65 return Err(LookupError::DuplicateFunction);
66 }
67 }
68
69 for type_decl in &asts.types {
70 if self
71 .types
72 .insert(type_decl.ident().clone(), type_decl)
73 .is_some()
74 {
75 return Err(LookupError::DuplicateType(type_decl.ident().clone()));
76 }
77 }
78
79 Ok(())
80 }
81
82 pub fn with(mut self, asts: &'a SegmentedAsts) -> Result<Self, LookupError> {
83 self.add_from(asts)?;
84 Ok(self)
85 }
86}
87
88impl Lookup for LookupContext<'_> {
89 fn resolve_type(&self, name: &TypeIdent) -> Option<&ToplevelItem<TypeDecl>> {
90 self.types.get(&name).copied()
91 }
92
93 fn resolve_function(
94 &self,
95 receiver: Option<&TypeIdent>,
96 name: &Ident,
97 labels: &[&str],
98 ) -> Option<&ToplevelItem<FnDecl>> {
99 let func_id = FunctionId::new(receiver, name, labels);
100 self.functions.get(&func_id).copied()
101 }
102}
103
104#[derive(Clone, Debug, Hash, PartialEq, Eq)]
105pub struct FunctionId(Box<str>);
106
107impl FunctionId {
108 fn new(receiver: Option<&TypeIdent>, fn_ident: &Ident, labels: &[&str]) -> Self {
109 let mut id = String::new();
110 if let Some(receiver) = receiver {
111 id.push_str(receiver.as_str());
112 id.push_str("::");
113 }
114 id.push_str(fn_ident.as_str());
115 if !labels.is_empty() {
116 id.push(':');
117 id.push_str(&labels.join(":"));
118 }
119
120 Self(id.into())
121 }
122}
123
124impl std::fmt::Display for FunctionId {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 write!(f, "{}", self.0)
127 }
128}