sim_lib_lang_javascript/objects/
function.rs1#[derive(Clone, Debug, Eq, Hash, PartialEq)]
4pub enum JavascriptPropertyKey {
5 String(String),
7 Symbol(u64),
9 Private {
11 class: ManagedId,
13 name: String,
15 },
16}
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum JavascriptFunctionKind {
20 Function,
22 Arrow,
24 ClassConstructor,
26}
27
28#[derive(Clone, Debug)]
30pub struct JavascriptFunctionPolicy {
31 pub kind: JavascriptFunctionKind,
33 pub constructable: bool,
35 pub defaults: BTreeMap<Symbol, JavascriptValue>,
37 pub asynchronous: bool,
39 pub generator: bool,
41 pub realm: Symbol,
43 pub error_origin: String,
45}
46
47#[derive(Clone, Debug, Eq, PartialEq)]
49pub struct JavascriptCallError {
50 pub origin: String,
52 pub message: String,
54}
55
56#[derive(Clone, Debug)]
59pub struct JavascriptFunction {
60 plan: FunctionPlan,
61 captures: Vec<CapturedBinding>,
62 policy: JavascriptFunctionPolicy,
63 pub private_names: Vec<String>,
65}
66
67impl JavascriptFunction {
68 pub fn new(
70 plan: FunctionPlan,
71 captures: Vec<CapturedBinding>,
72 policy: JavascriptFunctionPolicy,
73 private_names: Vec<String>,
74 ) -> Result<Self, InstanceError> {
75 validate_capture_bindings(&plan, &captures)?;
76 Ok(Self {
77 plan,
78 captures,
79 policy,
80 private_names,
81 })
82 }
83
84 pub const fn plan(&self) -> &FunctionPlan {
86 &self.plan
87 }
88
89 pub fn captures(&self) -> &[CapturedBinding] {
91 &self.captures
92 }
93
94 pub const fn policy(&self) -> &JavascriptFunctionPolicy {
96 &self.policy
97 }
98
99 pub fn bind_arguments(
101 &self,
102 arguments: &[JavascriptValue],
103 ) -> Result<BTreeMap<Symbol, Vec<JavascriptValue>>, JavascriptCallError> {
104 let mut bound = BTreeMap::new();
105 let mut at = 0;
106 for parameter in self.plan.parameters() {
107 let values = match parameter.kind() {
108 ParameterKind::Remainder => {
109 let values = arguments[at..].to_vec();
110 at = arguments.len();
111 values
112 }
113 ParameterKind::Required => {
114 let Some(value) = arguments.get(at) else {
115 return self
116 .bind_error(format!("missing required argument {}", parameter.name()));
117 };
118 at += 1;
119 vec![value.clone()]
120 }
121 ParameterKind::Optional => {
122 let supplied = arguments.get(at);
123 let value = match supplied {
124 Some(JavascriptValue::Undefined) | None => self
125 .policy
126 .defaults
127 .get(parameter.name())
128 .cloned()
129 .or_else(|| supplied.cloned()),
130 Some(value) => Some(value.clone()),
131 };
132 if supplied.is_some() {
133 at += 1;
134 }
135 vec![value.unwrap_or(JavascriptValue::Undefined)]
136 }
137 };
138 bound.insert(parameter.name().clone(), values);
139 }
140 if at != arguments.len() {
141 return self.bind_error("too many arguments".into());
142 }
143 Ok(bound)
144 }
145
146 fn bind_error<T>(&self, message: String) -> Result<T, JavascriptCallError> {
147 Err(JavascriptCallError {
148 origin: self.policy.error_origin.clone(),
149 message,
150 })
151 }
152}
153
154#[derive(Clone, Debug, PartialEq)]
156pub enum JavascriptThis {
157 Lexical(JavascriptValue),
159 Dynamic(JavascriptValue),
161}
162
163#[derive(Clone, Copy, Debug, Eq, PartialEq)]
166pub enum JavascriptObjectGap {
167 ProxyInvariants,
169 ExoticObjectInvariants,
171}
172
173#[derive(Clone, Debug, Eq, PartialEq)]
175pub enum JavascriptObjectError {
176 Arena(ArenaError),
178 ManagedGraph(JavascriptManagedMutationError),
180 Descriptor(DefineError),
182 Access,
184 PrototypeCycle,
186 NotConstructor,
188 PrivateBrand,
190}
191impl From<ArenaError> for JavascriptObjectError {
192 fn from(v: ArenaError) -> Self {
193 Self::Arena(v)
194 }
195}
196
197impl From<JavascriptManagedMutationError> for JavascriptObjectError {
198 fn from(value: JavascriptManagedMutationError) -> Self {
199 Self::ManagedGraph(value)
200 }
201}
202impl From<DefineError> for JavascriptObjectError {
203 fn from(v: DefineError) -> Self {
204 Self::Descriptor(v)
205 }
206}
207
208#[derive(Clone, Debug, PartialEq)]
209struct Accessor {
210 get: Option<JavascriptValue>,
211 set: bool,
212}
213#[derive(Default)]
214struct Hooks {
215 writes: Vec<(ManagedId, JavascriptPropertyKey, JavascriptValue)>,
216}
217impl PropertyHook<ManagedId, JavascriptPropertyKey, JavascriptValue, Accessor> for Hooks {
218 type Error = ();
219 fn get(
220 &mut self,
221 _: &mut AccessContext<ManagedId, JavascriptPropertyKey>,
222 hook: &Accessor,
223 _: &ManagedId,
224 _: &JavascriptPropertyKey,
225 ) -> Result<JavascriptValue, AccessError<()>> {
226 hook.get.clone().ok_or(AccessError::Hook(()))
227 }
228 fn set(
229 &mut self,
230 _: &mut AccessContext<ManagedId, JavascriptPropertyKey>,
231 hook: &Accessor,
232 receiver: &ManagedId,
233 key: &JavascriptPropertyKey,
234 value: JavascriptValue,
235 ) -> Result<(), AccessError<()>> {
236 if !hook.set {
237 return Err(AccessError::Hook(()));
238 }
239 self.writes.push((*receiver, key.clone(), value));
240 Ok(())
241 }
242}