Skip to main content

datex_core/libs/
core.rs

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,                                // #core
74    Type,                                // #core.type
75    Null,                                // #core.null
76    Boolean,                             // #core.boolean
77    Integer(Option<IntegerTypeVariant>), // #core.integer
78    Decimal(Option<DecimalTypeVariant>), // #core.decimal
79    Text,                                // #core.text
80    Endpoint,                            // #core.endpoint
81    List,                                // #core.List
82    Map,                                 // #core.Map
83    Callable,                            // #core.Callable
84    Unit,                                // #core.Unit
85    Never,                               // #core.never
86    Unknown,                             // #core.unknown
87    Print, // #core.print (function, might be removed later)
88    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
213/// Retrieves either a core library type or value by its CoreLibPointerId.
214pub 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        // try types first
220        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
248/// Loads the core library into the provided memory instance.
249pub 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        // add core lib values
271        for (name, val) in core_lib_values.iter() {
272            let name = name.to_string();
273            types_structure.push((name, val.clone()));
274        }
275
276        // TODO #455: dont store variants as separate entries in core_struct (e.g., integer/u8, integer/i32, only keep integer)
277        // Import variants directly by variant access operator from base type (e.g., integer -> integer/u8)
278        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
289/// Creates a new instance of the core library as a ValueContainer
290/// including all core types as properties.
291pub 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                // TODO #680: add I/O abstraction layer / interface
424
425                let mut output = String::new();
426
427                // if first argument is a string value, print it directly
428                if let Some(ValueContainer::Local(Value {
429                    inner: CoreValue::Text(text),
430                    ..
431                })) = args.first()
432                {
433                    output.push_str(&text.0);
434                    // remove first argument from args
435                    args = &args[1..];
436                    // if there are still arguments, add a space
437                    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
470/// Creates a core type with the given parameters.
471fn 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            // &shared type<()>
491            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        // integer -> integer -> integer ...
650        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        // integer/u8 -> integer -> integer -> integer ...
658        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    /// Generates a TypeScript mapping of core type addresses to their names.
687    /// Run this test and copy the output into `src/dif/definitions.ts`.
688    ///
689    /// `cargo test create_core_type_ts_mapping -- --show-output --ignored`
690    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}