solscript_typeck/
scope.rs1use indexmap::IndexMap;
4use smol_str::SmolStr;
5
6use crate::types::{FunctionType, Type, TypeDef};
7
8#[derive(Debug, Clone)]
10pub enum Symbol {
11 Variable(VariableSymbol),
13 Function(FunctionSymbol),
15 Type(TypeDef),
17 Module(ModuleSymbol),
19}
20
21#[derive(Debug, Clone)]
23pub struct VariableSymbol {
24 pub name: SmolStr,
25 pub ty: Type,
26 pub is_mutable: bool,
27}
28
29#[derive(Debug, Clone)]
31pub struct FunctionSymbol {
32 pub name: SmolStr,
33 pub ty: FunctionType,
34 pub is_public: bool,
35}
36
37#[derive(Debug, Clone)]
39pub struct ModuleSymbol {
40 pub name: SmolStr,
41 pub symbols: IndexMap<SmolStr, Symbol>,
42}
43
44#[derive(Debug, Clone)]
46pub struct Scope {
47 pub symbols: IndexMap<SmolStr, Symbol>,
49 pub kind: ScopeKind,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum ScopeKind {
56 Global,
58 Contract,
60 Function,
62 Block,
64}
65
66impl Scope {
67 pub fn new(kind: ScopeKind) -> Self {
68 Self {
69 symbols: IndexMap::new(),
70 kind,
71 }
72 }
73
74 pub fn define(&mut self, name: SmolStr, symbol: Symbol) -> Option<Symbol> {
76 self.symbols.insert(name, symbol)
77 }
78
79 pub fn lookup(&self, name: &str) -> Option<&Symbol> {
81 self.symbols.get(name)
82 }
83}
84
85#[derive(Debug)]
87pub struct SymbolTable {
88 scopes: Vec<Scope>,
90 type_defs: IndexMap<SmolStr, TypeDef>,
92}
93
94impl SymbolTable {
95 pub fn new() -> Self {
96 let mut table = Self {
97 scopes: vec![Scope::new(ScopeKind::Global)],
98 type_defs: IndexMap::new(),
99 };
100 table.define_builtins();
101 table
102 }
103
104 fn define_builtins(&mut self) {
106 }
108
109 pub fn push_scope(&mut self, kind: ScopeKind) {
111 self.scopes.push(Scope::new(kind));
112 }
113
114 pub fn pop_scope(&mut self) -> Option<Scope> {
116 if self.scopes.len() > 1 {
117 self.scopes.pop()
118 } else {
119 None
120 }
121 }
122
123 pub fn current_scope_kind(&self) -> ScopeKind {
125 self.scopes
126 .last()
127 .map(|s| s.kind)
128 .unwrap_or(ScopeKind::Global)
129 }
130
131 pub fn in_contract(&self) -> bool {
133 self.scopes.iter().any(|s| s.kind == ScopeKind::Contract)
134 }
135
136 pub fn in_function(&self) -> bool {
138 self.scopes.iter().any(|s| s.kind == ScopeKind::Function)
139 }
140
141 pub fn define(&mut self, name: SmolStr, symbol: Symbol) -> Option<Symbol> {
143 self.scopes.last_mut()?.define(name, symbol)
144 }
145
146 pub fn define_variable(&mut self, name: SmolStr, ty: Type, is_mutable: bool) -> Option<Symbol> {
148 self.define(
149 name.clone(),
150 Symbol::Variable(VariableSymbol {
151 name,
152 ty,
153 is_mutable,
154 }),
155 )
156 }
157
158 pub fn define_function(
160 &mut self,
161 name: SmolStr,
162 ty: FunctionType,
163 is_public: bool,
164 ) -> Option<Symbol> {
165 self.define(
166 name.clone(),
167 Symbol::Function(FunctionSymbol {
168 name,
169 ty,
170 is_public,
171 }),
172 )
173 }
174
175 pub fn define_type(&mut self, name: SmolStr, def: TypeDef) -> Option<TypeDef> {
177 self.type_defs.insert(name, def)
178 }
179
180 pub fn lookup(&self, name: &str) -> Option<&Symbol> {
182 for scope in self.scopes.iter().rev() {
183 if let Some(symbol) = scope.lookup(name) {
184 return Some(symbol);
185 }
186 }
187 None
188 }
189
190 pub fn lookup_variable(&self, name: &str) -> Option<&VariableSymbol> {
192 self.lookup(name).and_then(|s| match s {
193 Symbol::Variable(v) => Some(v),
194 _ => None,
195 })
196 }
197
198 pub fn lookup_function(&self, name: &str) -> Option<&FunctionSymbol> {
200 self.lookup(name).and_then(|s| match s {
201 Symbol::Function(f) => Some(f),
202 _ => None,
203 })
204 }
205
206 pub fn lookup_type(&self, name: &str) -> Option<&TypeDef> {
208 self.type_defs.get(name)
209 }
210
211 pub fn lookup_local(&self, name: &str) -> Option<&Symbol> {
213 self.scopes.last()?.lookup(name)
214 }
215}
216
217impl Default for SymbolTable {
218 fn default() -> Self {
219 Self::new()
220 }
221}