1use crate::{diag::*, resolve::*, syntax::*};
7
8pub(super) trait Symbolize<T = Option<Symbol>> {
9 fn symbolize(&self, _parent: &Symbol, _context: &mut ResolveContext) -> ResolveResult<T> {
11 unreachable!()
12 }
13}
14
15impl SourceFile {
16 pub fn symbolize(
18 &self,
19 visibility: Visibility,
20 context: &mut ResolveContext,
21 ) -> ResolveResult<Symbol> {
22 let symbol = Symbol::new_with_visibility(
23 visibility,
24 SymbolDefinition::SourceFile(self.clone().into()),
25 None,
26 );
27 symbol.set_children(
28 self.statements
29 .grant(&symbol, context)?
30 .symbolize(&symbol, context)?,
31 );
32 Ok(symbol)
33 }
34}
35
36impl Symbolize<Symbol> for ModuleDefinition {
37 fn symbolize(&self, parent: &Symbol, context: &mut ResolveContext) -> ResolveResult<Symbol> {
38 let symbol = if let Some(body) = &self.body {
39 let symbol = Symbol::new(
40 SymbolDefinition::Module(self.clone().into()),
41 Some(parent.clone()),
42 );
43 symbol.set_children(body.grant(&symbol, context)?.symbolize(&symbol, context)?);
44 symbol
45 } else if let Some(parent_path) = parent.source_path() {
46 let mut symbol = context.symbolize_file(self.visibility, parent_path, &self.id)?;
47 symbol.set_parent(parent.clone());
48 symbol
49 } else {
50 todo!("no top-level source file")
51 };
52 Ok(symbol)
53 }
54}
55
56impl Symbolize<SymbolMap> for StatementList {
57 fn symbolize(&self, parent: &Symbol, context: &mut ResolveContext) -> ResolveResult<SymbolMap> {
58 let mut symbols = SymbolMap::default();
59
60 for statement in &self.0 {
62 if let Some((id, symbol)) = statement
63 .grant(parent, context)?
64 .symbolize(parent, context)?
65 {
66 symbols.insert(id, symbol);
67 }
68 }
69
70 Ok(symbols)
71 }
72}
73
74impl Symbolize<Option<(Identifier, Symbol)>> for Statement {
75 fn symbolize(
76 &self,
77 parent: &Symbol,
78 context: &mut ResolveContext,
79 ) -> ResolveResult<Option<(Identifier, Symbol)>> {
80 match self {
81 Statement::Workbench(wd) => Ok(Some((
82 wd.id.clone(),
83 wd.grant(parent, context)?.symbolize(parent, context)?,
84 ))),
85 Statement::Module(md) => Ok(Some((
86 md.id.clone(),
87 md.grant(parent, context)?.symbolize(parent, context)?,
88 ))),
89 Statement::Function(fd) => Ok(Some((
90 fd.id.clone(),
91 fd.grant(parent, context)?.symbolize(parent, context)?,
92 ))),
93 Statement::Use(us) => us.grant(parent, context)?.symbolize(parent, context),
94 Statement::Assignment(a) => Ok(a
95 .grant(parent, context)?
96 .symbolize(parent, context)?
97 .map(|symbol| (a.assignment.id.clone(), symbol))),
98 Statement::Init(_)
100 | Statement::Return(_)
101 | Statement::If(_)
102 | Statement::InnerAttribute(_)
103 | Statement::Expression(_) => Ok(None),
104 }
105 }
106}
107
108impl Symbolize<Symbol> for WorkbenchDefinition {
109 fn symbolize(&self, parent: &Symbol, context: &mut ResolveContext) -> ResolveResult<Symbol> {
110 let symbol = Symbol::new(
111 SymbolDefinition::Workbench(self.clone().into()),
112 Some(parent.clone()),
113 );
114 symbol.set_children(
115 self.body
116 .grant(&symbol, context)?
117 .symbolize(&symbol, context)?,
118 );
119 Ok(symbol)
120 }
121}
122
123impl Symbolize<Symbol> for FunctionDefinition {
124 fn symbolize(&self, parent: &Symbol, context: &mut ResolveContext) -> ResolveResult<Symbol> {
125 let symbol = Symbol::new(
126 SymbolDefinition::Function((*self).clone().into()),
127 Some(parent.clone()),
128 );
129 symbol.set_children(
130 self.body
131 .grant(&symbol, context)?
132 .symbolize(&symbol, context)?,
133 );
134
135 Ok(symbol)
136 }
137}
138
139impl Symbolize for AssignmentStatement {
140 fn symbolize(
141 &self,
142 parent: &Symbol,
143 context: &mut ResolveContext,
144 ) -> ResolveResult<Option<Symbol>> {
145 let symbol = match (self.assignment.visibility, self.assignment.qualifier()) {
146 (_, Qualifier::Prop) => {
148 if !parent.can_prop() {
149 None
150 } else {
151 Some(None)
152 }
153 }
154 (_, Qualifier::Const) | (Visibility::Public, Qualifier::Value) => {
156 if !parent.can_const() {
157 None
158 } else {
159 log::trace!("Declaring private const expression: {}", self.assignment.id);
160 Some(Some(Symbol::new(
161 SymbolDefinition::ConstExpression(
162 self.assignment.visibility,
163 self.assignment.id.clone(),
164 self.assignment.expression.clone(),
165 ),
166 Some(parent.clone()),
167 )))
168 }
169 }
170 (Visibility::Private, Qualifier::Value) => {
172 if self.assignment.visibility == Visibility::Private && !parent.can_value() {
173 None
174 } else {
175 Some(None)
176 }
177 }
178 (Visibility::Deleted, _) => unreachable!(),
179 };
180
181 match symbol {
182 Some(symbol) => Ok(symbol),
183 None => {
184 context.error(
185 self,
186 ResolveError::DeclNotAllowed(self.assignment.id.clone(), parent.full_name()),
187 )?;
188 Ok(None)
189 }
190 }
191 }
192}
193
194impl Symbolize<SymbolMap> for Body {
195 fn symbolize(&self, parent: &Symbol, context: &mut ResolveContext) -> ResolveResult<SymbolMap> {
196 self.statements
197 .grant(parent, context)?
198 .symbolize(parent, context)
199 }
200}
201
202impl Symbolize<Option<(Identifier, Symbol)>> for UseStatement {
203 fn symbolize(
204 &self,
205 parent: &Symbol,
206 _: &mut ResolveContext,
207 ) -> ResolveResult<Option<(Identifier, Symbol)>> {
208 if !parent.is_module() {
209 return Ok(None);
210 }
211 match &self.decl {
212 UseDeclaration::Use(name) => {
213 let identifier = name.last().expect("Identifier");
214 Ok(Some((
215 identifier.clone(),
216 Symbol::new(
217 SymbolDefinition::Alias(self.visibility, identifier.clone(), name.clone()),
218 Some(parent.clone()),
219 ),
220 )))
221 }
222 UseDeclaration::UseAll(name) => Ok(Some((
223 Identifier::unique(),
224 Symbol::new(
225 SymbolDefinition::UseAll(self.visibility, name.clone()),
226 Some(parent.clone()),
227 ),
228 ))),
229 UseDeclaration::UseAlias(name, alias) => Ok(Some((
230 alias.clone(),
231 Symbol::new(
232 SymbolDefinition::Alias(self.visibility, alias.clone(), name.clone()),
233 Some(parent.clone()),
234 ),
235 ))),
236 }
237 }
238}