use sim_kernel::{Cx, Expr, Result, Symbol, Value};
use sim_lib_standard_core::{
CoercionPolicy, GuestRuntimeKit, LanguageProfile, OrganUse, ProfileBackingLib, ProfileRegistry,
TruthPolicy, install_language_profile,
};
use std::sync::Arc;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct JavascriptIntrinsic {
pub name: &'static str,
pub kind: &'static str,
pub backing: &'static str,
}
pub const fn javascript_intrinsic_manifest() -> &'static [JavascriptIntrinsic] {
include!(concat!(env!("OUT_DIR"), "/javascript_intrinsics.rs"))
}
pub const fn javascript_gap_catalog() -> &'static [&'static str] {
&[
"compiler-or-bytecode",
"foreign-engine-or-node",
"general-realm-agent-engine",
"host-event-loop",
"weak-apis",
"retain-policy-leaks-cycles",
"proxy-invariants",
"exotic-object-invariants",
]
}
pub fn javascript_core_profile() -> LanguageProfile {
let mut p = LanguageProfile::new(Symbol::qualified("lang", "javascript-core/v1"))
.with_reader(Symbol::qualified("codec", "javascript"))
.with_lowering(Symbol::qualified("javascript", "expr-lowering/v1"))
.with_eval_policy(Symbol::qualified("javascript", "direct-eval/v1"))
.with_organ(OrganUse::new(sim_lib_binding::binding_organ_symbol()))
.with_organ(OrganUse::new(sim_lib_control::control_organ_symbol()))
.with_organ(OrganUse::new(sim_lib_mutation::mutation_organ_symbol()))
.with_organ(OrganUse::new(sim_lib_sequence::sequence_organ_symbol()))
.with_organ(OrganUse::new(sim_lib_pattern::pattern_organ_symbol()))
.with_organ(OrganUse::new(sim_lib_dispatch::dispatch_organ_symbol()))
.requiring(sim_lib_mutation::standard_mutate_capability());
for gap in javascript_gap_catalog() {
p = p.with_unsupported_form(Symbol::qualified("javascript", *gap));
}
p
}
pub fn install_javascript_core_profile(
cx: &mut Cx,
registry: &mut ProfileRegistry,
) -> Result<LanguageProfile> {
install_language_profile(
cx,
registry,
javascript_core_profile(),
&[
ProfileBackingLib::loadable(
sim_lib_binding::binding_organ_symbol(),
sim_lib_binding::manifest_name(),
sim_lib_binding::install_binding_lib,
Some(sim_lib_binding::publish_binding_organ_claims_for_lib),
),
ProfileBackingLib::loadable(
sim_lib_control::control_organ_symbol(),
sim_lib_control::manifest_name(),
sim_lib_control::install_control_lib,
None,
),
ProfileBackingLib::unresolved(
sim_lib_mutation::mutation_organ_symbol(),
Symbol::qualified("sim", "mutation"),
),
ProfileBackingLib::loadable(
sim_lib_sequence::sequence_organ_symbol(),
sim_lib_sequence::manifest_name(),
sim_lib_sequence::install_sequence_lib,
Some(sim_lib_sequence::publish_sequence_organ_claims_for_lib),
),
ProfileBackingLib::loadable(
sim_lib_pattern::pattern_organ_symbol(),
sim_lib_pattern::manifest_name(),
sim_lib_pattern::install_pattern_lib,
Some(sim_lib_pattern::publish_pattern_organ_claims_for_lib),
),
ProfileBackingLib::unresolved(
sim_lib_dispatch::dispatch_organ_symbol(),
Symbol::qualified("sim", "dispatch"),
),
],
&[],
)
}
struct JsTruth;
impl TruthPolicy for JsTruth {
fn is_truthy(&self, cx: &mut Cx, value: &Value) -> Result<bool> {
Ok(!matches!(
value.object().as_expr(cx)?,
Expr::Bool(false) | Expr::Nil
))
}
}
struct JsCoercion;
impl CoercionPolicy for JsCoercion {
fn to_number(&self, _: &mut Cx, _: &Value) -> Result<Option<Value>> {
Ok(None)
}
fn to_string(&self, _: &mut Cx, _: &Value) -> Result<Option<Value>> {
Ok(None)
}
}
pub fn javascript_runtime_kit(cx: &mut Cx) -> Result<GuestRuntimeKit> {
Ok(GuestRuntimeKit::new(
Arc::new(JsTruth),
Arc::new(JsCoercion),
cx.factory().nil()?,
))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn registration_is_complete() {
let e = javascript_core_profile().checked_guest_evidence().unwrap();
assert_eq!(e.organs.len(), 6);
assert_eq!(e.capabilities.len(), 1);
assert_eq!(e.gaps.len(), 8);
let manifest = javascript_intrinsic_manifest();
assert_eq!(manifest.len(), 25);
assert!(manifest.windows(2).all(|pair| pair[0].name != pair[1].name));
assert!(
manifest
.iter()
.all(|entry| !entry.backing.is_empty() && !entry.kind.is_empty())
);
}
}