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 pub return_type: TypeElement,
13 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}