1use crate::{
5 builtin::*, diag::*, eval::*, model::*, rc::*, resolve::*, syntax::*, tree_display::*,
6};
7
8pub trait Grant<T> {
10 fn grant(&mut self, t: &T) -> EvalResult<()>;
12}
13
14pub struct Context {
25 symbol_table: SymbolTable,
27 diag_handler: DiagHandler,
29 output: Box<dyn Output>,
31 exporters: ExporterRegistry,
33 importers: ImporterRegistry,
35}
36
37impl Context {
38 pub fn new(
46 root: Identifier,
47 symbols: SymbolMap,
48 sources: Sources,
49 output: Box<dyn Output>,
50 ) -> Self {
51 log::debug!("Creating Context");
52
53 Self {
55 symbol_table: SymbolTable::new(root, symbols, sources).expect("unknown root id"),
56 output,
57 diag_handler: Default::default(),
58 exporters: ExporterRegistry::default(),
59 importers: ImporterRegistry::default(),
60 }
61 }
62
63 pub fn current_symbol(&self) -> Symbol {
65 self.symbol_table
66 .stack
67 .current_symbol()
68 .expect("Some symbol")
69 }
70
71 pub fn from_source(
78 root: impl AsRef<std::path::Path> + std::fmt::Debug,
79 builtin: Symbol,
80 search_paths: &[std::path::PathBuf],
81 ) -> EvalResult<Self> {
82 let root = SourceFile::load(root)?;
83 let root_id = root.id();
84 let sources = Sources::load(root, search_paths)?;
85 let mut symbols = sources.resolve()?;
86 symbols.insert(Identifier::no_ref("__builtin"), builtin);
87 Ok(Self::new(root_id, symbols, sources, Box::new(Stdout)))
88 }
89
90 pub fn output(&self) -> Option<String> {
92 self.output.output()
93 }
94
95 pub fn print(&mut self, what: String) {
97 self.output.print(what).expect("could not write to output");
98 }
99
100 pub fn locate(&self, referrer: &impl SrcReferrer) -> EvalResult<String> {
102 Ok(format!(
103 "{}:{}",
104 self.get_by_hash(referrer.src_ref().source_hash())?
105 .filename_as_str(),
106 referrer.src_ref()
107 ))
108 }
109
110 pub fn source_code(&self, referrer: &impl SrcReferrer) -> EvalResult<String> {
112 Ok(referrer
113 .src_ref()
114 .source_slice(&self.get_by_hash(referrer.src_ref().source_hash())?.source)
115 .to_string())
116 }
117
118 pub fn eval(&mut self) -> EvalResult<Model> {
120 let source_file = match &self.symbol_table.root.borrow().def {
121 SymbolDefinition::SourceFile(source_file) => source_file.clone(),
122 _ => todo!(),
123 };
124 source_file.eval(self)
125 }
126
127 pub fn root(&self) -> &Symbol {
129 &self.symbol_table.root
130 }
131
132 pub fn scope<T>(&mut self, stack_frame: StackFrame, f: impl FnOnce(&mut Context) -> T) -> T {
134 self.open(stack_frame);
135 let result = f(self);
136 self.close();
137 result
138 }
139
140 pub fn set_importers(&mut self, importers: ImporterRegistry) {
142 self.importers = importers;
143 }
144
145 pub fn exporters(&self) -> &ExporterRegistry {
147 &self.exporters
148 }
149
150 pub fn set_exporters(&mut self, exporters: ExporterRegistry) {
152 self.exporters = exporters;
153 }
154
155 pub fn search_paths(&self) -> &Vec<std::path::PathBuf> {
157 self.symbol_table.search_paths()
158 }
159
160 pub fn get_property(&self, id: &Identifier) -> EvalResult<Value> {
162 match self.get_model() {
163 Ok(model) => {
164 if let Some(value) = model.get_property(id) {
165 Ok(value.clone())
166 } else {
167 Err(EvalError::PropertyNotFound(id.clone()))
168 }
169 }
170 Err(err) => Err(err),
171 }
172 }
173
174 pub fn init_property(&self, id: Identifier, value: Value) -> EvalResult<()> {
178 match self.get_model() {
179 Ok(model) => {
180 if let Some(previous_value) = model.borrow_mut().set_property(id.clone(), value) {
181 if !previous_value.is_invalid() {
182 return Err(EvalError::ValueAlreadyInitialized(
183 id.clone(),
184 previous_value,
185 id.src_ref(),
186 ));
187 }
188 }
189 Ok(())
190 }
191 Err(err) => Err(err),
192 }
193 }
194
195 pub fn is_init(&mut self) -> bool {
197 matches!(
198 self.symbol_table.stack.current_frame(),
199 Some(StackFrame::Init(_))
200 )
201 }
202
203 fn lookup_property(&self, name: &QualifiedName) -> EvalResult<Symbol> {
205 match name.single_identifier() {
206 Some(id) => match self.get_property(id) {
207 Ok(value) => {
208 log::debug!(
209 "{found} property '{name:?}'",
210 found = crate::mark!(FOUND_INTERIM)
211 );
212 Ok(Symbol::new(
213 SymbolDefinition::Constant(Visibility::Public, id.clone(), value),
214 None,
215 ))
216 }
217 Err(err) => {
218 log::warn!(
219 "{not_found} Property '{name:?}'",
220 not_found = crate::mark!(NOT_FOUND_INTERIM)
221 );
222 Err(err)
223 }
224 },
225 None => {
226 log::debug!(
227 "{not_found} Property '{name:?}'",
228 not_found = crate::mark!(NOT_FOUND_INTERIM)
229 );
230 Err(EvalError::SymbolNotFound(name.clone()))
231 }
232 }
233 }
234}
235
236impl Locals for Context {
237 fn set_local_value(&mut self, id: Identifier, value: Value) -> EvalResult<()> {
238 self.symbol_table.set_local_value(id, value)
239 }
240
241 fn get_local_value(&self, id: &Identifier) -> EvalResult<Value> {
242 self.symbol_table.get_local_value(id)
243 }
244
245 fn open(&mut self, frame: StackFrame) {
246 self.symbol_table.open(frame);
247 }
248
249 fn close(&mut self) {
250 self.symbol_table.close();
251 }
252
253 fn fetch(&self, id: &Identifier) -> EvalResult<Symbol> {
254 self.symbol_table.fetch(id)
255 }
256
257 fn get_model(&self) -> EvalResult<Model> {
258 self.symbol_table.get_model()
259 }
260
261 fn current_name(&self) -> QualifiedName {
262 self.symbol_table.current_name()
263 }
264}
265
266impl Default for Context {
267 fn default() -> Self {
268 Self {
269 symbol_table: Default::default(),
270 diag_handler: Default::default(),
271 output: Box::new(Stdout),
272 exporters: Default::default(),
273 importers: Default::default(),
274 }
275 }
276}
277
278impl Lookup for Context {
279 fn lookup(&mut self, name: &QualifiedName) -> EvalResult<Symbol> {
280 log::debug!("Lookup symbol or property '{name}'");
281 let symbol = self.symbol_table.lookup(name);
282 let property = self.lookup_property(name);
283
284 match (&symbol, &property) {
285 (Ok(_), Err(_)) => {
286 log::debug!(
287 "{found} symbol '{name:?}'",
288 found = crate::mark!(FOUND_FINAL)
289 );
290 symbol
291 }
292 (Err(_), Ok(_)) => {
293 log::debug!(
294 "{found} property '{name:?}'",
295 found = crate::mark!(FOUND_FINAL)
296 );
297 property
298 }
299 (Ok(symbol), Ok(property)) => {
300 log::debug!(
301 "{ambiguous} symbol '{name:?}' in {symbol} and {property}:\n{self}",
302 ambiguous = crate::mark!(AMBIGUOUS),
303 );
304 Err(EvalError::AmbiguousProperty(
305 symbol.full_name(),
306 property.id(),
307 ))
308 }
309 (Err(_), Err(_)) => {
311 log::debug!(
312 "{not_found} symbol or property '{name:?}'",
313 not_found = crate::mark!(NOT_FOUND)
314 );
315 symbol
316 }
317 }
318 }
319}
320
321impl Diag for Context {
322 fn fmt_diagnosis(&self, f: &mut dyn std::fmt::Write) -> std::fmt::Result {
323 self.diag_handler.pretty_print(f, &self.symbol_table)
324 }
325
326 fn error_count(&self) -> u32 {
327 self.diag_handler.error_count()
328 }
329
330 fn error_lines(&self) -> std::collections::HashSet<usize> {
331 self.diag_handler.error_lines()
332 }
333
334 fn warning_lines(&self) -> std::collections::HashSet<usize> {
335 self.diag_handler.warning_lines()
336 }
337}
338
339impl Context {
340 pub fn use_symbol(
342 &mut self,
343 visibility: Visibility,
344 name: &QualifiedName,
345 id: Option<Identifier>,
346 ) -> EvalResult<Symbol> {
347 self.symbol_table
348 .use_symbol(visibility, name, id, &self.current_name())
349 }
350
351 pub fn use_symbols_of(
353 &mut self,
354 visibility: Visibility,
355 name: &QualifiedName,
356 ) -> EvalResult<Symbol> {
357 self.symbol_table
358 .use_symbols_of(visibility, name, &self.current_name())
359 }
360}
361
362impl PushDiag for Context {
363 fn push_diag(&mut self, diag: Diagnostic) -> EvalResult<()> {
364 let result = self.diag_handler.push_diag(diag);
365 log::trace!("Error Context:\n{self}");
366 result
367 }
368}
369
370impl GetSourceByHash for Context {
371 fn get_by_hash(&self, hash: u64) -> ResolveResult<Rc<SourceFile>> {
372 self.symbol_table.get_by_hash(hash)
373 }
374}
375
376impl std::fmt::Display for Context {
377 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
378 if let Ok(model) = self.get_model() {
379 write!(f, "\nModel:\n")?;
380 model.tree_print(f, 4.into())?;
381 }
382 if self.has_errors() {
383 writeln!(f, "{}\nErrors:", self.symbol_table)?;
384 self.diag_handler.pretty_print(f, &self.symbol_table)?;
385 } else {
386 write!(f, "{}", self.symbol_table)?;
387 }
388 Ok(())
389 }
390}
391
392impl ImporterRegistryAccess for Context {
393 type Error = EvalError;
394
395 fn import(
396 &mut self,
397 arg_map: &Tuple,
398 search_paths: &[std::path::PathBuf],
399 ) -> Result<Value, Self::Error> {
400 match self.importers.import(arg_map, search_paths) {
401 Ok(value) => Ok(value),
402 Err(err) => {
403 self.error(arg_map, err)?;
404 Ok(Value::None)
405 }
406 }
407 }
408}
409
410impl ExporterAccess for Context {
411 fn exporter_by_id(&self, id: &crate::Id) -> Result<Rc<dyn Exporter>, ExportError> {
412 self.exporters.exporter_by_id(id)
413 }
414
415 fn exporter_by_filename(
416 &self,
417 filename: &std::path::Path,
418 ) -> Result<Rc<dyn Exporter>, ExportError> {
419 self.exporters.exporter_by_filename(filename)
420 }
421}
422
423impl Grant<WorkbenchDefinition> for Context {
424 fn grant(&mut self, statement: &WorkbenchDefinition) -> EvalResult<()> {
425 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
426 matches!(
427 stack_frame,
428 StackFrame::Source(_, _) | StackFrame::Module(_, _)
429 )
430 } else {
431 false
432 };
433 if granted {
434 Ok(())
435 } else {
436 self.error(
437 statement,
438 EvalError::StatementNotSupported(statement.kind.as_str()),
439 )
440 }
441 }
442}
443
444impl Grant<ModuleDefinition> for Context {
445 fn grant(&mut self, statement: &ModuleDefinition) -> EvalResult<()> {
446 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
447 matches!(
448 stack_frame,
449 StackFrame::Source(_, _) | StackFrame::Module(_, _)
450 )
451 } else {
452 false
453 };
454 if granted {
455 Ok(())
456 } else {
457 self.error(statement, EvalError::StatementNotSupported("Module"))
458 }
459 }
460}
461
462impl Grant<FunctionDefinition> for Context {
463 fn grant(&mut self, statement: &FunctionDefinition) -> EvalResult<()> {
464 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
465 match stack_frame {
466 StackFrame::Source(..) | StackFrame::Module(..) => true,
468 StackFrame::Workbench(..) => statement.visibility == Visibility::Private,
469 _ => false,
470 }
471 } else {
472 false
473 };
474 if granted {
475 Ok(())
476 } else {
477 self.error(statement, EvalError::StatementNotSupported("Function"))
478 }
479 }
480}
481impl Grant<InitDefinition> for Context {
482 fn grant(&mut self, statement: &InitDefinition) -> EvalResult<()> {
483 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
484 matches!(stack_frame, StackFrame::Workbench(..))
485 } else {
486 false
487 };
488 if granted {
489 Ok(())
490 } else {
491 self.error(statement, EvalError::StatementNotSupported("Init"))
492 }
493 }
494}
495
496impl Grant<UseStatement> for Context {
497 fn grant(&mut self, statement: &UseStatement) -> EvalResult<()> {
498 match (
499 &statement.visibility,
500 self.symbol_table.stack.current_frame(),
501 ) {
502 (Visibility::Private, _) => Ok(()),
503 (Visibility::Public, Some(StackFrame::Source(..) | StackFrame::Module(..))) => Ok(()),
504 _ => self.error(statement, EvalError::StatementNotSupported("Use")),
505 }
506 }
507}
508
509impl Grant<ReturnStatement> for Context {
510 fn grant(&mut self, statement: &ReturnStatement) -> EvalResult<()> {
511 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
512 matches!(stack_frame, StackFrame::Function(_))
513 } else {
514 false
515 };
516 if granted {
517 Ok(())
518 } else {
519 self.error(statement, EvalError::StatementNotSupported("Return"))
520 }
521 }
522}
523
524impl Grant<IfStatement> for Context {
525 fn grant(&mut self, statement: &IfStatement) -> EvalResult<()> {
526 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
527 matches!(
528 stack_frame,
529 StackFrame::Source(_, _)
530 | StackFrame::Workbench(_, _, _)
531 | StackFrame::Body(_)
532 | StackFrame::Function(_)
533 )
534 } else {
535 false
536 };
537 if granted {
538 Ok(())
539 } else {
540 self.error(statement, EvalError::StatementNotSupported("If"))
541 }
542 }
543}
544
545impl Grant<AssignmentStatement> for Context {
546 fn grant(&mut self, statement: &AssignmentStatement) -> EvalResult<()> {
547 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
548 match statement.assignment.qualifier {
549 Qualifier::Const => {
550 matches!(stack_frame, StackFrame::Source(..) | StackFrame::Module(..))
551 }
552 Qualifier::Value => {
553 matches!(
554 stack_frame,
555 StackFrame::Source(..)
556 | StackFrame::Module(..)
557 | StackFrame::Body(_)
558 | StackFrame::Workbench(..)
559 | StackFrame::Init(_)
560 | StackFrame::Function(_)
561 )
562 }
563 Qualifier::Prop => matches!(stack_frame, StackFrame::Workbench(..)),
564 }
565 } else {
566 false
567 };
568 if granted {
569 Ok(())
570 } else {
571 self.error(statement, EvalError::StatementNotSupported("Assignment"))
572 }
573 }
574}
575
576impl Grant<ExpressionStatement> for Context {
577 fn grant(&mut self, statement: &ExpressionStatement) -> EvalResult<()> {
578 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
579 matches!(
580 stack_frame,
581 StackFrame::Source(_, _)
582 | StackFrame::Body(_)
583 | StackFrame::Workbench(_, _, _)
584 | StackFrame::Function(_)
585 )
586 } else {
587 false
588 };
589 if granted {
590 Ok(())
591 } else {
592 self.error(statement, EvalError::StatementNotSupported("Expression"))
593 }
594 }
595}
596
597impl Grant<Marker> for Context {
598 fn grant(&mut self, statement: &Marker) -> EvalResult<()> {
599 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
600 matches!(stack_frame, StackFrame::Workbench(_, _, _))
601 } else {
602 false
603 };
604 if granted {
605 Ok(())
606 } else {
607 self.error(statement, EvalError::StatementNotSupported("Expression"))
608 }
609 }
610}
611
612impl Grant<crate::syntax::Attribute> for Context {
613 fn grant(&mut self, statement: &crate::syntax::Attribute) -> EvalResult<()> {
614 let granted = if let Some(stack_frame) = self.symbol_table.stack.current_frame() {
615 matches!(
616 stack_frame,
617 StackFrame::Source(_, _) | StackFrame::Body(_) | StackFrame::Workbench(_, _, _)
618 )
619 } else {
620 false
621 };
622 if granted {
623 Ok(())
624 } else {
625 self.error(
626 statement,
627 EvalError::StatementNotSupported("InnerAttribute"),
628 )
629 }
630 }
631}