galvan_resolver/
lookup.rs

1use galvan_ast::{FnDecl, Ident, MainDecl, SegmentedAsts, ToplevelItem, TypeDecl, TypeIdent};
2use std::collections::HashMap;
3use thiserror::Error;
4
5#[derive(Debug, Default)]
6pub struct LookupContext<'a> {
7    /// Types are resolved by their name
8    pub types: HashMap<TypeIdent, &'a ToplevelItem<TypeDecl>>,
9    /// Functions are resolved by their name and - if present - named arguments and their receiver type
10    ///
11    /// `fn foo(a: i32, b: i32) -> i32` is identified as `foo`
12    /// `fn foo(bar a: i32, b: i32) -> i32` is identified as `foo:bar`
13    /// `fn foo(self: i32, b: i32) -> i32` is identified as `i32::foo`
14    pub functions: HashMap<FunctionId, &'a ToplevelItem<FnDecl>>,
15    // TODO: Nested contexts for resolving names from imported modules
16    // pub imports: HashMap<String, LookupContext<'a>>,
17    pub main: Option<&'a ToplevelItem<MainDecl>>,
18}
19
20pub trait Lookup {
21    fn resolve_type(&self, name: &TypeIdent) -> Option<&ToplevelItem<TypeDecl>>;
22
23    fn resolve_function(
24        &self,
25        receiver: Option<&TypeIdent>,
26        name: &Ident,
27        labels: &[&str],
28    ) -> Option<&ToplevelItem<FnDecl>>;
29}
30
31// TODO: Include spans in errors
32#[derive(Debug, Error)]
33pub enum LookupError {
34    #[error("Type not found")]
35    TypeNotFound,
36    #[error("Function not found")]
37    FunctionNotFound,
38    #[error("Duplicate type")]
39    DuplicateType(TypeIdent),
40    #[error("Duplicate function")]
41    DuplicateFunction,
42}
43
44impl<'a> LookupContext<'a> {
45    pub fn new() -> Self {
46        Self::default()
47    }
48    pub fn add_from(&mut self, asts: &'a SegmentedAsts) -> Result<(), LookupError> {
49        for func in &asts.functions {
50            let func_id = FunctionId::new(None, &func.signature.identifier, &[]);
51            if self.functions.insert(func_id, func).is_some() {
52                return Err(LookupError::DuplicateFunction);
53            }
54        }
55
56        for type_decl in &asts.types {
57            if self
58                .types
59                .insert(type_decl.ident().clone(), type_decl)
60                .is_some()
61            {
62                return Err(LookupError::DuplicateType(type_decl.ident().clone()));
63            }
64        }
65
66        Ok(())
67    }
68
69    pub fn with(mut self, asts: &'a SegmentedAsts) -> Result<Self, LookupError> {
70        self.add_from(asts)?;
71        Ok(self)
72    }
73}
74
75impl Lookup for LookupContext<'_> {
76    fn resolve_type(&self, name: &TypeIdent) -> Option<&ToplevelItem<TypeDecl>> {
77        self.types.get(&name).copied()
78    }
79
80    fn resolve_function(
81        &self,
82        receiver: Option<&TypeIdent>,
83        name: &Ident,
84        labels: &[&str],
85    ) -> Option<&ToplevelItem<FnDecl>> {
86        let func_id = FunctionId::new(receiver, name, labels);
87        self.functions.get(&func_id).copied()
88    }
89}
90
91#[derive(Debug, Hash, PartialEq, Eq)]
92pub struct FunctionId(Box<str>);
93
94impl FunctionId {
95    fn new(receiver: Option<&TypeIdent>, fn_ident: &Ident, labels: &[&str]) -> Self {
96        let mut id = String::new();
97        if let Some(receiver) = receiver {
98            id.push_str(receiver.as_str());
99            id.push_str("::");
100        }
101        id.push_str(fn_ident.as_str());
102        if !labels.is_empty() {
103            id.push(':');
104            id.push_str(&labels.join(":"));
105        }
106
107        Self(id.into())
108    }
109}