galvan_resolver/
lookup.rs

1use 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    /// Types are resolved by their name
10    pub types: HashMap<TypeIdent, &'a ToplevelItem<TypeDecl>>,
11    /// Functions are resolved by their name and - if present - named arguments and their receiver type
12    ///
13    /// `fn foo(a: i32, b: i32) -> i32` is identified as `foo`
14    /// `fn foo(bar a: i32, b: i32) -> i32` is identified as `foo:bar`
15    /// `fn foo(self: i32, b: i32) -> i32` is identified as `i32::foo`
16    pub functions: HashMap<FunctionId, &'a ToplevelItem<FnDecl>>,
17    // TODO: Nested contexts for resolving names from imported modules
18    // pub imports: HashMap<String, LookupContext<'a>>,
19    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// TODO: Include spans in errors
34#[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                    // TODO: We should allow implementing something on Vec, etc. as well
55                    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}