1use crate::{
2 collections::HashMap,
3 runtime::memory::Memory,
4 shared_values::{
5 shared_container::SharedContainer,
6 shared_type_container::{NominalTypeDeclaration, SharedTypeContainer},
7 },
8 types::definition::TypeDefinition,
9 values::{
10 core_value::CoreValue,
11 core_values::{
12 callable::{CallableBody, CallableKind, CallableSignature},
13 decimal::typed_decimal::DecimalTypeVariant,
14 integer::typed_integer::IntegerTypeVariant,
15 map::Map,
16 r#type::Type,
17 },
18 value::Value,
19 value_container::ValueContainer,
20 },
21};
22
23use crate::{
24 prelude::*,
25 shared_values::{
26 pointer::{Pointer, PointerReferenceMutability},
27 pointer_address::{PointerAddress, ReferencedPointerAddress},
28 },
29 values::core_values::r#type::TypeMetadata,
30};
31use core::{cell::RefCell, iter::once, result::Result};
32use datex_macros_internal::LibTypeString;
33use log::info;
34use strum::IntoEnumIterator;
35
36type CoreLibTypes = HashMap<CoreLibPointerId, Type>;
37type CoreLibVals = HashMap<CoreLibPointerId, ValueContainer>;
38
39#[cfg_attr(not(feature = "embassy_runtime"), thread_local)]
40pub static mut CORE_LIB_TYPES: Option<CoreLibTypes> = None;
41
42#[cfg_attr(not(feature = "embassy_runtime"), thread_local)]
43pub static mut CORE_LIB_VALS: Option<CoreLibVals> = None;
44
45fn with_full_core_lib<R>(
46 handler: impl FnOnce(&CoreLibTypes, &CoreLibVals) -> R,
47) -> R {
48 unsafe {
49 if CORE_LIB_TYPES.is_none() {
50 CORE_LIB_TYPES.replace(create_core_lib_types());
51 }
52 if CORE_LIB_VALS.is_none() {
53 CORE_LIB_VALS.replace(create_core_lib_vals());
54 }
55 handler(
56 CORE_LIB_TYPES.as_ref().unwrap_unchecked(),
57 CORE_LIB_VALS.as_ref().unwrap_unchecked(),
58 )
59 }
60}
61
62fn with_core_lib_types<R>(handler: impl FnOnce(&CoreLibTypes) -> R) -> R {
63 unsafe {
64 if CORE_LIB_TYPES.is_none() {
65 CORE_LIB_TYPES.replace(create_core_lib_types());
66 }
67 handler(CORE_LIB_TYPES.as_ref().unwrap_unchecked())
68 }
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Hash, LibTypeString)]
72pub enum CoreLibPointerId {
73 Core, Type, Null, Boolean, Integer(Option<IntegerTypeVariant>), Decimal(Option<DecimalTypeVariant>), Text, Endpoint, List, Map, Callable, Unit, Never, Unknown, Print, Range,
89}
90
91impl CoreLibPointerId {
92 const INTEGER_BASE: u16 = 100;
93 const DECIMAL_BASE: u16 = 300;
94
95 pub fn to_u16(&self) -> u16 {
96 match self {
97 CoreLibPointerId::Core => 0,
98 CoreLibPointerId::Null => 1,
99 CoreLibPointerId::Type => 2,
100 CoreLibPointerId::Boolean => 3,
101 CoreLibPointerId::Callable => 5,
102 CoreLibPointerId::Endpoint => 7,
103 CoreLibPointerId::Text => 8,
104 CoreLibPointerId::List => 9,
105 CoreLibPointerId::Unit => 11,
106 CoreLibPointerId::Map => 12,
107 CoreLibPointerId::Never => 13,
108 CoreLibPointerId::Unknown => 14,
109 CoreLibPointerId::Print => 15,
110 CoreLibPointerId::Range => 16,
111 CoreLibPointerId::Integer(None) => Self::INTEGER_BASE,
112 CoreLibPointerId::Integer(Some(v)) => {
113 let v: u8 = (*v).into();
114 CoreLibPointerId::Integer(None).to_u16() + v as u16
115 }
116 CoreLibPointerId::Decimal(None) => Self::DECIMAL_BASE,
117 CoreLibPointerId::Decimal(Some(v)) => {
118 let v: u8 = (*v).into();
119 CoreLibPointerId::Decimal(None).to_u16() + v as u16
120 }
121 }
122 }
123
124 pub fn from_u16(id: u16) -> Option<Self> {
125 match id {
126 0 => Some(CoreLibPointerId::Core),
127 1 => Some(CoreLibPointerId::Null),
128 2 => Some(CoreLibPointerId::Type),
129 3 => Some(CoreLibPointerId::Boolean),
130 5 => Some(CoreLibPointerId::Callable),
131 7 => Some(CoreLibPointerId::Endpoint),
132 8 => Some(CoreLibPointerId::Text),
133 9 => Some(CoreLibPointerId::List),
134 11 => Some(CoreLibPointerId::Unit),
135 12 => Some(CoreLibPointerId::Map),
136 13 => Some(CoreLibPointerId::Never),
137 14 => Some(CoreLibPointerId::Unknown),
138 15 => Some(CoreLibPointerId::Print),
139 16 => Some(CoreLibPointerId::Range),
140
141 Self::INTEGER_BASE => Some(CoreLibPointerId::Integer(None)),
142 n if (Self::INTEGER_BASE + 1..Self::DECIMAL_BASE).contains(&n) => {
143 IntegerTypeVariant::try_from((n - Self::INTEGER_BASE) as u8)
144 .ok()
145 .map(|v| CoreLibPointerId::Integer(Some(v)))
146 }
147
148 Self::DECIMAL_BASE => Some(CoreLibPointerId::Decimal(None)),
149 n if n > Self::DECIMAL_BASE => {
150 DecimalTypeVariant::try_from((n - Self::DECIMAL_BASE) as u8)
151 .ok()
152 .map(|v| CoreLibPointerId::Decimal(Some(v)))
153 }
154
155 _ => None,
156 }
157 }
158}
159
160impl From<CoreLibPointerId> for PointerAddress {
161 fn from(id: CoreLibPointerId) -> Self {
162 PointerAddress::Referenced(ReferencedPointerAddress::from(&id))
163 }
164}
165
166impl From<&CoreLibPointerId> for ReferencedPointerAddress {
167 fn from(id: &CoreLibPointerId) -> Self {
168 let id_bytes: [u8; 3] =
169 (id.to_u16() as u32).to_le_bytes()[0..3].try_into().unwrap();
170 ReferencedPointerAddress::Internal(id_bytes)
171 }
172}
173
174impl TryFrom<&PointerAddress> for CoreLibPointerId {
175 type Error = String;
176 fn try_from(address: &PointerAddress) -> Result<Self, Self::Error> {
177 match address {
178 PointerAddress::Referenced(ReferencedPointerAddress::Internal(
179 id_bytes,
180 )) => {
181 let mut id_array = [0u8; 4];
182 id_array[0..3].copy_from_slice(id_bytes);
183 let id = u32::from_le_bytes(id_array);
184 match CoreLibPointerId::from_u16(id as u16) {
185 Some(core_id) => Ok(core_id),
186 None => Err("Invalid CoreLibPointerId".to_string()),
187 }
188 }
189 e => Err(format!(
190 "CoreLibPointerId can only be created from Internal PointerAddress, got: {:?}",
191 e
192 )),
193 }
194 }
195}
196
197pub fn get_core_lib_type(id: impl Into<CoreLibPointerId>) -> Type {
198 with_core_lib_types(|core_lib_types| {
199 core_lib_types.get(&id.into()).unwrap().clone()
200 })
201}
202
203pub fn get_core_lib_type_reference(
204 id: impl Into<CoreLibPointerId>,
205) -> Rc<RefCell<SharedTypeContainer>> {
206 let type_container = get_core_lib_type(id);
207 match type_container.type_definition {
208 TypeDefinition::SharedReference(tr) => tr,
209 _ => core::panic!("Core lib type is not a TypeReference"),
210 }
211}
212
213pub fn get_core_lib_value(
215 id: impl Into<CoreLibPointerId>,
216) -> Option<ValueContainer> {
217 let id = id.into();
218 with_full_core_lib(|core_lib_types, core_lib_values| {
219 if let Some(ty) = core_lib_types.get(&id) {
221 match &ty.type_definition {
222 TypeDefinition::SharedReference(tr) => Some(
223 ValueContainer::Shared(SharedContainer::Type(tr.clone())),
224 ),
225 _ => core::panic!("Core lib type is not a TypeReference"),
226 }
227 } else {
228 core_lib_values.get(&id).cloned()
229 }
230 })
231}
232
233pub fn get_core_lib_type_definition(
234 id: impl Into<CoreLibPointerId>,
235) -> TypeDefinition {
236 get_core_lib_type(id).type_definition
237}
238
239fn has_core_lib_type<T>(id: T) -> bool
240where
241 T: Into<CoreLibPointerId>,
242{
243 with_core_lib_types(|core_lib_types| {
244 core_lib_types.contains_key(&id.into())
245 })
246}
247
248pub fn load_core_lib(memory: &mut Memory) {
250 with_full_core_lib(|core_lib_types, core_lib_values| {
251 let mut types_structure = core_lib_types
252 .values()
253 .map(|ty| match &ty.type_definition {
254 TypeDefinition::SharedReference(type_reference) => {
255 let name = type_reference
256 .borrow()
257 .nominal_type_declaration
258 .as_ref()
259 .unwrap()
260 .to_string();
261 let reference =
262 SharedContainer::Type(type_reference.clone());
263 memory.register_shared_container(&reference);
264 (name, ValueContainer::Shared(reference))
265 }
266 _ => core::panic!("Core lib type is not a TypeReference"),
267 })
268 .collect::<Vec<(String, ValueContainer)>>();
269
270 for (name, val) in core_lib_values.iter() {
272 let name = name.to_string();
273 types_structure.push((name, val.clone()));
274 }
275
276 let core_struct = SharedContainer::boxed(
279 Map::from_iter(types_structure),
280 Pointer::new_reference(
281 ReferencedPointerAddress::from(&CoreLibPointerId::Core),
282 PointerReferenceMutability::Immutable,
283 ),
284 );
285 memory.register_shared_container(&core_struct);
286 });
287}
288
289pub fn create_core_lib_types() -> HashMap<CoreLibPointerId, Type> {
292 let integer = integer();
293 let decimal = decimal();
294 vec![
295 ty(),
296 text(),
297 list(),
298 boolean(),
299 endpoint(),
300 unit(),
301 never(),
302 unknown(),
303 map(),
304 null(),
305 callable(),
306 range(),
307 ]
308 .into_iter()
309 .chain(once(integer.clone()))
310 .chain(
311 IntegerTypeVariant::iter()
312 .map(|variant| integer_variant(integer.1.clone(), variant)),
313 )
314 .chain(once(decimal.clone()))
315 .chain(
316 DecimalTypeVariant::iter()
317 .map(|variant| decimal_variant(decimal.1.clone(), variant)),
318 )
319 .collect::<HashMap<CoreLibPointerId, Type>>()
320}
321
322pub fn create_core_lib_vals() -> HashMap<CoreLibPointerId, ValueContainer> {
323 vec![print()]
324 .into_iter()
325 .collect::<HashMap<CoreLibPointerId, ValueContainer>>()
326}
327
328type CoreLibTypeDefinition = (CoreLibPointerId, Type);
329pub fn ty() -> CoreLibTypeDefinition {
330 create_core_type("type", None, None, CoreLibPointerId::Type)
331}
332pub fn null() -> CoreLibTypeDefinition {
333 create_core_type("null", None, None, CoreLibPointerId::Null)
334}
335pub fn list() -> CoreLibTypeDefinition {
336 create_core_type("List", None, None, CoreLibPointerId::List)
337}
338pub fn map() -> CoreLibTypeDefinition {
339 create_core_type("Map", None, None, CoreLibPointerId::Map)
340}
341
342pub fn unit() -> CoreLibTypeDefinition {
343 create_core_type("Unit", None, None, CoreLibPointerId::Unit)
344}
345
346pub fn never() -> CoreLibTypeDefinition {
347 create_core_type("never", None, None, CoreLibPointerId::Never)
348}
349
350pub fn unknown() -> CoreLibTypeDefinition {
351 create_core_type("unknown", None, None, CoreLibPointerId::Unknown)
352}
353
354pub fn boolean() -> CoreLibTypeDefinition {
355 create_core_type("boolean", None, None, CoreLibPointerId::Boolean)
356}
357
358pub fn decimal() -> CoreLibTypeDefinition {
359 create_core_type("decimal", None, None, CoreLibPointerId::Decimal(None))
360}
361
362pub fn callable() -> CoreLibTypeDefinition {
363 create_core_type("Callable", None, None, CoreLibPointerId::Callable)
364}
365
366pub fn range() -> CoreLibTypeDefinition {
367 create_core_type("range", None, None, CoreLibPointerId::Range)
368}
369
370pub fn decimal_variant(
371 base_type: Type,
372 variant: DecimalTypeVariant,
373) -> CoreLibTypeDefinition {
374 let variant_name = variant.as_ref().to_string();
375 create_core_type(
376 "decimal",
377 Some(variant_name),
378 Some(base_type),
379 CoreLibPointerId::Decimal(Some(variant)),
380 )
381}
382pub fn endpoint() -> CoreLibTypeDefinition {
383 create_core_type("endpoint", None, None, CoreLibPointerId::Endpoint)
384}
385
386pub fn text() -> CoreLibTypeDefinition {
387 create_core_type("text", None, None, CoreLibPointerId::Text)
388}
389
390pub fn integer() -> CoreLibTypeDefinition {
391 create_core_type("integer", None, None, CoreLibPointerId::Integer(None))
392}
393
394pub fn integer_variant(
395 base_type: Type,
396 variant: IntegerTypeVariant,
397) -> CoreLibTypeDefinition {
398 let variant_name = variant.as_ref().to_string();
399 create_core_type(
400 "integer",
401 Some(variant_name),
402 Some(base_type),
403 CoreLibPointerId::Integer(Some(variant)),
404 )
405}
406
407pub fn print() -> (CoreLibPointerId, ValueContainer) {
408 (
409 CoreLibPointerId::Print,
410 ValueContainer::Local(Value::callable(
411 Some("print".to_string()),
412 CallableSignature {
413 kind: CallableKind::Function,
414 parameter_types: vec![],
415 rest_parameter_type: Some((
416 Some("values".to_string()),
417 Box::new(Type::unknown()),
418 )),
419 return_type: None,
420 yeet_type: None,
421 },
422 CallableBody::Native(|mut args: &[ValueContainer]| {
423 let mut output = String::new();
426
427 if let Some(ValueContainer::Local(Value {
429 inner: CoreValue::Text(text),
430 ..
431 })) = args.first()
432 {
433 output.push_str(&text.0);
434 args = &args[1..];
436 if !args.is_empty() {
438 output.push(' ');
439 }
440 }
441
442 #[cfg(feature = "decompiler")]
443 let args_string = args
444 .iter()
445 .map(|v| {
446 crate::decompiler::decompile_value(
447 v,
448 crate::decompiler::DecompileOptions::colorized(),
449 )
450 })
451 .collect::<Vec<_>>()
452 .join(" ");
453 #[cfg(not(feature = "decompiler"))]
454 let args_string = args
455 .iter()
456 .map(|v| v.to_string())
457 .collect::<Vec<_>>()
458 .join(" ");
459 output.push_str(&args_string);
460
461 #[cfg(feature = "std")]
462 println!("[PRINT] {}", output);
463 info!("[PRINT] {}", output);
464 Ok(None)
465 }),
466 )),
467 )
468}
469
470fn create_core_type(
472 name: &str,
473 variant: Option<String>,
474 base_type: Option<Type>,
475 pointer_id: CoreLibPointerId,
476) -> CoreLibTypeDefinition {
477 let base_type_ref = match base_type {
478 Some(Type {
479 type_definition: TypeDefinition::SharedReference(reference),
480 ..
481 }) => Some(reference),
482 Some(_) => {
483 core::panic!("Base type must be a Reference")
484 }
485 None => None,
486 };
487 (
488 pointer_id.clone(),
489 Type::new(
490 TypeDefinition::shared_reference(Rc::new(RefCell::new(
492 SharedTypeContainer {
493 nominal_type_declaration: Some(NominalTypeDeclaration {
494 name: name.to_string(),
495 variant,
496 }),
497 type_value: Type {
498 base_type: base_type_ref,
499 type_definition: TypeDefinition::Unit,
500 metadata: TypeMetadata::default(),
501 },
502 pointer: Pointer::new_reference(
503 ReferencedPointerAddress::from(&pointer_id),
504 PointerReferenceMutability::Immutable,
505 ),
506 },
507 ))),
508 TypeMetadata::default(),
509 ),
510 )
511}
512
513#[cfg(test)]
514mod tests {
515 use core::str::FromStr;
516
517 use crate::values::core_values::endpoint::Endpoint;
518
519 use super::*;
520
521 use itertools::Itertools;
522
523 #[test]
524 fn core_lib() {
525 assert!(has_core_lib_type(CoreLibPointerId::Endpoint));
526 assert!(has_core_lib_type(CoreLibPointerId::Null));
527 assert!(has_core_lib_type(CoreLibPointerId::Boolean));
528 assert!(has_core_lib_type(CoreLibPointerId::Integer(None)));
529 assert!(has_core_lib_type(CoreLibPointerId::Decimal(None)));
530 assert!(has_core_lib_type(CoreLibPointerId::Type));
531 assert!(has_core_lib_type(CoreLibPointerId::Text));
532 assert!(has_core_lib_type(CoreLibPointerId::List));
533 assert!(has_core_lib_type(CoreLibPointerId::Map));
534 assert!(has_core_lib_type(CoreLibPointerId::Range));
535 assert!(has_core_lib_type(CoreLibPointerId::Callable));
536 assert!(has_core_lib_type(CoreLibPointerId::Unit));
537 assert!(has_core_lib_type(CoreLibPointerId::Never));
538 assert!(has_core_lib_type(CoreLibPointerId::Unknown));
539 for variant in IntegerTypeVariant::iter() {
540 assert!(has_core_lib_type(CoreLibPointerId::Integer(Some(
541 variant
542 ))));
543 }
544 for variant in DecimalTypeVariant::iter() {
545 assert!(has_core_lib_type(CoreLibPointerId::Decimal(Some(
546 variant
547 ))));
548 }
549 }
550
551 #[test]
552 fn debug() {
553 let mut memory = Memory::new(Endpoint::LOCAL);
554 load_core_lib(&mut memory);
555 info!(
556 "{}",
557 memory
558 .get_value_reference(&CoreLibPointerId::Core.into())
559 .unwrap()
560 .borrow()
561 .value_container
562 );
563 }
564
565 #[test]
566 fn core_lib_type_addresses() {
567 let integer_base = "integer";
568 let integer_u8 = "integer/u8";
569 let integer_i32 = "integer/i32";
570 let decimal_base = "decimal";
571 let decimal_f64 = "decimal/f64";
572
573 assert_eq!(
574 CoreLibPointerId::from_str(integer_base),
575 Ok(CoreLibPointerId::Integer(None))
576 );
577 assert_eq!(
578 CoreLibPointerId::from_str(integer_u8),
579 Ok(CoreLibPointerId::Integer(Some(IntegerTypeVariant::U8)))
580 );
581 assert_eq!(
582 CoreLibPointerId::from_str(integer_i32),
583 Ok(CoreLibPointerId::Integer(Some(IntegerTypeVariant::I32)))
584 );
585 assert_eq!(
586 CoreLibPointerId::from_str(decimal_base),
587 Ok(CoreLibPointerId::Decimal(None))
588 );
589 assert_eq!(
590 CoreLibPointerId::from_str(decimal_f64),
591 Ok(CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64)))
592 );
593
594 assert_eq!(CoreLibPointerId::Integer(None).to_string(), integer_base);
595 assert_eq!(
596 CoreLibPointerId::Integer(Some(IntegerTypeVariant::U8)).to_string(),
597 integer_u8
598 );
599 assert_eq!(
600 CoreLibPointerId::Integer(Some(IntegerTypeVariant::I32))
601 .to_string(),
602 integer_i32
603 );
604 assert_eq!(CoreLibPointerId::Decimal(None).to_string(), decimal_base);
605 assert_eq!(
606 CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64))
607 .to_string(),
608 decimal_f64
609 );
610 }
611
612 #[test]
613 fn core_lib_pointer_id_conversion() {
614 let core_id = CoreLibPointerId::Core;
615 let pointer_address: PointerAddress = core_id.clone().into();
616 let converted_id: CoreLibPointerId =
617 (&pointer_address).try_into().unwrap();
618 assert_eq!(core_id, converted_id);
619
620 let boolean_id = CoreLibPointerId::Boolean;
621 let pointer_address: PointerAddress = boolean_id.clone().into();
622 let converted_id: CoreLibPointerId =
623 (&pointer_address).try_into().unwrap();
624 assert_eq!(boolean_id, converted_id);
625
626 let integer_id =
627 CoreLibPointerId::Integer(Some(IntegerTypeVariant::I32));
628 let pointer_address: PointerAddress = integer_id.clone().into();
629 let converted_id: CoreLibPointerId =
630 (&pointer_address).try_into().unwrap();
631 assert_eq!(integer_id, converted_id);
632
633 let decimal_id =
634 CoreLibPointerId::Decimal(Some(DecimalTypeVariant::F64));
635 let pointer_address: PointerAddress = decimal_id.clone().into();
636 let converted_id: CoreLibPointerId =
637 (&pointer_address).try_into().unwrap();
638 assert_eq!(decimal_id, converted_id);
639
640 let type_id = CoreLibPointerId::Type;
641 let pointer_address: PointerAddress = type_id.clone().into();
642 let converted_id: CoreLibPointerId =
643 (&pointer_address).try_into().unwrap();
644 assert_eq!(type_id, converted_id);
645 }
646
647 #[test]
648 fn base_type_simple() {
649 let integer_type = get_core_lib_type(CoreLibPointerId::Integer(None));
651 let integer_base = integer_type.base_type_reference();
652 assert_eq!(integer_base.unwrap().borrow().to_string(), "integer");
653 }
654
655 #[test]
656 fn base_type_complex() {
657 let integer_u8_type = get_core_lib_type(CoreLibPointerId::Integer(
659 Some(IntegerTypeVariant::U8),
660 ));
661 assert_eq!(integer_u8_type.to_string(), "integer/u8");
662
663 let integer = integer_u8_type.base_type_reference();
664 assert_eq!(integer.unwrap().borrow().to_string(), "integer");
665 }
666
667 #[ignore]
668 #[test]
669 #[cfg(feature = "std")]
670 fn print_core_lib_addresses_as_hex() {
671 with_full_core_lib(|core_lib_types, _| {
672 let sorted_entries = core_lib_types
673 .keys()
674 .map(|k| (k.clone(), PointerAddress::from(k.clone())))
675 .sorted_by_key(|(_, address)| address.bytes().to_vec())
676 .collect::<Vec<_>>();
677 for (core_lib_id, address) in sorted_entries {
678 println!("{:?}: {}", core_lib_id, address);
679 }
680 });
681 }
682
683 #[test]
684 #[ignore]
685 #[cfg(feature = "std")]
686 fn create_core_type_ts_mapping() {
691 let core_lib = create_core_lib_types();
692 let mut core_lib: Vec<(CoreLibPointerId, PointerAddress)> = core_lib
693 .keys()
694 .map(|key| (key.clone(), PointerAddress::from(key.clone())))
695 .collect();
696 core_lib.sort_by_key(|(key, _)| {
697 PointerAddress::from(key.clone()).bytes().to_vec()
698 });
699
700 println!("export const CoreTypeAddress = {{");
701 for (core_lib_id, address) in core_lib {
702 println!(
703 " {}: \"{}\",",
704 core_lib_id.to_string().replace("/", "_"),
705 address.to_string().strip_prefix("$").unwrap()
706 );
707 }
708 println!("}} as const;");
709 }
710}