galvan_resolver/
scope.rs

1use crate::{FunctionId, Lookup, LookupContext};
2use galvan_ast::{
3    DeclModifier, FnDecl, Ident, Ownership, ToplevelItem, TypeDecl, TypeElement, TypeIdent,
4};
5use std::collections::HashMap;
6
7#[derive(Debug, Default)]
8pub struct Scope<'a> {
9    pub parent: Option<&'a Scope<'a>>,
10    pub variables: HashMap<Ident, Variable>,
11    /// expected type of this scopes return value
12    pub return_type: TypeElement,
13    /// expected ownership of this scopes return value
14    pub ownership: Ownership,
15    pub fn_return: TypeElement,
16
17    lookup: Option<LookupContext<'a>>,
18}
19
20impl Scope<'_> {
21    pub fn child(parent: &Self) -> Scope {
22        Scope {
23            parent: Some(parent),
24            variables: HashMap::new(),
25            lookup: None,
26            return_type: TypeElement::void(),
27            ownership: Ownership::UniqueOwned,
28            fn_return: parent.fn_return.clone(),
29        }
30    }
31
32    pub fn declare_variable(&mut self, variable: Variable) {
33        self.variables.insert(variable.ident.clone(), variable);
34    }
35
36    pub fn get_variable(&self, ident: &Ident) -> Option<&Variable> {
37        self.variables
38            .get(ident)
39            .or_else(|| self.parent.and_then(|parent| parent.get_variable(ident)))
40    }
41}
42
43impl<'a> Scope<'a> {
44    pub fn set_lookup(&mut self, lookup: LookupContext<'a>) {
45        self.lookup = Some(lookup);
46    }
47
48    pub fn returns(mut self, ty: TypeElement, ownership: Ownership) -> Scope<'a> {
49        self.return_type = ty;
50        self.ownership = ownership;
51        self
52    }
53
54    pub fn functions(&self) -> Vec<FunctionId> {
55        let mut functions = Vec::new();
56        let mut scope = self;
57
58        loop {
59            if let Some(ref lookup) = scope.lookup {
60                functions.extend(lookup.functions.keys().map(|v| v.to_owned()))
61            }
62
63            match scope.parent {
64                Some(s) => scope = s,
65                None => break,
66            }
67        }
68
69        functions
70    }
71}
72
73impl Lookup for Scope<'_> {
74    fn resolve_type(&self, name: &TypeIdent) -> Option<&ToplevelItem<TypeDecl>> {
75        self.lookup
76            .as_ref()
77            .and_then(|lookup| lookup.resolve_type(name))
78            .or_else(|| self.parent.and_then(|parent| parent.resolve_type(name)))
79    }
80
81    fn resolve_function(
82        &self,
83        receiver: Option<&TypeIdent>,
84        name: &Ident,
85        labels: &[&str],
86    ) -> Option<&ToplevelItem<FnDecl>> {
87        self.lookup
88            .as_ref()
89            .and_then(|lookup| lookup.resolve_function(receiver, name, labels))
90            .or_else(|| {
91                self.parent
92                    .and_then(|parent| parent.resolve_function(receiver, name, labels))
93            })
94    }
95}
96
97#[derive(Clone, Debug)]
98pub struct Variable {
99    pub ident: Ident,
100    pub modifier: DeclModifier,
101    pub ty: TypeElement,
102    pub ownership: Ownership,
103}
104
105impl Variable {
106    pub fn is_mut(&self) -> bool {
107        matches!(self.modifier, DeclModifier::Mut)
108    }
109}