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