1use crate::host::HostFunction;
2use crate::object::object::JSObject;
3use crate::runtime::context::JSContext;
4use crate::value::JSValue;
5
6fn create_builtin_function(ctx: &mut JSContext, name: &str) -> JSValue {
7 let mut func = crate::object::function::JSFunction::new_builtin(ctx.intern(name), 1);
8 func.set_builtin_marker(ctx, name);
9 let ptr = Box::into_raw(Box::new(func)) as usize;
10 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
11 JSValue::new_function(ptr)
12}
13
14pub fn init_error(ctx: &mut JSContext) {
15 let error_atom = ctx.intern("Error");
16
17 let mut error_func = crate::object::function::JSFunction::new_builtin(error_atom, 1);
18 error_func.set_builtin_marker(ctx, "error_constructor");
19 let error_ptr = Box::into_raw(Box::new(error_func)) as usize;
20 ctx.runtime_mut().gc_heap_mut().track_function(error_ptr);
21 let error_value = JSValue::new_function(error_ptr);
22
23 let global = ctx.global();
24 if global.is_object() {
25 let global_obj = global.as_object_mut();
26 global_obj.set(error_atom, error_value);
27 }
28
29 let mut proto_obj = JSObject::new();
30 proto_obj.set(ctx.intern("name"), JSValue::new_string(ctx.intern("Error")));
31 proto_obj.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
32 proto_obj.set(
33 ctx.intern("toString"),
34 create_builtin_function(ctx, "error_toString"),
35 );
36
37 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
38 proto_obj.prototype = Some(obj_proto_ptr);
39 }
40
41 proto_obj.set(ctx.intern("constructor"), error_value);
42
43 let proto_ptr = Box::into_raw(Box::new(proto_obj)) as usize;
44 ctx.set_error_prototype(proto_ptr);
45 let proto_value = JSValue::new_object(proto_ptr);
46 if ctx.get_builtin_func("error_constructor").is_some() {
47 let f = unsafe { JSValue::function_from_ptr_mut(error_ptr) };
48 f.base.set(ctx.intern("prototype"), proto_value);
49 }
50
51 let proto_atom = ctx.intern("ErrorPrototype");
52 if global.is_object() {
53 let global_obj = global.as_object_mut();
54 global_obj.set(proto_atom, proto_value);
55 }
56
57 init_type_error(ctx);
58 init_reference_error(ctx);
59 init_syntax_error(ctx);
60 init_range_error(ctx);
61}
62
63fn init_type_error(ctx: &mut JSContext) {
64 let atom = ctx.intern("TypeError");
65 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
66 ctor.set_builtin_marker(ctx, "type_error_constructor");
67 let ptr = Box::into_raw(Box::new(ctor)) as usize;
68 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
69 let value = JSValue::new_function(ptr);
70
71 let global = ctx.global();
72 if global.is_object() {
73 let global_obj = global.as_object_mut();
74 global_obj.set(atom, value);
75 }
76
77 let mut proto = JSObject::new();
78 proto.set(
79 ctx.intern("name"),
80 JSValue::new_string(ctx.intern("TypeError")),
81 );
82 proto.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
83
84 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
85 proto.prototype = Some(error_proto_ptr);
86 }
87 proto.set(ctx.intern("constructor"), value);
88
89 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
90 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
91 let proto_value = JSValue::new_object(proto_ptr);
92 ctx.set_type_error_prototype(proto_ptr);
93 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
94 ctor.base.set(ctx.intern("prototype"), proto_value);
95}
96
97fn init_reference_error(ctx: &mut JSContext) {
98 let atom = ctx.intern("ReferenceError");
99 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
100 ctor.set_builtin_marker(ctx, "reference_error_constructor");
101 let ptr = Box::into_raw(Box::new(ctor)) as usize;
102 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
103 let value = JSValue::new_function(ptr);
104
105 let mut proto = JSObject::new();
106 proto.set(
107 ctx.intern("name"),
108 JSValue::new_string(ctx.intern("ReferenceError")),
109 );
110 proto.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
111 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
112 proto.prototype = Some(error_proto_ptr);
113 }
114 proto.set(ctx.intern("constructor"), value);
115
116 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
117 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
118 let proto_value = JSValue::new_object(proto_ptr);
119 ctx.set_reference_error_prototype(proto_ptr);
120 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
121 ctor.base.set(ctx.intern("prototype"), proto_value);
122
123 let global = ctx.global();
124 if global.is_object() {
125 let global_obj = global.as_object_mut();
126 global_obj.set(atom, value);
127 }
128}
129
130fn init_syntax_error(ctx: &mut JSContext) {
131 let atom = ctx.intern("SyntaxError");
132 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
133 ctor.set_builtin_marker(ctx, "syntax_error_constructor");
134 let ptr = Box::into_raw(Box::new(ctor)) as usize;
135 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
136 let value = JSValue::new_function(ptr);
137
138 let mut proto = JSObject::new();
139 proto.set(
140 ctx.intern("name"),
141 JSValue::new_string(ctx.intern("SyntaxError")),
142 );
143 proto.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
144 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
145 proto.prototype = Some(error_proto_ptr);
146 }
147 proto.set(ctx.intern("constructor"), value);
148
149 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
150 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
151 let proto_value = JSValue::new_object(proto_ptr);
152 ctx.set_syntax_error_prototype(proto_ptr);
153 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
154 ctor.base.set(ctx.intern("prototype"), proto_value);
155
156 let global = ctx.global();
157 if global.is_object() {
158 let global_obj = global.as_object_mut();
159 global_obj.set(atom, value);
160 }
161}
162
163fn init_range_error(ctx: &mut JSContext) {
164 let atom = ctx.intern("RangeError");
165 let mut ctor = crate::object::function::JSFunction::new_builtin(atom, 1);
166 ctor.set_builtin_marker(ctx, "range_error_constructor");
167 let ptr = Box::into_raw(Box::new(ctor)) as usize;
168 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
169 let value = JSValue::new_function(ptr);
170
171 let mut proto = JSObject::new();
172 proto.set(
173 ctx.intern("name"),
174 JSValue::new_string(ctx.intern("RangeError")),
175 );
176 proto.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
177 if let Some(error_proto_ptr) = ctx.get_error_prototype() {
178 proto.prototype = Some(error_proto_ptr);
179 }
180 proto.set(ctx.intern("constructor"), value);
181
182 let proto_ptr = Box::into_raw(Box::new(proto)) as usize;
183 ctx.runtime_mut().gc_heap_mut().track(proto_ptr);
184 let proto_value = JSValue::new_object(proto_ptr);
185 ctx.set_range_error_prototype(proto_ptr);
186 let ctor = unsafe { JSValue::function_from_ptr_mut(ptr) };
187 ctor.base.set(ctx.intern("prototype"), proto_value);
188
189 let global = ctx.global();
190 if global.is_object() {
191 let global_obj = global.as_object_mut();
192 global_obj.set(atom, value);
193 }
194}
195
196pub fn error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
197 let mut err = JSObject::new();
198 err.set(ctx.intern("name"), JSValue::new_string(ctx.intern("Error")));
199
200 if !args.is_empty() && args[0].is_string() {
201 err.set(ctx.intern("message"), args[0]);
202 } else {
203 err.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
204 }
205
206 if args.len() > 1 && args[1].is_object() {
207 let opts = args[1].as_object();
208 if let Some(cause) = opts.get(ctx.intern("cause")) {
209 err.set(ctx.intern("cause"), cause);
210 }
211 }
212
213 if let Some(proto) = ctx.get_error_prototype() {
214 err.prototype = Some(proto as *mut _);
215 }
216
217 let ptr = Box::into_raw(Box::new(err)) as usize;
218 ctx.runtime_mut().gc_heap_mut().track(ptr);
219 JSValue::new_object(ptr)
220}
221
222pub fn type_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
223 let mut err = JSObject::new();
224 err.set(
225 ctx.intern("name"),
226 JSValue::new_string(ctx.intern("TypeError")),
227 );
228
229 if !args.is_empty() && args[0].is_string() {
230 err.set(ctx.intern("message"), args[0]);
231 } else {
232 err.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
233 }
234
235 if args.len() > 1 && args[1].is_object() {
236 let opts = args[1].as_object();
237 if let Some(cause) = opts.get(ctx.intern("cause")) {
238 err.set(ctx.intern("cause"), cause);
239 }
240 }
241
242 if let Some(proto) = ctx.get_type_error_prototype() {
243 err.prototype = Some(proto as *mut _);
244 }
245
246 let ptr = Box::into_raw(Box::new(err)) as usize;
247 ctx.runtime_mut().gc_heap_mut().track(ptr);
248 JSValue::new_object(ptr)
249}
250
251pub fn reference_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
252 let mut err = JSObject::new();
253 err.set(
254 ctx.intern("name"),
255 JSValue::new_string(ctx.intern("ReferenceError")),
256 );
257
258 if !args.is_empty() && args[0].is_string() {
259 err.set(ctx.intern("message"), args[0]);
260 } else {
261 err.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
262 }
263
264 if args.len() > 1 && args[1].is_object() {
265 let opts = args[1].as_object();
266 if let Some(cause) = opts.get(ctx.intern("cause")) {
267 err.set(ctx.intern("cause"), cause);
268 }
269 }
270
271 if let Some(proto) = ctx.get_reference_error_prototype() {
272 err.prototype = Some(proto as *mut _);
273 } else if let Some(proto) = ctx.get_error_prototype() {
274 err.prototype = Some(proto as *mut _);
275 }
276
277 let ptr = Box::into_raw(Box::new(err)) as usize;
278 ctx.runtime_mut().gc_heap_mut().track(ptr);
279 JSValue::new_object(ptr)
280}
281
282pub fn syntax_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
283 let mut err = JSObject::new();
284 err.set(
285 ctx.intern("name"),
286 JSValue::new_string(ctx.intern("SyntaxError")),
287 );
288
289 if !args.is_empty() && args[0].is_string() {
290 err.set(ctx.intern("message"), args[0]);
291 } else {
292 err.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
293 }
294
295 if args.len() > 1 && args[1].is_object() {
296 let opts = args[1].as_object();
297 if let Some(cause) = opts.get(ctx.intern("cause")) {
298 err.set(ctx.intern("cause"), cause);
299 }
300 }
301
302 if let Some(proto) = ctx.get_syntax_error_prototype() {
303 err.prototype = Some(proto as *mut _);
304 }
305
306 let ptr = Box::into_raw(Box::new(err)) as usize;
307 ctx.runtime_mut().gc_heap_mut().track(ptr);
308 JSValue::new_object(ptr)
309}
310
311pub fn range_error_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
312 let mut err = JSObject::new();
313 err.set(
314 ctx.intern("name"),
315 JSValue::new_string(ctx.intern("RangeError")),
316 );
317
318 if !args.is_empty() && args[0].is_string() {
319 err.set(ctx.intern("message"), args[0]);
320 } else {
321 err.set(ctx.intern("message"), JSValue::new_string(ctx.intern("")));
322 }
323
324 if args.len() > 1 && args[1].is_object() {
325 let opts = args[1].as_object();
326 if let Some(cause) = opts.get(ctx.intern("cause")) {
327 err.set(ctx.intern("cause"), cause);
328 }
329 }
330
331 if let Some(proto) = ctx.get_range_error_prototype() {
332 err.prototype = Some(proto as *mut _);
333 } else if let Some(proto) = ctx.get_error_prototype() {
334 err.prototype = Some(proto as *mut _);
335 }
336
337 let ptr = Box::into_raw(Box::new(err)) as usize;
338 ctx.runtime_mut().gc_heap_mut().track(ptr);
339 JSValue::new_object(ptr)
340}
341
342fn error_to_string(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
343 if args.is_empty() {
344 return JSValue::new_string(ctx.intern("Error"));
345 }
346 let this = &args[0];
347 if !this.is_object() {
348 return JSValue::new_string(ctx.intern("Error"));
349 }
350
351 let obj = this.as_object();
352
353 let name = if let Some(n) = obj.get(ctx.intern("name")) {
354 if n.is_string() {
355 ctx.get_atom_str(n.get_atom()).to_string()
356 } else {
357 "Error".to_string()
358 }
359 } else {
360 "Error".to_string()
361 };
362
363 let message = if let Some(m) = obj.get(ctx.intern("message")) {
364 if m.is_string() {
365 ctx.get_atom_str(m.get_atom()).to_string()
366 } else {
367 String::new()
368 }
369 } else {
370 String::new()
371 };
372
373 if message.is_empty() {
374 JSValue::new_string(ctx.intern(&name))
375 } else {
376 JSValue::new_string(ctx.intern(&format!("{}: {}", name, message)))
377 }
378}
379
380pub fn register_builtins(ctx: &mut JSContext) {
381 ctx.register_builtin(
382 "error_constructor",
383 HostFunction::new("Error", 1, error_constructor),
384 );
385 ctx.register_builtin(
386 "type_error_constructor",
387 HostFunction::new("TypeError", 1, type_error_constructor),
388 );
389 ctx.register_builtin(
390 "reference_error_constructor",
391 HostFunction::new("ReferenceError", 1, reference_error_constructor),
392 );
393 ctx.register_builtin(
394 "syntax_error_constructor",
395 HostFunction::new("SyntaxError", 1, syntax_error_constructor),
396 );
397 ctx.register_builtin(
398 "range_error_constructor",
399 HostFunction::new("RangeError", 1, range_error_constructor),
400 );
401 ctx.register_builtin(
402 "error_toString",
403 HostFunction::new("toString", 0, error_to_string),
404 );
405}