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