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