microcad_lang/resolve/
mod.rs1mod externals;
19mod resolve_error;
20mod sources;
21mod symbol;
22mod symbol_definition;
23mod symbol_map;
24
25pub use externals::*;
26pub use resolve_error::*;
27pub use sources::*;
28pub use symbol::*;
29pub use symbol_definition::*;
30pub use symbol_map::*;
31
32use crate::{syntax::*, value::Value};
33
34pub trait FullyQualify {
36 fn full_name(&self) -> QualifiedName;
38}
39
40trait Resolve<T = Option<Symbol>> {
41 fn resolve(&self, parent: &Symbol) -> ResolveResult<T>;
43
44 }
46
47#[test]
48fn resolve_test() {
49 let root = SourceFile::load("../examples/lego_brick.µcad").expect("loading failed");
50 let sources = Sources::load(root.clone(), &["../lib".into()]).expect("loading failed");
51 let root_id = sources.root().id();
52 let symbols = sources.resolve().expect("resolve failed");
53 log::trace!("Symbols:\n{symbols}");
54
55 crate::eval::SymbolTable::new(root_id, symbols, sources).expect("new symbol table");
56}
57
58impl SourceFile {
59 pub fn resolve(&self) -> ResolveResult<Symbol> {
61 let name = self.filename_as_str();
62 log::debug!("Creating symbol from source file {name}");
63 let symbol = Symbol::new(SymbolDefinition::SourceFile(self.clone().into()), None);
64 symbol.borrow_mut().children = self.statements.resolve(&symbol)?;
65 log::trace!("Created symbol from source file {name}:\n{symbol}");
66 Ok(symbol)
67 }
68}
69
70impl Resolve<Symbol> for ModuleDefinition {
71 fn resolve(&self, parent: &Symbol) -> ResolveResult<Symbol> {
73 let symbol = Symbol::new(
74 SymbolDefinition::Module(self.clone().into()),
75 Some(parent.clone()),
76 );
77 symbol.borrow_mut().children = self.body.resolve(&symbol)?;
78 Ok(symbol)
79 }
80}
81
82impl Resolve<SymbolMap> for StatementList {
83 fn resolve(&self, parent: &Symbol) -> ResolveResult<SymbolMap> {
84 let mut symbols = SymbolMap::default();
85
86 for statement in &self.0 {
88 if let Some((id, symbol)) = statement.resolve(parent)? {
89 symbols.insert(id, symbol);
90 }
91 }
92
93 Ok(symbols)
94 }
95}
96
97impl Resolve<Option<(Identifier, Symbol)>> for Statement {
98 fn resolve(&self, parent: &Symbol) -> ResolveResult<Option<(Identifier, Symbol)>> {
99 match self {
100 Statement::Workbench(wd) => Ok(Some((wd.id.clone(), wd.resolve(parent)?))),
101 Statement::Module(md) => Ok(Some((md.id.clone(), md.resolve(parent)?))),
102 Statement::Function(fd) => Ok(Some((fd.id.clone(), fd.resolve(parent)?))),
103 Statement::Use(us) => us.resolve(parent),
104 Statement::Assignment(a) => Ok(a
105 .resolve(parent)?
106 .map(|symbol| (a.assignment.id.clone(), symbol))),
107 Statement::Init(_)
109 | Statement::Return(_)
110 | Statement::If(_)
111 | Statement::InnerAttribute(_)
112 | Statement::Expression(_) => Ok(None),
113 }
114 }
115}
116
117impl Resolve<Symbol> for WorkbenchDefinition {
118 fn resolve(&self, parent: &Symbol) -> ResolveResult<Symbol> {
119 let symbol = Symbol::new(
120 SymbolDefinition::Workbench(self.clone().into()),
121 Some(parent.clone()),
122 );
123 symbol.borrow_mut().children = self.body.resolve(&symbol)?;
124 Ok(symbol)
125 }
126}
127
128impl Resolve<Symbol> for FunctionDefinition {
129 fn resolve(&self, parent: &Symbol) -> ResolveResult<Symbol> {
130 let symbol = Symbol::new(
131 SymbolDefinition::Function((*self).clone().into()),
132 Some(parent.clone()),
133 );
134 symbol.borrow_mut().children = self.body.resolve(&symbol)?;
135
136 Ok(symbol)
137 }
138}
139
140impl Resolve for InitDefinition {
141 fn resolve(&self, _parent: &Symbol) -> ResolveResult<Option<Symbol>> {
142 Ok(None)
143 }
144}
145
146impl Resolve<Option<(Identifier, Symbol)>> for UseStatement {
147 fn resolve(&self, parent: &Symbol) -> ResolveResult<Option<(Identifier, Symbol)>> {
148 match self.visibility {
149 Visibility::Private => Ok(None),
150 Visibility::Public => self.decl.resolve(parent),
152 }
153 }
154}
155
156impl Resolve for ReturnStatement {
157 fn resolve(&self, _parent: &Symbol) -> ResolveResult<Option<Symbol>> {
158 Ok(None)
159 }
160}
161
162impl Resolve for IfStatement {
163 fn resolve(&self, _parent: &Symbol) -> ResolveResult<Option<Symbol>> {
164 Ok(None)
165 }
166}
167
168impl Resolve for Attribute {
169 fn resolve(&self, _parent: &Symbol) -> ResolveResult<Option<Symbol>> {
170 Ok(None)
171 }
172}
173
174impl Resolve for AssignmentStatement {
175 fn resolve(&self, parent: &Symbol) -> ResolveResult<Option<Symbol>> {
176 match (self.assignment.visibility, self.assignment.qualifier) {
177 (_, Qualifier::Prop) => {
179 if !parent.can_prop() {
180 Err(ResolveError::DeclNotAllowed(
181 self.assignment.id.clone(),
182 parent.full_name(),
183 ))
184 } else {
185 Ok(None)
186 }
187 }
188 (_, Qualifier::Const) | (Visibility::Public, Qualifier::Value) => {
190 if !parent.can_const() {
191 Err(ResolveError::DeclNotAllowed(
192 self.assignment.id.clone(),
193 parent.full_name(),
194 ))
195 } else {
196 log::trace!("Declare private value {}", self.assignment.id);
197 Ok(Some(Symbol::new(
198 SymbolDefinition::Constant(
199 self.assignment.visibility,
200 self.assignment.id.clone(),
201 Value::None,
202 ),
203 Some(parent.clone()),
204 )))
205 }
206 }
207 (Visibility::Private, Qualifier::Value) => {
209 if self.assignment.visibility == Visibility::Private && !parent.can_value() {
210 Err(ResolveError::DeclNotAllowed(
211 self.assignment.id.clone(),
212 parent.full_name(),
213 ))
214 } else {
215 Ok(None)
216 }
217 }
218 }
219 }
220}
221
222impl Resolve for ExpressionStatement {
223 fn resolve(&self, _parent: &Symbol) -> ResolveResult<Option<Symbol>> {
224 Ok(None)
225 }
226}
227
228impl Resolve<SymbolMap> for Body {
229 fn resolve(&self, parent: &Symbol) -> ResolveResult<SymbolMap> {
230 self.statements.resolve(parent)
231 }
232}
233
234impl Resolve<Option<(Identifier, Symbol)>> for UseDeclaration {
235 fn resolve(&self, parent: &Symbol) -> ResolveResult<Option<(Identifier, Symbol)>> {
236 match self {
237 UseDeclaration::Use(visibility, name) => {
238 let identifier = name.last().expect("Identifier");
239 Ok(Some((
240 identifier.clone(),
241 Symbol::new(
242 SymbolDefinition::Alias(*visibility, identifier.clone(), name.clone()),
243 Some(parent.clone()),
244 ),
245 )))
246 }
247 UseDeclaration::UseAll(visibility, _) => Ok(None),
248 UseDeclaration::UseAlias(visibility, name, alias) => Ok(Some((
249 alias.clone(),
250 Symbol::new(
251 SymbolDefinition::Alias(*visibility, alias.clone(), name.clone()),
252 Some(parent.clone()),
253 ),
254 ))),
255 }
256 }
257}
258
259#[test]
260fn resolve_source_file() {
261 let source_file =
262 SourceFile::load_from_str(r#"part A() { part B() {} } "#).expect("Valid source");
263
264 let symbol = source_file.resolve().expect("expecting resolve success");
265
266 assert!(symbol.get(&"A".into()).is_some());
270 assert!(symbol.get(&"c".into()).is_none());
271
272 assert!(symbol.search(&"A".into()).is_some());
273 assert!(symbol.search(&"A::B".into()).is_some());
274 assert!(symbol.search(&"A::B::C".into()).is_none());
275
276 log::trace!("Symbol symbol:\n{symbol}");
282
283 let b = symbol.search(&"A::B".into()).expect("cant find symbol");
284 assert!(b.search(&"A".into()).is_none());
285
286 log::trace!("{symbol}");
289}