use std::collections::HashMap;
use std::sync::LazyLock;
use crate::Effect;
use crate::Type;
use crate::object_shape::*;
use crate::type_config::AliasingEffectConfig;
use crate::type_config::AliasingSignatureConfig;
use crate::type_config::ApplyArgConfig;
use crate::type_config::ApplyArgHoleKind;
use crate::type_config::BuiltInTypeRef;
use crate::type_config::TypeConfig;
use crate::type_config::TypeReferenceConfig;
use crate::type_config::ValueKind;
use crate::type_config::ValueReason;
pub type Global = Type;
pub struct GlobalRegistry {
base: Option<&'static HashMap<String, Global>>,
entries: HashMap<String, Global>,
}
impl GlobalRegistry {
pub fn new() -> Self {
Self {
base: None,
entries: HashMap::new(),
}
}
pub fn with_base(base: &'static HashMap<String, Global>) -> Self {
Self {
base: Some(base),
entries: HashMap::new(),
}
}
pub fn get(&self, key: &str) -> Option<&Global> {
self.entries
.get(key)
.or_else(|| self.base.and_then(|b| b.get(key)))
}
pub fn insert(&mut self, key: String, value: Global) {
self.entries.insert(key, value);
}
pub fn contains_key(&self, key: &str) -> bool {
self.entries.contains_key(key) || self.base.map_or(false, |b| b.contains_key(key))
}
pub fn keys(&self) -> impl Iterator<Item = &String> {
let base_keys = self
.base
.into_iter()
.flat_map(|b| b.keys())
.filter(|k| !self.entries.contains_key(k.as_str()));
self.entries.keys().chain(base_keys)
}
pub fn into_inner(self) -> HashMap<String, Global> {
debug_assert!(
self.base.is_none(),
"into_inner() called on overlay-mode GlobalRegistry"
);
self.entries
}
}
impl Clone for GlobalRegistry {
fn clone(&self) -> Self {
Self {
base: self.base,
entries: self.entries.clone(),
}
}
}
struct BaseRegistries {
shapes: HashMap<String, ObjectShape>,
globals: HashMap<String, Global>,
}
static BASE: LazyLock<BaseRegistries> = LazyLock::new(|| {
let mut shapes = build_builtin_shapes();
let globals = build_default_globals(&mut shapes);
BaseRegistries {
shapes: shapes.into_inner(),
globals: globals.into_inner(),
}
});
pub fn base_shapes() -> &'static HashMap<String, ObjectShape> {
&BASE.shapes
}
pub fn base_globals() -> &'static HashMap<String, Global> {
&BASE.globals
}
pub fn install_type_config(
_globals: &mut GlobalRegistry,
shapes: &mut ShapeRegistry,
type_config: &TypeConfig,
module_name: &str,
_loc: (),
) -> Global {
install_type_config_inner(_globals, shapes, type_config, module_name, _loc, &mut None)
}
pub fn install_type_config_with_errors(
_globals: &mut GlobalRegistry,
shapes: &mut ShapeRegistry,
type_config: &TypeConfig,
module_name: &str,
_loc: (),
errors: &mut Vec<String>,
) -> Global {
install_type_config_inner(
_globals,
shapes,
type_config,
module_name,
_loc,
&mut Some(errors),
)
}
fn install_type_config_inner(
_globals: &mut GlobalRegistry,
shapes: &mut ShapeRegistry,
type_config: &TypeConfig,
module_name: &str,
_loc: (),
errors: &mut Option<&mut Vec<String>>,
) -> Global {
match type_config {
TypeConfig::TypeReference(TypeReferenceConfig { name }) => match name {
BuiltInTypeRef::Array => Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
BuiltInTypeRef::MixedReadonly => Type::Object {
shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),
},
BuiltInTypeRef::Primitive => Type::Primitive,
BuiltInTypeRef::Ref => Type::Object {
shape_id: Some(BUILT_IN_USE_REF_ID.to_string()),
},
BuiltInTypeRef::Any => Type::Poly,
},
TypeConfig::Function(func_config) => {
let return_type = install_type_config_inner(
_globals,
shapes,
&func_config.return_type,
module_name,
(),
errors,
);
add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: func_config.positional_params.clone(),
rest_param: func_config.rest_param,
callee_effect: func_config.callee_effect,
return_type,
return_value_kind: func_config.return_value_kind,
no_alias: func_config.no_alias.unwrap_or(false),
mutable_only_if_operands_are_mutable: func_config
.mutable_only_if_operands_are_mutable
.unwrap_or(false),
impure: func_config.impure.unwrap_or(false),
canonical_name: func_config.canonical_name.clone(),
aliasing: func_config.aliasing.clone(),
known_incompatible: func_config.known_incompatible.clone(),
..Default::default()
},
None,
false,
)
}
TypeConfig::Hook(hook_config) => {
let return_type = install_type_config_inner(
_globals,
shapes,
&hook_config.return_type,
module_name,
(),
errors,
);
add_hook(
shapes,
HookSignatureBuilder {
hook_kind: HookKind::Custom,
positional_params: hook_config.positional_params.clone().unwrap_or_default(),
rest_param: hook_config.rest_param.or(Some(Effect::Freeze)),
callee_effect: Effect::Read,
return_type,
return_value_kind: hook_config.return_value_kind.unwrap_or(ValueKind::Frozen),
no_alias: hook_config.no_alias.unwrap_or(false),
aliasing: hook_config.aliasing.clone(),
known_incompatible: hook_config.known_incompatible.clone(),
..Default::default()
},
None,
)
}
TypeConfig::Object(obj_config) => {
let properties: Vec<(String, Type)> = obj_config
.properties
.as_ref()
.map(|props| {
props
.iter()
.map(|(key, value)| {
let ty = install_type_config_inner(
_globals,
shapes,
value,
module_name,
(),
errors,
);
if let Some(errs) = errors {
let expect_hook = crate::environment::is_hook_name(key);
let is_hook = match &ty {
Type::Function { shape_id: Some(id), .. } => {
shapes.get(id)
.and_then(|shape| shape.function_type.as_ref())
.and_then(|ft| ft.hook_kind.as_ref())
.is_some()
}
_ => false,
};
if expect_hook != is_hook {
errs.push(format!(
"Expected type for object property '{}' from module '{}' {} based on the property name",
key,
module_name,
if expect_hook { "to be a hook" } else { "not to be a hook" }
));
}
}
(key.clone(), ty)
})
.collect()
})
.unwrap_or_default();
add_object(shapes, None, properties)
}
}
}
pub fn build_builtin_shapes() -> ShapeRegistry {
let mut shapes = ShapeRegistry::new();
add_object(
&mut shapes,
Some(BUILT_IN_PROPS_ID),
vec![(
"ref".to_string(),
Type::Object {
shape_id: Some(BUILT_IN_USE_REF_ID.to_string()),
},
)],
);
build_array_shape(&mut shapes);
build_set_shape(&mut shapes);
build_map_shape(&mut shapes);
build_weak_set_shape(&mut shapes);
build_weak_map_shape(&mut shapes);
build_object_shape(&mut shapes);
build_ref_shapes(&mut shapes);
build_state_shapes(&mut shapes);
build_hook_shapes(&mut shapes);
build_misc_shapes(&mut shapes);
shapes
}
fn simple_function(
shapes: &mut ShapeRegistry,
positional_params: Vec<Effect>,
rest_param: Option<Effect>,
return_type: Type,
return_value_kind: ValueKind,
) -> Type {
add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params,
rest_param,
return_type,
return_value_kind,
..Default::default()
},
None,
false,
)
}
fn pure_primitive_fn(shapes: &mut ShapeRegistry) -> Type {
simple_function(
shapes,
Vec::new(),
Some(Effect::Read),
Type::Primitive,
ValueKind::Primitive,
)
}
fn build_array_shape(shapes: &mut ShapeRegistry) {
let index_of = pure_primitive_fn(shapes);
let includes = pure_primitive_fn(shapes);
let pop = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Store,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let at = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let concat = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Capture),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
callee_effect: Effect::Capture,
..Default::default()
},
None,
false,
);
let join = pure_primitive_fn(shapes);
let slice = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
callee_effect: Effect::Capture,
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let map = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
aliasing: Some(AliasingSignatureConfig {
receiver: "@receiver".to_string(),
params: vec!["@callback".to_string()],
rest: None,
returns: "@returns".to_string(),
temporaries: vec![
"@item".to_string(),
"@callbackReturn".to_string(),
"@thisArg".to_string(),
],
effects: vec![
AliasingEffectConfig::Create {
into: "@returns".to_string(),
value: ValueKind::Mutable,
reason: ValueReason::KnownReturnSignature,
},
AliasingEffectConfig::CreateFrom {
from: "@receiver".to_string(),
into: "@item".to_string(),
},
AliasingEffectConfig::Create {
into: "@thisArg".to_string(),
value: ValueKind::Primitive,
reason: ValueReason::KnownReturnSignature,
},
AliasingEffectConfig::Apply {
receiver: "@thisArg".to_string(),
function: "@callback".to_string(),
mutates_function: false,
args: vec![
ApplyArgConfig::Place("@item".to_string()),
ApplyArgConfig::Hole {
kind: ApplyArgHoleKind::Hole,
},
ApplyArgConfig::Place("@receiver".to_string()),
],
into: "@callbackReturn".to_string(),
},
AliasingEffectConfig::Capture {
from: "@callbackReturn".to_string(),
into: "@returns".to_string(),
},
],
}),
..Default::default()
},
None,
false,
);
let filter = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let find = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let find_index = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let every = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let some = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let flat_map = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let length = Type::Primitive;
let push = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Capture),
callee_effect: Effect::Store,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
aliasing: Some(AliasingSignatureConfig {
receiver: "@receiver".to_string(),
params: Vec::new(),
rest: Some("@rest".to_string()),
returns: "@returns".to_string(),
temporaries: Vec::new(),
effects: vec![
AliasingEffectConfig::Mutate {
value: "@receiver".to_string(),
},
AliasingEffectConfig::Capture {
from: "@rest".to_string(),
into: "@receiver".to_string(),
},
AliasingEffectConfig::Create {
into: "@returns".to_string(),
value: ValueKind::Primitive,
reason: ValueReason::KnownReturnSignature,
},
],
}),
..Default::default()
},
None,
false,
);
add_object(
shapes,
Some(BUILT_IN_ARRAY_ID),
vec![
("indexOf".to_string(), index_of),
("includes".to_string(), includes),
("pop".to_string(), pop),
("at".to_string(), at),
("concat".to_string(), concat),
("length".to_string(), length),
("push".to_string(), push),
("slice".to_string(), slice),
("map".to_string(), map),
("flatMap".to_string(), flat_map),
("filter".to_string(), filter),
("every".to_string(), every),
("some".to_string(), some),
("find".to_string(), find),
("findIndex".to_string(), find_index),
("join".to_string(), join),
],
);
}
fn build_set_shape(shapes: &mut ShapeRegistry) {
let has = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let add = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture],
callee_effect: Effect::Store,
return_type: Type::Object {
shape_id: Some(BUILT_IN_SET_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
aliasing: Some(AliasingSignatureConfig {
receiver: "@receiver".to_string(),
params: Vec::new(),
rest: Some("@rest".to_string()),
returns: "@returns".to_string(),
temporaries: Vec::new(),
effects: vec![
AliasingEffectConfig::Assign {
from: "@receiver".to_string(),
into: "@returns".to_string(),
},
AliasingEffectConfig::Mutate {
value: "@receiver".to_string(),
},
AliasingEffectConfig::Capture {
from: "@rest".to_string(),
into: "@receiver".to_string(),
},
],
}),
..Default::default()
},
None,
false,
);
let clear = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Store,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let delete = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Store,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let size = Type::Primitive;
let difference = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture],
callee_effect: Effect::Capture,
return_type: Type::Object {
shape_id: Some(BUILT_IN_SET_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let union = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture],
callee_effect: Effect::Capture,
return_type: Type::Object {
shape_id: Some(BUILT_IN_SET_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let symmetrical_difference = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture],
callee_effect: Effect::Capture,
return_type: Type::Object {
shape_id: Some(BUILT_IN_SET_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let is_subset_of = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Read,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let is_superset_of = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Read,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let for_each = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let values = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let keys = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let entries = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
add_object(
shapes,
Some(BUILT_IN_SET_ID),
vec![
("add".to_string(), add),
("clear".to_string(), clear),
("delete".to_string(), delete),
("has".to_string(), has),
("size".to_string(), size),
("difference".to_string(), difference),
("union".to_string(), union),
("symmetricalDifference".to_string(), symmetrical_difference),
("isSubsetOf".to_string(), is_subset_of),
("isSupersetOf".to_string(), is_superset_of),
("forEach".to_string(), for_each),
("values".to_string(), values),
("keys".to_string(), keys),
("entries".to_string(), entries),
],
);
}
fn build_map_shape(shapes: &mut ShapeRegistry) {
let has = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let get = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let clear = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Store,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let set = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture, Effect::Capture],
callee_effect: Effect::Store,
return_type: Type::Object {
shape_id: Some(BUILT_IN_MAP_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let delete = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Store,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let size = Type::Primitive;
let for_each = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let values = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let keys = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let entries = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
add_object(
shapes,
Some(BUILT_IN_MAP_ID),
vec![
("has".to_string(), has),
("get".to_string(), get),
("set".to_string(), set),
("clear".to_string(), clear),
("delete".to_string(), delete),
("size".to_string(), size),
("forEach".to_string(), for_each),
("values".to_string(), values),
("keys".to_string(), keys),
("entries".to_string(), entries),
],
);
}
fn build_weak_set_shape(shapes: &mut ShapeRegistry) {
let has = pure_primitive_fn(shapes);
let add = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture],
callee_effect: Effect::Store,
return_type: Type::Object {
shape_id: Some(BUILT_IN_WEAK_SET_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let delete = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Store,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
add_object(
shapes,
Some(BUILT_IN_WEAK_SET_ID),
vec![
("has".to_string(), has),
("add".to_string(), add),
("delete".to_string(), delete),
],
);
}
fn build_weak_map_shape(shapes: &mut ShapeRegistry) {
let has = pure_primitive_fn(shapes);
let get = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Capture,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let set = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture, Effect::Capture],
callee_effect: Effect::Store,
return_type: Type::Object {
shape_id: Some(BUILT_IN_WEAK_MAP_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let delete = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
callee_effect: Effect::Store,
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
add_object(
shapes,
Some(BUILT_IN_WEAK_MAP_ID),
vec![
("has".to_string(), has),
("get".to_string(), get),
("set".to_string(), set),
("delete".to_string(), delete),
],
);
}
fn build_object_shape(shapes: &mut ShapeRegistry) {
let to_string = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
add_object(
shapes,
Some(BUILT_IN_OBJECT_ID),
vec![("toString".to_string(), to_string)],
);
add_object(shapes, Some(BUILT_IN_FUNCTION_ID), Vec::new());
add_object(shapes, Some(BUILT_IN_JSX_ID), Vec::new());
let mixed_to_string = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let mixed_index_of = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let mixed_includes = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let mixed_at = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
return_type: Type::Object {
shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),
},
callee_effect: Effect::Capture,
return_value_kind: ValueKind::Frozen,
..Default::default()
},
None,
false,
);
let mixed_map = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
callee_effect: Effect::ConditionallyMutate,
return_value_kind: ValueKind::Mutable,
no_alias: true,
..Default::default()
},
None,
false,
);
let mixed_flat_map = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
callee_effect: Effect::ConditionallyMutate,
return_value_kind: ValueKind::Mutable,
no_alias: true,
..Default::default()
},
None,
false,
);
let mixed_filter = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
callee_effect: Effect::ConditionallyMutate,
return_value_kind: ValueKind::Mutable,
no_alias: true,
..Default::default()
},
None,
false,
);
let mixed_concat = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Capture),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
callee_effect: Effect::Capture,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let mixed_slice = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
callee_effect: Effect::Capture,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let mixed_every = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
return_type: Type::Primitive,
callee_effect: Effect::ConditionallyMutate,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let mixed_some = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
return_type: Type::Primitive,
callee_effect: Effect::ConditionallyMutate,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let mixed_find = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
return_type: Type::Object {
shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),
},
callee_effect: Effect::ConditionallyMutate,
return_value_kind: ValueKind::Frozen,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let mixed_find_index = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
return_type: Type::Primitive,
callee_effect: Effect::ConditionallyMutate,
return_value_kind: ValueKind::Primitive,
no_alias: true,
mutable_only_if_operands_are_mutable: true,
..Default::default()
},
None,
false,
);
let mixed_join = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let mut mixed_props = HashMap::new();
mixed_props.insert("toString".to_string(), mixed_to_string);
mixed_props.insert("indexOf".to_string(), mixed_index_of);
mixed_props.insert("includes".to_string(), mixed_includes);
mixed_props.insert("at".to_string(), mixed_at);
mixed_props.insert("map".to_string(), mixed_map);
mixed_props.insert("flatMap".to_string(), mixed_flat_map);
mixed_props.insert("filter".to_string(), mixed_filter);
mixed_props.insert("concat".to_string(), mixed_concat);
mixed_props.insert("slice".to_string(), mixed_slice);
mixed_props.insert("every".to_string(), mixed_every);
mixed_props.insert("some".to_string(), mixed_some);
mixed_props.insert("find".to_string(), mixed_find);
mixed_props.insert("findIndex".to_string(), mixed_find_index);
mixed_props.insert("join".to_string(), mixed_join);
mixed_props.insert(
"*".to_string(),
Type::Object {
shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),
},
);
shapes.insert(
BUILT_IN_MIXED_READONLY_ID.to_string(),
ObjectShape {
properties: mixed_props,
function_type: None,
},
);
}
fn build_ref_shapes(shapes: &mut ShapeRegistry) {
add_object(
shapes,
Some(BUILT_IN_USE_REF_ID),
vec![(
"current".to_string(),
Type::Object {
shape_id: Some(BUILT_IN_REF_VALUE_ID.to_string()),
},
)],
);
add_object(
shapes,
Some(BUILT_IN_REF_VALUE_ID),
vec![(
"*".to_string(),
Type::Object {
shape_id: Some(BUILT_IN_REF_VALUE_ID.to_string()),
},
)],
);
}
fn build_state_shapes(shapes: &mut ShapeRegistry) {
let set_state = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
Some(BUILT_IN_SET_STATE_ID),
false,
);
add_object(
shapes,
Some(BUILT_IN_USE_STATE_ID),
vec![("0".to_string(), Type::Poly), ("1".to_string(), set_state)],
);
let set_action_state = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
Some(BUILT_IN_SET_ACTION_STATE_ID),
false,
);
add_object(
shapes,
Some(BUILT_IN_USE_ACTION_STATE_ID),
vec![
("0".to_string(), Type::Poly),
("1".to_string(), set_action_state),
],
);
let dispatch = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
Some(BUILT_IN_DISPATCH_ID),
false,
);
add_object(
shapes,
Some(BUILT_IN_USE_REDUCER_ID),
vec![("0".to_string(), Type::Poly), ("1".to_string(), dispatch)],
);
let start_transition = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
Some(BUILT_IN_START_TRANSITION_ID),
false,
);
add_object(
shapes,
Some(BUILT_IN_USE_TRANSITION_ID),
vec![
("0".to_string(), Type::Primitive),
("1".to_string(), start_transition),
],
);
let set_optimistic = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
Some(BUILT_IN_SET_OPTIMISTIC_ID),
false,
);
add_object(
shapes,
Some(BUILT_IN_USE_OPTIMISTIC_ID),
vec![
("0".to_string(), Type::Poly),
("1".to_string(), set_optimistic),
],
);
}
fn build_hook_shapes(shapes: &mut ShapeRegistry) {
add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::ConditionallyMutate),
callee_effect: Effect::ConditionallyMutate,
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
..Default::default()
},
Some(BUILT_IN_EFFECT_EVENT_ID),
false,
);
}
fn build_misc_shapes(shapes: &mut ShapeRegistry) {
add_object(shapes, Some(REANIMATED_SHARED_VALUE_ID), Vec::new());
}
pub fn get_reanimated_module_type(shapes: &mut ShapeRegistry) -> Type {
let mut reanimated_type: Vec<(String, Type)> = Vec::new();
let frozen_hooks = [
"useFrameCallback",
"useAnimatedStyle",
"useAnimatedProps",
"useAnimatedScrollHandler",
"useAnimatedReaction",
"useWorkletCallback",
];
for hook in &frozen_hooks {
let hook_type = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
no_alias: true,
hook_kind: HookKind::Custom,
..Default::default()
},
None,
);
reanimated_type.push((hook.to_string(), hook_type));
}
let mutable_hooks = ["useSharedValue", "useDerivedValue"];
for hook in &mutable_hooks {
let hook_type = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Object {
shape_id: Some(REANIMATED_SHARED_VALUE_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
no_alias: true,
hook_kind: HookKind::Custom,
..Default::default()
},
None,
);
reanimated_type.push((hook.to_string(), hook_type));
}
let funcs = [
"withTiming",
"withSpring",
"createAnimatedPropAdapter",
"withDecay",
"withRepeat",
"runOnUI",
"executeOnUIRuntimeSync",
];
for func_name in &funcs {
let func_type = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
no_alias: true,
..Default::default()
},
None,
false,
);
reanimated_type.push((func_name.to_string(), func_type));
}
add_object(shapes, None, reanimated_type)
}
pub fn build_default_globals(shapes: &mut ShapeRegistry) -> GlobalRegistry {
let mut globals = GlobalRegistry::new();
let react_apis = build_react_apis(shapes, &mut globals);
for name in UNTYPED_GLOBALS {
globals.insert(name.to_string(), Type::Poly);
}
let typed_globals = build_typed_globals(shapes, &mut globals, react_apis);
globals.insert(
"globalThis".to_string(),
add_object(shapes, Some("globalThis"), typed_globals.clone()),
);
globals.insert(
"global".to_string(),
add_object(shapes, Some("global"), typed_globals),
);
globals
}
const UNTYPED_GLOBALS: &[&str] = &[
"Object",
"Function",
"RegExp",
"Date",
"Error",
"TypeError",
"RangeError",
"ReferenceError",
"SyntaxError",
"URIError",
"EvalError",
"DataView",
"Float32Array",
"Float64Array",
"Int8Array",
"Int16Array",
"Int32Array",
"WeakMap",
"Uint8Array",
"Uint8ClampedArray",
"Uint16Array",
"Uint32Array",
"ArrayBuffer",
"JSON",
"console",
"eval",
];
fn build_react_apis(
shapes: &mut ShapeRegistry,
globals: &mut GlobalRegistry,
) -> Vec<(String, Type)> {
let mut react_apis: Vec<(String, Type)> = Vec::new();
let use_context = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
return_value_reason: Some(ValueReason::Context),
hook_kind: HookKind::UseContext,
..Default::default()
},
Some(BUILT_IN_USE_CONTEXT_HOOK_ID),
);
react_apis.push(("useContext".to_string(), use_context));
let use_state = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Object {
shape_id: Some(BUILT_IN_USE_STATE_ID.to_string()),
},
return_value_kind: ValueKind::Frozen,
return_value_reason: Some(ValueReason::State),
hook_kind: HookKind::UseState,
..Default::default()
},
None,
);
react_apis.push(("useState".to_string(), use_state));
let use_action_state = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Object {
shape_id: Some(BUILT_IN_USE_ACTION_STATE_ID.to_string()),
},
return_value_kind: ValueKind::Frozen,
return_value_reason: Some(ValueReason::State),
hook_kind: HookKind::UseActionState,
..Default::default()
},
None,
);
react_apis.push(("useActionState".to_string(), use_action_state));
let use_reducer = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Object {
shape_id: Some(BUILT_IN_USE_REDUCER_ID.to_string()),
},
return_value_kind: ValueKind::Frozen,
return_value_reason: Some(ValueReason::ReducerState),
hook_kind: HookKind::UseReducer,
..Default::default()
},
None,
);
react_apis.push(("useReducer".to_string(), use_reducer));
let use_ref = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Capture),
return_type: Type::Object {
shape_id: Some(BUILT_IN_USE_REF_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
hook_kind: HookKind::UseRef,
..Default::default()
},
None,
);
react_apis.push(("useRef".to_string(), use_ref));
let use_imperative_handle = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Primitive,
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseImperativeHandle,
..Default::default()
},
None,
);
react_apis.push(("useImperativeHandle".to_string(), use_imperative_handle));
let use_memo = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseMemo,
..Default::default()
},
None,
);
react_apis.push(("useMemo".to_string(), use_memo));
let use_callback = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseCallback,
..Default::default()
},
None,
);
react_apis.push(("useCallback".to_string(), use_callback));
let use_effect = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Primitive,
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseEffect,
aliasing: Some(AliasingSignatureConfig {
receiver: "@receiver".to_string(),
params: Vec::new(),
rest: Some("@rest".to_string()),
returns: "@returns".to_string(),
temporaries: vec!["@effect".to_string()],
effects: vec![
AliasingEffectConfig::Freeze {
value: "@rest".to_string(),
reason: ValueReason::Effect,
},
AliasingEffectConfig::Create {
into: "@effect".to_string(),
value: ValueKind::Frozen,
reason: ValueReason::KnownReturnSignature,
},
AliasingEffectConfig::Capture {
from: "@rest".to_string(),
into: "@effect".to_string(),
},
AliasingEffectConfig::Create {
into: "@returns".to_string(),
value: ValueKind::Primitive,
reason: ValueReason::KnownReturnSignature,
},
],
}),
..Default::default()
},
Some(BUILT_IN_USE_EFFECT_HOOK_ID),
);
react_apis.push(("useEffect".to_string(), use_effect));
let use_layout_effect = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseLayoutEffect,
..Default::default()
},
Some(BUILT_IN_USE_LAYOUT_EFFECT_HOOK_ID),
);
react_apis.push(("useLayoutEffect".to_string(), use_layout_effect));
let use_insertion_effect = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseInsertionEffect,
..Default::default()
},
Some(BUILT_IN_USE_INSERTION_EFFECT_HOOK_ID),
);
react_apis.push(("useInsertionEffect".to_string(), use_insertion_effect));
let use_transition = add_hook(
shapes,
HookSignatureBuilder {
rest_param: None,
return_type: Type::Object {
shape_id: Some(BUILT_IN_USE_TRANSITION_ID.to_string()),
},
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseTransition,
..Default::default()
},
None,
);
react_apis.push(("useTransition".to_string(), use_transition));
let use_optimistic = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Object {
shape_id: Some(BUILT_IN_USE_OPTIMISTIC_ID.to_string()),
},
return_value_kind: ValueKind::Frozen,
return_value_reason: Some(ValueReason::State),
hook_kind: HookKind::UseOptimistic,
..Default::default()
},
None,
);
react_apis.push(("useOptimistic".to_string(), use_optimistic));
let use_fn = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
..Default::default()
},
Some(BUILT_IN_USE_OPERATOR_ID),
false,
);
react_apis.push(("use".to_string(), use_fn));
let use_effect_event = add_hook(
shapes,
HookSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Function {
shape_id: Some(BUILT_IN_EFFECT_EVENT_ID.to_string()),
return_type: Box::new(Type::Poly),
is_constructor: false,
},
return_value_kind: ValueKind::Frozen,
hook_kind: HookKind::UseEffectEvent,
..Default::default()
},
Some(BUILT_IN_USE_EFFECT_EVENT_ID),
);
react_apis.push(("useEffectEvent".to_string(), use_effect_event));
for (name, ty) in &react_apis {
globals.insert(name.clone(), ty.clone());
}
react_apis
}
fn build_typed_globals(
shapes: &mut ShapeRegistry,
globals: &mut GlobalRegistry,
react_apis: Vec<(String, Type)>,
) -> Vec<(String, Type)> {
let mut typed_globals: Vec<(String, Type)> = Vec::new();
let obj_keys = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
aliasing: Some(AliasingSignatureConfig {
receiver: "@receiver".to_string(),
params: vec!["@object".to_string()],
rest: None,
returns: "@returns".to_string(),
temporaries: Vec::new(),
effects: vec![
AliasingEffectConfig::Create {
into: "@returns".to_string(),
value: ValueKind::Mutable,
reason: ValueReason::KnownReturnSignature,
},
AliasingEffectConfig::ImmutableCapture {
from: "@object".to_string(),
into: "@returns".to_string(),
},
],
}),
..Default::default()
},
None,
false,
);
let obj_from_entries = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::ConditionallyMutate],
return_type: Type::Object {
shape_id: Some(BUILT_IN_OBJECT_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let obj_entries = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture],
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
aliasing: Some(AliasingSignatureConfig {
receiver: "@receiver".to_string(),
params: vec!["@object".to_string()],
rest: None,
returns: "@returns".to_string(),
temporaries: Vec::new(),
effects: vec![
AliasingEffectConfig::Create {
into: "@returns".to_string(),
value: ValueKind::Mutable,
reason: ValueReason::KnownReturnSignature,
},
AliasingEffectConfig::Capture {
from: "@object".to_string(),
into: "@returns".to_string(),
},
],
}),
..Default::default()
},
None,
false,
);
let obj_values = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Capture],
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
aliasing: Some(AliasingSignatureConfig {
receiver: "@receiver".to_string(),
params: vec!["@object".to_string()],
rest: None,
returns: "@returns".to_string(),
temporaries: Vec::new(),
effects: vec![
AliasingEffectConfig::Create {
into: "@returns".to_string(),
value: ValueKind::Mutable,
reason: ValueReason::KnownReturnSignature,
},
AliasingEffectConfig::Capture {
from: "@object".to_string(),
into: "@returns".to_string(),
},
],
}),
..Default::default()
},
None,
false,
);
let object_global = add_object(
shapes,
Some("Object"),
vec![
("keys".to_string(), obj_keys),
("fromEntries".to_string(), obj_from_entries),
("entries".to_string(), obj_entries),
("values".to_string(), obj_values),
],
);
typed_globals.push(("Object".to_string(), object_global.clone()));
globals.insert("Object".to_string(), object_global);
let array_is_array = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::Read],
return_type: Type::Primitive,
return_value_kind: ValueKind::Primitive,
..Default::default()
},
None,
false,
);
let array_from = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![
Effect::ConditionallyMutateIterator,
Effect::ConditionallyMutate,
Effect::ConditionallyMutate,
],
rest_param: Some(Effect::Read),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let array_of = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Object {
shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let array_global = add_object(
shapes,
Some("Array"),
vec![
("isArray".to_string(), array_is_array),
("from".to_string(), array_from),
("of".to_string(), array_of),
],
);
typed_globals.push(("Array".to_string(), array_global.clone()));
globals.insert("Array".to_string(), array_global);
let math_fns: Vec<(String, Type)> = ["max", "min", "trunc", "ceil", "floor", "pow"]
.iter()
.map(|name| (name.to_string(), pure_primitive_fn(shapes)))
.collect();
let mut math_props = math_fns;
math_props.push(("PI".to_string(), Type::Primitive));
let math_random = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
impure: true,
canonical_name: Some("Math.random".to_string()),
..Default::default()
},
None,
false,
);
math_props.push(("random".to_string(), math_random));
let math_global = add_object(shapes, Some("Math"), math_props);
typed_globals.push(("Math".to_string(), math_global.clone()));
globals.insert("Math".to_string(), math_global);
let perf_now = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
impure: true,
canonical_name: Some("performance.now".to_string()),
..Default::default()
},
None,
false,
);
let perf_global = add_object(
shapes,
Some("performance"),
vec![("now".to_string(), perf_now)],
);
typed_globals.push(("performance".to_string(), perf_global.clone()));
globals.insert("performance".to_string(), perf_global);
let date_now = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Read),
return_type: Type::Poly,
return_value_kind: ValueKind::Mutable,
impure: true,
canonical_name: Some("Date.now".to_string()),
..Default::default()
},
None,
false,
);
let date_global = add_object(shapes, Some("Date"), vec![("now".to_string(), date_now)]);
typed_globals.push(("Date".to_string(), date_global.clone()));
globals.insert("Date".to_string(), date_global);
let console_methods: Vec<(String, Type)> = ["error", "info", "log", "table", "trace", "warn"]
.iter()
.map(|name| (name.to_string(), pure_primitive_fn(shapes)))
.collect();
let console_global = add_object(shapes, Some("console"), console_methods);
typed_globals.push(("console".to_string(), console_global.clone()));
globals.insert("console".to_string(), console_global);
for name in &[
"Boolean",
"Number",
"String",
"parseInt",
"parseFloat",
"isNaN",
"isFinite",
"encodeURI",
"encodeURIComponent",
"decodeURI",
"decodeURIComponent",
] {
let f = pure_primitive_fn(shapes);
typed_globals.push((name.to_string(), f.clone()));
globals.insert(name.to_string(), f);
}
typed_globals.push(("Infinity".to_string(), Type::Primitive));
globals.insert("Infinity".to_string(), Type::Primitive);
typed_globals.push(("NaN".to_string(), Type::Primitive));
globals.insert("NaN".to_string(), Type::Primitive);
let map_ctor = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::ConditionallyMutateIterator],
return_type: Type::Object {
shape_id: Some(BUILT_IN_MAP_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
true,
);
typed_globals.push(("Map".to_string(), map_ctor.clone()));
globals.insert("Map".to_string(), map_ctor);
let set_ctor = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::ConditionallyMutateIterator],
return_type: Type::Object {
shape_id: Some(BUILT_IN_SET_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
true,
);
typed_globals.push(("Set".to_string(), set_ctor.clone()));
globals.insert("Set".to_string(), set_ctor);
let weak_map_ctor = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::ConditionallyMutateIterator],
return_type: Type::Object {
shape_id: Some(BUILT_IN_WEAK_MAP_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
true,
);
typed_globals.push(("WeakMap".to_string(), weak_map_ctor.clone()));
globals.insert("WeakMap".to_string(), weak_map_ctor);
let weak_set_ctor = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
positional_params: vec![Effect::ConditionallyMutateIterator],
return_type: Type::Object {
shape_id: Some(BUILT_IN_WEAK_SET_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
true,
);
typed_globals.push(("WeakSet".to_string(), weak_set_ctor.clone()));
globals.insert("WeakSet".to_string(), weak_set_ctor);
let react_create_element = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
..Default::default()
},
None,
false,
);
let react_clone_element = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
..Default::default()
},
None,
false,
);
let react_create_ref = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Capture),
return_type: Type::Object {
shape_id: Some(BUILT_IN_USE_REF_ID.to_string()),
},
return_value_kind: ValueKind::Mutable,
..Default::default()
},
None,
false,
);
let mut react_props: Vec<(String, Type)> = react_apis;
react_props.push(("createElement".to_string(), react_create_element));
react_props.push(("cloneElement".to_string(), react_clone_element));
react_props.push(("createRef".to_string(), react_create_ref));
let react_global = add_object(shapes, None, react_props);
typed_globals.push(("React".to_string(), react_global.clone()));
globals.insert("React".to_string(), react_global);
let jsx_fn = add_function(
shapes,
Vec::new(),
FunctionSignatureBuilder {
rest_param: Some(Effect::Freeze),
return_type: Type::Poly,
return_value_kind: ValueKind::Frozen,
..Default::default()
},
None,
false,
);
typed_globals.push(("_jsx".to_string(), jsx_fn.clone()));
globals.insert("_jsx".to_string(), jsx_fn);
typed_globals
}