Skip to main content

submilli_engine/runtime/prelude/
mod.rs

1//! The prelude's implementation: every built-in method, static, constant, and
2//! vtable as Rust host fns, registered under `submilli:prelude`.
3//!
4//! Each method is declared (via [`declare_method`]) as a value symbol whose
5//! mangled name is the method's *dispatch key* (e.g.
6//! `submilli:prelude#String#repeat`) — the same string is the linker field the
7//! host fn registers under, so codegen's method lookup resolves straight to the
8//! Rust impl. `codegen::prelude::merged_prelude_declaration` folds these value
9//! symbols into the single `submilli:prelude` package next to the type surface;
10//! selected top-level bindings (`isNaN`, `NaN`, …) are loaded into user scope by
11//! the typechecker.
12
13pub(crate) mod arguments;
14pub mod array;
15pub mod bigint;
16mod bitwise;
17pub mod boolean;
18pub(crate) mod closure;
19pub(crate) mod collection;
20pub(crate) mod console;
21pub mod declaration;
22pub(crate) mod error;
23pub(crate) mod iterator;
24mod keep;
25mod ledger;
26pub mod map;
27pub mod math;
28pub(crate) mod member;
29pub mod number;
30pub mod object;
31pub mod regex;
32pub mod set;
33pub mod string;
34pub mod temporal;
35pub mod textcodec;
36pub mod uint8array;
37pub(crate) mod undefined;
38pub(crate) mod uri;
39pub(crate) mod value;
40pub(crate) mod vtable;
41
42use wasmtime::{Linker, Store};
43
44use crate::runtime::StoreData;
45use crate::{MangledName, PackageDeclaration, Param, Span, Type, ValueKind, ValueSymbol};
46
47pub use declaration::{
48    MODULE_NAME, cached_runtime_package_declarations, prelude_package_declaration,
49};
50
51/// Register every ported host fn. Store-less, so it goes into the reusable base
52/// linker; the returned `$string`/`$Array` values read the prelude's vtables at
53/// call time, not here. The store-bound vtable globals install separately via
54/// [`install_vtables`].
55pub fn install(linker: &mut Linker<StoreData>) -> wasmtime::Result<()> {
56    vtable::install_walk_guards(linker)?;
57    console::install(linker)?;
58    error::install(linker)?;
59    string::install(linker)?;
60    array::install(linker)?;
61    map::install(linker)?;
62    set::install(linker)?;
63    number::install(linker)?;
64    object::install(linker)?;
65    boolean::install(linker)?;
66    uint8array::install(linker)?;
67    textcodec::install(linker)?;
68    bigint::install(linker)?;
69    math::install(linker)?;
70    temporal::install(linker)?;
71    uri::install(linker)?;
72    regex::install(linker)?;
73    value::install(linker)?;
74    member::install(linker)
75}
76
77/// Define the host-owned object vtable globals. Unlike [`install`], this is
78/// store-bound (it allocates `$VTable` GC structs) and must run per-store before
79/// the prelude instantiates — the prelude imports these globals — so the runtime
80/// calls it at the top of `install_prelude_async`.
81pub(crate) fn install_vtables(
82    linker: &mut Linker<StoreData>,
83    store: &mut Store<StoreData>,
84) -> wasmtime::Result<(vtable::HostVtables, error::ErrorHost)> {
85    let vtables = vtable::install_vtable_module(linker, store)?;
86    undefined::install_store_bound(linker, store, &vtables.object)?;
87    let intr = crate::runtime::intrinsic_types::build_intrinsic_types(store.engine())?;
88    let error_host = error::install_store_bound(linker, store, &intr, &vtables.string)?;
89    number::install_constants(linker, store)?;
90    math::install_constants(linker, store)?;
91    Ok((vtables, error_host))
92}
93
94/// The codegen-facing declaration: the value symbols that route ported methods
95/// to their Rust impls (see the module doc).
96pub fn package_declaration() -> PackageDeclaration {
97    let mut defs = PackageDeclaration::with_package(MODULE_NAME);
98    vtable::declare_walk_guards(&mut defs);
99    console::declare(&mut defs);
100    string::declare(&mut defs);
101    array::declare(&mut defs);
102    map::declare(&mut defs);
103    set::declare(&mut defs);
104    number::declare(&mut defs);
105    object::declare(&mut defs);
106    boolean::declare(&mut defs);
107    math::declare(&mut defs);
108    uint8array::declare(&mut defs);
109    textcodec::declare(&mut defs);
110    bigint::declare(&mut defs);
111    temporal::declare(&mut defs);
112    uri::declare(&mut defs);
113    regex::declare(&mut defs);
114    value::declare(&mut defs);
115    member::declare(&mut defs);
116    defs
117}
118
119/// Declare a ported method's value symbol. Its mangled name is the method's
120/// dispatch key, and its first param is the (otherwise implicit) receiver —
121/// `import_value_symbol` emits no receiver of its own.
122pub(crate) fn declare_method(
123    defs: &mut PackageDeclaration,
124    name: &str,
125    mangled_name: MangledName,
126    params: Vec<Param>,
127    ret: Type,
128) {
129    // Key by the dispatch key, not the bare method name: String and Array share
130    // method names (`at`, `slice`, `concat`, …), so a name-keyed map would have
131    // one type's declaration clobber the other's. Codegen routes on
132    // `mangled_name`, not this key.
133    defs.values.insert(
134        mangled_name.as_str().to_string(),
135        ValueSymbol {
136            name: name.to_string(),
137            mangled_name,
138            declaration_span: Span::at(crate::FileId::PRELUDE),
139            kind: ValueKind::Function {
140                generics: Vec::new(),
141                params,
142                ret,
143                type_predicate: None,
144                doc: None,
145            },
146        },
147    );
148}