1use crate::{
2 collections::{HashMap, HashSet},
3 module::{
4 ModuleAssociatedFn, ModuleFn, ModuleInternalEnum, ModuleMacro, ModuleType, ModuleUnitType,
5 },
6 CompileMeta, CompileMetaKind, CompileMetaStruct, CompileMetaTuple, ComponentRef, ConstValue,
7 Hash, IntoComponent, Item, Module, Names, Protocol, RuntimeContext, Stack, StaticType,
8 TypeCheck, TypeInfo, TypeOf, VmError,
9};
10use std::{any, fmt, sync::Arc};
11
12use thiserror::Error;
13
14#[derive(Debug, Error)]
16pub enum ContextError {
17 #[error("`()` types are already present")]
19 UnitAlreadyPresent,
20 #[error("`{name}` types are already present")]
22 InternalAlreadyPresent {
23 name: &'static str,
25 },
26 #[error("conflicting meta {existing} while trying to insert {current}")]
28 ConflictingMeta {
29 current: Box<CompileMeta>,
31 existing: Box<CompileMeta>,
33 },
34 #[error("function `{signature}` ({hash}) already exists")]
36 ConflictingFunction {
37 signature: ContextSignature,
39 hash: Hash,
41 },
42 #[error("function with name `{name}` already exists")]
44 ConflictingFunctionName {
45 name: Item,
47 },
48 #[error("constant with name `{name}` already exists")]
50 ConflictingConstantName {
51 name: Item,
53 },
54 #[error("instance function `{name}` for type `{type_info}` already exists")]
56 ConflictingInstanceFunction {
57 type_info: TypeInfo,
59 name: String,
61 },
62 #[error("module `{item}` with hash `{hash}` already exists")]
64 ConflictingModule {
65 item: Item,
67 hash: Hash,
69 },
70 #[error("type `{item}` already exists `{existing}`")]
72 ConflictingType {
73 item: Item,
75 existing: TypeInfo,
77 },
78 #[error("tried to insert conflicting hash `{hash}` for `{existing}`")]
80 ConflictingTypeHash {
81 hash: Hash,
83 existing: Hash,
85 },
86 #[error("variant with `{item}` already exists")]
88 ConflictingVariant {
89 item: Item,
91 },
92 #[error("instance `{instance_type}` does not exist in module")]
95 MissingInstance {
96 instance_type: TypeInfo,
98 },
99 #[error("error when converting to constant value: {error}")]
101 ValueError {
102 error: VmError,
104 },
105}
106
107pub(crate) type Handler = dyn Fn(&mut Stack, usize) -> Result<(), VmError> + Send + Sync;
109
110pub(crate) type Macro =
112 dyn Fn(&dyn any::Any) -> Result<Box<dyn any::Any>, crate::Error> + Send + Sync;
113
114#[derive(Debug, Clone)]
116pub struct ContextTypeInfo {
117 pub type_check: TypeCheck,
121 pub item: Item,
123 pub type_hash: Hash,
125 pub type_info: TypeInfo,
127}
128
129impl fmt::Display for ContextTypeInfo {
130 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
131 write!(fmt, "{} => {}", self.item, self.type_info)?;
132 Ok(())
133 }
134}
135
136#[derive(Debug, Clone)]
138pub enum ContextSignature {
139 Function {
141 type_hash: Hash,
143 item: Item,
145 args: Option<usize>,
147 },
148 Instance {
150 type_hash: Hash,
152 item: Item,
154 name: String,
156 args: Option<usize>,
158 self_type_info: TypeInfo,
160 },
161}
162
163impl fmt::Display for ContextSignature {
164 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
165 match self {
166 Self::Function { item, args, .. } => {
167 write!(fmt, "{}(", item)?;
168
169 if let Some(args) = args {
170 let mut it = 0..*args;
171 let last = it.next_back();
172
173 for n in it {
174 write!(fmt, "#{}, ", n)?;
175 }
176
177 if let Some(n) = last {
178 write!(fmt, "#{}", n)?;
179 }
180 } else {
181 write!(fmt, "...")?;
182 }
183
184 write!(fmt, ")")?;
185 }
186 Self::Instance {
187 item,
188 name,
189 self_type_info,
190 args,
191 ..
192 } => {
193 write!(fmt, "{}::{}(self: {}", item, name, self_type_info)?;
194
195 if let Some(args) = args {
196 for n in 0..*args {
197 write!(fmt, ", #{}", n)?;
198 }
199 } else {
200 write!(fmt, ", ...")?;
201 }
202
203 write!(fmt, ")")?;
204 }
205 }
206
207 Ok(())
208 }
209}
210
211#[derive(Default)]
218pub struct Context {
219 has_default_modules: bool,
221 meta: HashMap<Item, CompileMeta>,
223 functions: HashMap<Hash, Arc<Handler>>,
225 macros: HashMap<Hash, Arc<Macro>>,
227 functions_info: HashMap<Hash, ContextSignature>,
229 types: HashMap<Hash, ContextTypeInfo>,
231 types_rev: HashMap<Hash, Hash>,
233 unit_type: Option<Hash>,
235 internal_enums: HashSet<&'static StaticType>,
237 names: Names,
239 crates: HashSet<Box<str>>,
241 constants: HashMap<Hash, ConstValue>,
243}
244
245impl Context {
246 pub fn new() -> Self {
248 Self::default()
249 }
250
251 pub fn with_config(stdio: bool) -> Result<Self, ContextError> {
256 let mut this = Self::new();
257 this.install(&crate::modules::any::module()?)?;
258 this.install(&crate::modules::bytes::module()?)?;
259 this.install(&crate::modules::char::module()?)?;
260 this.install(&crate::modules::cmp::module()?)?;
261 this.install(&crate::modules::collections::module()?)?;
262 this.install(&crate::modules::core::module()?)?;
263 this.install(&crate::modules::float::module()?)?;
264 this.install(&crate::modules::fmt::module()?)?;
265 this.install(&crate::modules::future::module()?)?;
266 this.install(&crate::modules::generator::module()?)?;
267 this.install(&crate::modules::int::module()?)?;
268 this.install(&crate::modules::io::module(stdio)?)?;
269 this.install(&crate::modules::iter::module()?)?;
270 this.install(&crate::modules::mem::module()?)?;
271 this.install(&crate::modules::object::module()?)?;
272 this.install(&crate::modules::ops::module()?)?;
273 this.install(&crate::modules::option::module()?)?;
274 this.install(&crate::modules::result::module()?)?;
275 this.install(&crate::modules::stream::module()?)?;
276 this.install(&crate::modules::string::module()?)?;
277 this.install(&crate::modules::vec::module()?)?;
278 this.has_default_modules = true;
279 Ok(this)
280 }
281
282 pub fn runtime(&self) -> RuntimeContext {
298 RuntimeContext {
299 functions: self.functions.clone(),
300 types: self.types.iter().map(|(k, t)| (*k, t.type_check)).collect(),
301 constants: self.constants.clone(),
302 }
303 }
304
305 pub fn type_check_for(&self, item: &Item) -> Option<TypeCheck> {
307 let ty = self.types.get(&Hash::type_hash(item))?;
308 Some(ty.type_check)
309 }
310
311 pub fn with_default_modules() -> Result<Self, ContextError> {
313 Self::with_config(true)
314 }
315
316 pub fn contains_crate(&self, name: &str) -> bool {
318 self.crates.contains(name)
319 }
320
321 pub fn has_default_modules(&self) -> bool {
326 self.has_default_modules
327 }
328
329 pub fn iter_components<'a, I: 'a>(
331 &'a self,
332 iter: I,
333 ) -> impl Iterator<Item = ComponentRef<'a>> + 'a
334 where
335 I: IntoIterator,
336 I::Item: IntoComponent,
337 {
338 self.names.iter_components(iter)
339 }
340
341 pub fn unit_type(&self) -> Option<Hash> {
343 self.unit_type
344 }
345
346 pub fn contains_name(&self, item: &Item) -> bool {
348 self.names.contains(item)
349 }
350
351 pub fn contains_prefix(&self, item: &Item) -> bool {
353 self.names.contains_prefix(item)
354 }
355
356 pub fn lookup(&self, hash: Hash) -> Option<&Arc<Handler>> {
358 self.functions.get(&hash)
359 }
360
361 pub fn lookup_macro(&self, hash: Hash) -> Option<&Arc<Macro>> {
363 self.macros.get(&hash)
364 }
365
366 pub fn lookup_meta(&self, name: &Item) -> Option<CompileMeta> {
368 self.meta.get(name).cloned()
369 }
370
371 pub fn iter_functions(&self) -> impl Iterator<Item = (Hash, &ContextSignature)> {
373 let mut it = self.functions_info.iter();
374
375 std::iter::from_fn(move || {
376 let (hash, signature) = it.next()?;
377 Some((*hash, signature))
378 })
379 }
380
381 pub fn iter_types(&self) -> impl Iterator<Item = (Hash, &ContextTypeInfo)> {
383 let mut it = self.types.iter();
384
385 std::iter::from_fn(move || {
386 let (hash, ty) = it.next()?;
387 Some((*hash, ty))
388 })
389 }
390
391 pub fn install(&mut self, module: &Module) -> Result<(), ContextError> {
393 if let Some(ComponentRef::Crate(name)) = module.item.first() {
394 self.crates.insert(name.into());
395 }
396
397 for (type_hash, ty) in &module.types {
398 self.install_type(&module, *type_hash, ty)?;
399 }
400
401 for (name, f) in &module.functions {
402 self.install_function(&module, name, f)?;
403 }
404
405 for (name, m) in &module.macros {
406 self.install_macro(&module, name, m)?;
407 }
408
409 for (name, m) in &module.constants {
410 self.install_constant(&module, name, m)?;
411 }
412
413 if let Some(unit_type) = &module.unit_type {
414 self.install_unit_type(&module, unit_type)?;
415 }
416
417 for internal_enum in &module.internal_enums {
418 self.install_internal_enum(module, internal_enum)?;
419 }
420
421 for (key, inst) in &module.associated_functions {
422 self.install_associated_function(
423 key.type_hash,
424 key.hash,
425 inst,
426 |instance_type, field| key.kind.hash(instance_type, field),
427 )?;
428 }
429
430 Ok(())
431 }
432
433 fn install_meta(&mut self, meta: CompileMeta) -> Result<(), ContextError> {
435 if let Some(existing) = self.meta.insert(meta.item.item.clone(), meta.clone()) {
436 return Err(ContextError::ConflictingMeta {
437 existing: Box::new(existing),
438 current: Box::new(meta),
439 });
440 }
441
442 Ok(())
443 }
444
445 fn install_type(
447 &mut self,
448 module: &Module,
449 type_hash: Hash,
450 ty: &ModuleType,
451 ) -> Result<(), ContextError> {
452 let item = module.item.extended(&*ty.name);
453 let hash = Hash::type_hash(&item);
454
455 self.install_type_info(
456 hash,
457 ContextTypeInfo {
458 type_check: TypeCheck::Type(type_hash),
459 item: item.clone(),
460 type_hash,
461 type_info: ty.type_info.clone(),
462 },
463 )?;
464
465 self.install_meta(CompileMeta {
466 item: Arc::new(item.into()),
467 kind: CompileMetaKind::Struct {
468 type_hash,
469 object: CompileMetaStruct {
470 fields: Default::default(),
471 },
472 },
473 source: None,
474 })?;
475
476 Ok(())
477 }
478
479 fn install_type_info(&mut self, hash: Hash, info: ContextTypeInfo) -> Result<(), ContextError> {
480 self.names.insert(&info.item);
481
482 if let Some(existing) = self.types_rev.insert(info.type_hash, hash) {
484 return Err(ContextError::ConflictingTypeHash { hash, existing });
485 }
486
487 self.constants.insert(
488 Hash::instance_function(info.type_hash, Protocol::INTO_TYPE_NAME),
489 ConstValue::String(info.item.to_string()),
490 );
491
492 if let Some(existing) = self.types.insert(hash, info) {
493 return Err(ContextError::ConflictingType {
494 item: existing.item,
495 existing: existing.type_info,
496 });
497 }
498
499 Ok(())
500 }
501
502 fn install_function(
504 &mut self,
505 module: &Module,
506 item: &Item,
507 f: &ModuleFn,
508 ) -> Result<(), ContextError> {
509 let item = module.item.join(item);
510 self.names.insert(&item);
511
512 let hash = Hash::type_hash(&item);
513
514 let signature = ContextSignature::Function {
515 type_hash: hash,
516 item: item.clone(),
517 args: f.args,
518 };
519
520 if let Some(old) = self.functions_info.insert(hash, signature) {
521 return Err(ContextError::ConflictingFunction {
522 signature: old,
523 hash,
524 });
525 }
526
527 self.constants.insert(
528 Hash::instance_function(hash, Protocol::INTO_TYPE_NAME),
529 ConstValue::String(item.to_string()),
530 );
531
532 self.functions.insert(hash, f.handler.clone());
533 self.meta.insert(
534 item.clone(),
535 CompileMeta {
536 item: Arc::new(item.into()),
537 kind: CompileMetaKind::Function {
538 type_hash: hash,
539 is_test: false,
540 },
541 source: None,
542 },
543 );
544
545 Ok(())
546 }
547
548 fn install_macro(
550 &mut self,
551 module: &Module,
552 item: &Item,
553 m: &ModuleMacro,
554 ) -> Result<(), ContextError> {
555 let item = module.item.join(item);
556
557 self.names.insert(&item);
558
559 let hash = Hash::type_hash(&item);
560
561 self.macros.insert(hash, m.handler.clone());
562 Ok(())
563 }
564
565 fn install_constant(
567 &mut self,
568 module: &Module,
569 item: &Item,
570 v: &ConstValue,
571 ) -> Result<(), ContextError> {
572 let item = module.item.join(item);
573
574 self.names.insert(&item);
575
576 let hash = Hash::type_hash(&item);
577
578 self.constants.insert(hash, v.clone());
579
580 self.meta.insert(
581 item.clone(),
582 CompileMeta {
583 item: Arc::new(item.into()),
584 kind: CompileMetaKind::Const {
585 const_value: v.clone(),
586 },
587 source: None,
588 },
589 );
590 Ok(())
591 }
592
593 fn install_associated_function(
594 &mut self,
595 type_hash: Hash,
596 hash: Hash,
597 assoc: &ModuleAssociatedFn,
598 hash_fn: impl FnOnce(Hash, Hash) -> Hash,
599 ) -> Result<(), ContextError> {
600 let info = match self
601 .types_rev
602 .get(&type_hash)
603 .and_then(|hash| self.types.get(&hash))
604 {
605 Some(info) => info,
606 None => {
607 return Err(ContextError::MissingInstance {
608 instance_type: assoc.type_info.clone(),
609 });
610 }
611 };
612
613 let hash = hash_fn(type_hash, hash);
614
615 let signature = ContextSignature::Instance {
616 type_hash,
617 item: info.item.clone(),
618 name: assoc.name.clone(),
619 args: assoc.args,
620 self_type_info: info.type_info.clone(),
621 };
622 let item = info.item.extended(&assoc.name);
623
624 self.constants.insert(
625 Hash::instance_function(hash, Protocol::INTO_TYPE_NAME),
626 ConstValue::String(item.to_string()),
627 );
628
629 if let Some(old) = self.functions_info.insert(hash, signature) {
630 return Err(ContextError::ConflictingFunction {
631 signature: old,
632 hash,
633 });
634 }
635 self.meta.insert(
636 item.clone(),
637 CompileMeta {
638 item: Arc::new(item.into()),
639 kind: CompileMetaKind::Function {
640 type_hash: hash,
641 is_test: false,
642 },
643 source: None,
644 },
645 );
646
647 self.functions.insert(hash, assoc.handler.clone());
648 Ok(())
649 }
650
651 fn install_unit_type(
653 &mut self,
654 module: &Module,
655 unit_type: &ModuleUnitType,
656 ) -> Result<(), ContextError> {
657 if self.unit_type.is_some() {
658 return Err(ContextError::UnitAlreadyPresent);
659 }
660
661 let item = module.item.extended(&*unit_type.name);
662 let hash = Hash::type_hash(&item);
663 self.unit_type = Some(Hash::type_hash(&item));
664 self.add_internal_tuple(None, item.clone(), 0, || ())?;
665
666 self.install_type_info(
667 hash,
668 ContextTypeInfo {
669 type_check: TypeCheck::Unit,
670 item,
671 type_hash: crate::UNIT_TYPE.hash,
672 type_info: TypeInfo::StaticType(crate::UNIT_TYPE),
673 },
674 )?;
675
676 Ok(())
677 }
678
679 fn install_internal_enum(
681 &mut self,
682 module: &Module,
683 internal_enum: &ModuleInternalEnum,
684 ) -> Result<(), ContextError> {
685 if !self.internal_enums.insert(internal_enum.static_type) {
686 return Err(ContextError::InternalAlreadyPresent {
687 name: internal_enum.name,
688 });
689 }
690
691 let enum_item = module.item.join(&internal_enum.base_type);
692 let enum_hash = Hash::type_hash(&enum_item);
693
694 self.install_meta(CompileMeta {
695 item: Arc::new(enum_item.clone().into()),
696 kind: CompileMetaKind::Enum {
697 type_hash: internal_enum.static_type.hash,
698 },
699 source: None,
700 })?;
701
702 self.install_type_info(
703 enum_hash,
704 ContextTypeInfo {
705 type_check: TypeCheck::Type(internal_enum.static_type.hash),
706 item: enum_item.clone(),
707 type_hash: internal_enum.static_type.hash,
708 type_info: TypeInfo::StaticType(internal_enum.static_type),
709 },
710 )?;
711
712 for variant in &internal_enum.variants {
713 let item = enum_item.extended(variant.name);
714 let hash = Hash::type_hash(&item);
715
716 self.install_type_info(
717 hash,
718 ContextTypeInfo {
719 type_check: variant.type_check,
720 item: item.clone(),
721 type_hash: hash,
722 type_info: TypeInfo::StaticType(internal_enum.static_type),
723 },
724 )?;
725
726 self.install_meta(CompileMeta {
727 item: Arc::new(item.clone().into()),
728 kind: CompileMetaKind::TupleVariant {
729 type_hash: variant.type_hash,
730 enum_item: enum_item.clone(),
731 tuple: CompileMetaTuple {
732 args: variant.args,
733 hash,
734 },
735 },
736 source: None,
737 })?;
738
739 let signature = ContextSignature::Function {
740 type_hash: variant.type_hash,
741 item,
742 args: Some(variant.args),
743 };
744
745 if let Some(old) = self.functions_info.insert(hash, signature) {
746 return Err(ContextError::ConflictingFunction {
747 signature: old,
748 hash,
749 });
750 }
751 self.functions.insert(hash, variant.constructor.clone());
752 }
753
754 Ok(())
755 }
756
757 fn add_internal_tuple<C, Args>(
759 &mut self,
760 enum_item: Option<Item>,
761 item: Item,
762 args: usize,
763 constructor: C,
764 ) -> Result<(), ContextError>
765 where
766 C: crate::module::Function<Args>,
767 C::Return: TypeOf,
768 {
769 let type_hash = <C::Return as TypeOf>::type_hash();
770 let hash = Hash::type_hash(&item);
771
772 let tuple = CompileMetaTuple { args, hash };
773
774 let meta = match enum_item {
775 Some(enum_item) => CompileMeta {
776 item: Arc::new(item.clone().into()),
777 kind: CompileMetaKind::TupleVariant {
778 type_hash,
779 enum_item,
780 tuple,
781 },
782 source: None,
783 },
784 None => CompileMeta {
785 item: Arc::new(item.clone().into()),
786 kind: CompileMetaKind::TupleStruct { type_hash, tuple },
787 source: None,
788 },
789 };
790
791 self.install_meta(meta)?;
792
793 let constructor: Arc<Handler> =
794 Arc::new(move |stack, args| constructor.fn_call(stack, args));
795
796 self.constants.insert(
797 Hash::instance_function(type_hash, Protocol::INTO_TYPE_NAME),
798 ConstValue::String(item.to_string()),
799 );
800
801 let signature = ContextSignature::Function {
802 type_hash,
803 item,
804 args: Some(args),
805 };
806
807 if let Some(old) = self.functions_info.insert(hash, signature) {
808 return Err(ContextError::ConflictingFunction {
809 signature: old,
810 hash,
811 });
812 }
813 self.functions.insert(hash, constructor);
814 Ok(())
815 }
816}
817
818impl fmt::Debug for Context {
819 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820 write!(f, "Context")
821 }
822}
823
824#[cfg(test)]
825static_assertions::assert_impl_all!(Context: Send, Sync);