javascript/
core.rs

1#![allow(clippy::collapsible_if, clippy::collapsible_match)]
2
3use crate::error::JSError;
4use crate::js_promise::{PromiseState, run_event_loop};
5use crate::raise_eval_error;
6use crate::unicode::utf8_to_utf16;
7use std::cell::RefCell;
8use std::collections::HashMap;
9use std::rc::Rc;
10
11mod value;
12pub use value::*;
13
14mod property_key;
15pub use property_key::*;
16
17mod statement;
18pub use statement::*;
19
20mod token;
21pub use token::*;
22
23mod number;
24
25mod eval;
26pub use eval::*;
27
28mod parser;
29pub use parser::*;
30
31thread_local! {
32    // Well-known symbols storage (iterator, toStringTag, etc.)
33    static WELL_KNOWN_SYMBOLS: RefCell<HashMap<String, Rc<RefCell<Value>>>> = RefCell::new(HashMap::new());
34}
35
36pub fn evaluate_script<T, P>(script: T, script_path: Option<P>) -> Result<Value, JSError>
37where
38    T: AsRef<str>,
39    P: AsRef<std::path::Path>,
40{
41    let script = script.as_ref();
42    log::debug!("evaluate_script async called with script len {}", script.len());
43    let filtered = filter_input_script(script);
44    log::trace!("filtered script:\n{}", filtered);
45    let mut tokens = match tokenize(&filtered) {
46        Ok(t) => t,
47        Err(e) => {
48            log::debug!("tokenize error: {e:?}");
49            return Err(e);
50        }
51    };
52    let statements = match parse_statements(&mut tokens) {
53        Ok(s) => s,
54        Err(e) => {
55            log::debug!("parse_statements error: {e:?}");
56            return Err(e);
57        }
58    };
59    log::debug!("parsed {} statements", statements.len());
60    for (i, stmt) in statements.iter().enumerate() {
61        log::trace!("stmt[{i}] = {stmt:?}");
62    }
63    let env: JSObjectDataPtr = new_js_object_data();
64    env.borrow_mut().is_function_scope = true;
65    // Record a script name on the root environment so stack frames can include it.
66    let path = script_path.map_or("<script>".to_string(), |p| p.as_ref().to_string_lossy().to_string());
67    let _ = obj_set_key_value(&env, &"__script_name".into(), Value::String(utf8_to_utf16(&path)));
68
69    // Inject simple host `std` / `os` shims when importing with the pattern:
70    //   import * as NAME from "std";
71    for line in script.lines() {
72        let l = line.trim();
73        if l.starts_with("import * as")
74            && l.contains("from")
75            && let (Some(as_idx), Some(from_idx)) = (l.find("as"), l.find("from"))
76        {
77            let name_part = &l[as_idx + 2..from_idx].trim();
78            let name = PropertyKey::String(name_part.trim().to_string());
79            if let Some(start_quote) = l[from_idx..].find(|c: char| ['"', '\''].contains(&c)) {
80                let quote_char = l[from_idx + start_quote..].chars().next().unwrap();
81                let rest = &l[from_idx + start_quote + 1..];
82                if let Some(end_quote) = rest.find(quote_char) {
83                    let module = &rest[..end_quote];
84                    if module == "std" {
85                        obj_set_key_value(&env, &name, Value::Object(crate::js_std::make_std_object()?))?;
86                    } else if module == "os" {
87                        obj_set_key_value(&env, &name, Value::Object(crate::js_os::make_os_object()?))?;
88                    }
89                }
90            }
91        }
92    }
93
94    // Initialize global built-in constructors
95    initialize_global_constructors(&env)?;
96
97    let v = evaluate_statements(&env, &statements)?;
98    // If the result is a Promise object (wrapped in Object with __promise property), wait for it to resolve
99    if let Value::Object(obj) = &v
100        && let Some(promise_val_rc) = obj_get_key_value(obj, &"__promise".into())?
101        && let Value::Promise(promise) = &*promise_val_rc.borrow()
102    {
103        // Run the event loop until the promise is resolved
104        loop {
105            run_event_loop()?;
106            let promise_borrow = promise.borrow();
107            match &promise_borrow.state {
108                PromiseState::Fulfilled(val) => return Ok(val.clone()),
109                PromiseState::Rejected(reason) => {
110                    return Err(raise_eval_error!(format!("Promise rejected: {}", value_to_string(reason))));
111                }
112                PromiseState::Pending => {
113                    // Continue running the event loop
114                }
115            }
116        }
117    }
118    // Run the event loop to process any queued asynchronous tasks
119    run_event_loop()?;
120    Ok(v)
121}
122
123// Helper to ensure a constructor-like object exists in the root env.
124// Creates an object, marks it with `marker_key` (e.g. "__is_string_constructor")
125// creates an empty `prototype` object whose internal prototype points to
126// `Object.prototype` when available, stores the constructor in `env` under
127// `name`, and returns the constructor object pointer.
128pub fn ensure_constructor_object(env: &JSObjectDataPtr, name: &str, marker_key: &str) -> Result<JSObjectDataPtr, JSError> {
129    // If already present and is an object, return it
130    if let Some(val_rc) = obj_get_key_value(env, &name.into())? {
131        if let Value::Object(obj) = &*val_rc.borrow() {
132            return Ok(obj.clone());
133        }
134    }
135
136    let ctor = new_js_object_data();
137    // mark constructor
138    obj_set_key_value(&ctor, &marker_key.into(), Value::Boolean(true))?;
139
140    // create prototype object
141    let proto = new_js_object_data();
142    // link prototype.__proto__ to Object.prototype if available
143    if let Some(object_ctor_val) = obj_get_key_value(env, &"Object".into())?
144        && let Value::Object(object_ctor) = &*object_ctor_val.borrow()
145        && let Some(obj_proto_val) = obj_get_key_value(object_ctor, &"prototype".into())?
146        && let Value::Object(obj_proto_obj) = &*obj_proto_val.borrow()
147    {
148        proto.borrow_mut().prototype = Some(obj_proto_obj.clone());
149    }
150
151    obj_set_key_value(&ctor, &"prototype".into(), Value::Object(proto.clone()))?;
152    // Ensure prototype.constructor points back to the constructor object
153    obj_set_key_value(&proto, &"constructor".into(), Value::Object(ctor.clone()))?;
154
155    obj_set_key_value(env, &name.into(), Value::Object(ctor.clone()))?;
156    Ok(ctor)
157}
158
159// Helper to resolve a constructor's prototype object if present in `env`.
160pub fn get_constructor_prototype(env: &JSObjectDataPtr, name: &str) -> Result<Option<JSObjectDataPtr>, JSError> {
161    // First try to find a constructor object already stored in the environment
162    if let Some(val_rc) = obj_get_key_value(env, &name.into())? {
163        if let Value::Object(ctor_obj) = &*val_rc.borrow() {
164            if let Some(proto_val_rc) = obj_get_key_value(ctor_obj, &"prototype".into())? {
165                if let Value::Object(proto_obj) = &*proto_val_rc.borrow() {
166                    return Ok(Some(proto_obj.clone()));
167                }
168            }
169        }
170    }
171
172    // If not found, attempt to evaluate the variable to force lazy creation
173    match evaluate_expr(env, &Expr::Var(name.to_string())) {
174        Ok(Value::Object(ctor_obj)) => {
175            if let Some(proto_val_rc) = obj_get_key_value(&ctor_obj, &"prototype".into())? {
176                if let Value::Object(proto_obj) = &*proto_val_rc.borrow() {
177                    return Ok(Some(proto_obj.clone()));
178                }
179            }
180            Ok(None)
181        }
182        _ => Ok(None),
183    }
184}
185
186// Helper to set an object's internal prototype from a constructor name.
187// If the constructor.prototype is available, sets `obj.borrow_mut().prototype`
188// to that object. This consolidates the common pattern used when boxing
189// primitives and creating instances.
190pub fn set_internal_prototype_from_constructor(obj: &JSObjectDataPtr, env: &JSObjectDataPtr, ctor_name: &str) -> Result<(), JSError> {
191    if let Some(proto_obj) = get_constructor_prototype(env, ctor_name)? {
192        // set internal prototype pointer
193        obj.borrow_mut().prototype = Some(proto_obj.clone());
194    }
195    Ok(())
196}
197
198// Helper to initialize a collection from an iterable argument.
199// Used by Map, Set, WeakMap, WeakSet constructors.
200pub fn initialize_collection_from_iterable<F>(
201    args: &[Expr],
202    env: &JSObjectDataPtr,
203    constructor_name: &str,
204    mut process_item: F,
205) -> Result<(), JSError>
206where
207    F: FnMut(Value) -> Result<(), JSError>,
208{
209    if args.is_empty() {
210        return Ok(());
211    }
212    if args.len() > 1 {
213        let msg = format!("{constructor_name} constructor takes at most one argument",);
214        return Err(raise_eval_error!(msg));
215    }
216    let iterable = evaluate_expr(env, &args[0])?;
217    match iterable {
218        Value::Object(obj) => {
219            let mut i = 0;
220            loop {
221                let key = format!("{i}");
222                if let Some(item_val) = obj_get_key_value(&obj, &key.into())? {
223                    let item = item_val.borrow().clone();
224                    process_item(item)?;
225                } else {
226                    break;
227                }
228                i += 1;
229            }
230            Ok(())
231        }
232        _ => Err(raise_eval_error!(format!("{constructor_name} constructor requires an iterable"))),
233    }
234}
235
236#[derive(Debug, Clone)]
237pub enum Expr {
238    Number(f64),
239    /// BigInt literal (string form)
240    BigInt(String),
241    StringLit(Vec<u16>),
242    Boolean(bool),
243    Var(String),
244    Binary(Box<Expr>, BinaryOp, Box<Expr>),
245    UnaryNeg(Box<Expr>),
246    LogicalNot(Box<Expr>),
247    TypeOf(Box<Expr>),
248    Delete(Box<Expr>),
249    Void(Box<Expr>),
250    Assign(Box<Expr>, Box<Expr>),                   // target, value
251    LogicalAndAssign(Box<Expr>, Box<Expr>),         // target, value
252    LogicalOrAssign(Box<Expr>, Box<Expr>),          // target, value
253    NullishAssign(Box<Expr>, Box<Expr>),            // target, value
254    AddAssign(Box<Expr>, Box<Expr>),                // target, value
255    SubAssign(Box<Expr>, Box<Expr>),                // target, value
256    PowAssign(Box<Expr>, Box<Expr>),                // target, value
257    MulAssign(Box<Expr>, Box<Expr>),                // target, value
258    DivAssign(Box<Expr>, Box<Expr>),                // target, value
259    ModAssign(Box<Expr>, Box<Expr>),                // target, value
260    BitXorAssign(Box<Expr>, Box<Expr>),             // target, value
261    BitAndAssign(Box<Expr>, Box<Expr>),             // target, value
262    BitOrAssign(Box<Expr>, Box<Expr>),              // target, value
263    LeftShiftAssign(Box<Expr>, Box<Expr>),          // target, value
264    RightShiftAssign(Box<Expr>, Box<Expr>),         // target, value
265    UnsignedRightShiftAssign(Box<Expr>, Box<Expr>), // target, value
266    Increment(Box<Expr>),
267    Decrement(Box<Expr>),
268    PostIncrement(Box<Expr>),
269    PostDecrement(Box<Expr>),
270    Index(Box<Expr>, Box<Expr>),
271    Property(Box<Expr>, String),
272    Call(Box<Expr>, Vec<Expr>),
273    Function(Vec<String>, Vec<Statement>),                // parameters, body
274    AsyncFunction(Vec<String>, Vec<Statement>),           // parameters, body for async functions
275    GeneratorFunction(Vec<String>, Vec<Statement>),       // parameters, body for generator functions
276    ArrowFunction(Vec<String>, Vec<Statement>),           // parameters, body
277    AsyncArrowFunction(Vec<String>, Vec<Statement>),      // parameters, body for async arrow functions
278    Object(Vec<(String, Expr)>),                          // object literal: key-value pairs
279    Array(Vec<Expr>),                                     // array literal: [elem1, elem2, ...]
280    Getter(Box<Expr>),                                    // getter function
281    Setter(Box<Expr>),                                    // setter function
282    Spread(Box<Expr>),                                    // spread operator: ...expr
283    OptionalProperty(Box<Expr>, String),                  // optional property access: obj?.prop
284    OptionalCall(Box<Expr>, Vec<Expr>),                   // optional call: obj?.method(args)
285    OptionalIndex(Box<Expr>, Box<Expr>),                  // optional bracket access: obj?.[expr]
286    Await(Box<Expr>),                                     // await expression
287    Yield(Option<Box<Expr>>),                             // yield expression (optional value)
288    YieldStar(Box<Expr>),                                 // yield* expression (delegation)
289    This,                                                 // this keyword
290    New(Box<Expr>, Vec<Expr>),                            // new expression: new Constructor(args)
291    Super,                                                // super keyword
292    SuperCall(Vec<Expr>),                                 // super() call in constructor
293    SuperProperty(String),                                // super.property access
294    SuperMethod(String, Vec<Expr>),                       // super.method() call
295    ArrayDestructuring(Vec<DestructuringElement>),        // array destructuring: [a, b, ...rest]
296    ObjectDestructuring(Vec<ObjectDestructuringElement>), // object destructuring: {a, b: c, ...rest}
297    Conditional(Box<Expr>, Box<Expr>, Box<Expr>),         // conditional expression: condition ? trueExpr : falseExpr
298    /// Regular expression literal: pattern, flags
299    Regex(String, String),
300    /// Logical operators with short-circuit semantics
301    LogicalAnd(Box<Expr>, Box<Expr>),
302    LogicalOr(Box<Expr>, Box<Expr>),
303    Value(Value), // literal value
304}
305
306#[derive(Debug, Clone)]
307pub enum BinaryOp {
308    Add,
309    Sub,
310    Mul,
311    Div,
312    Mod,
313    Equal,
314    StrictEqual,
315    NotEqual,
316    StrictNotEqual,
317    LessThan,
318    GreaterThan,
319    LessEqual,
320    GreaterEqual,
321    InstanceOf,
322    In,
323    NullishCoalescing,
324    Pow,
325    BitXor,
326    BitAnd,
327    BitOr,
328    LeftShift,
329    RightShift,
330    UnsignedRightShift,
331}
332
333#[derive(Debug, Clone)]
334pub enum DestructuringElement {
335    Variable(String, Option<Box<Expr>>),           // a or a = default
336    NestedArray(Vec<DestructuringElement>),        // [a, b]
337    NestedObject(Vec<ObjectDestructuringElement>), // {a, b}
338    Rest(String),                                  // ...rest
339    Empty,                                         // for skipped elements: [, b] = [1, 2]
340}
341
342#[derive(Debug, Clone)]
343pub enum ObjectDestructuringElement {
344    Property { key: String, value: DestructuringElement }, // a: b or a
345    Rest(String),                                          // ...rest
346}
347
348pub(crate) fn filter_input_script(script: &str) -> String {
349    // Remove comments and simple import lines that we've already handled via shim injection
350    let mut filtered = String::new();
351    let chars: Vec<char> = script.trim().chars().collect();
352    let mut i = 0;
353    let mut in_single = false;
354    let mut in_double = false;
355    let mut in_backtick = false;
356    let mut escape = false;
357
358    while i < chars.len() {
359        let ch = chars[i];
360
361        // Handle escape sequences
362        if escape {
363            filtered.push(ch);
364            escape = false;
365            i += 1;
366            continue;
367        }
368        if ch == '\\' {
369            escape = true;
370            filtered.push(ch);
371            i += 1;
372            continue;
373        }
374
375        // Handle quote states
376        match ch {
377            '\'' if !in_double && !in_backtick => {
378                in_single = !in_single;
379                filtered.push(ch);
380                i += 1;
381                continue;
382            }
383            '"' if !in_single && !in_backtick => {
384                in_double = !in_double;
385                filtered.push(ch);
386                i += 1;
387                continue;
388            }
389            '`' if !in_single && !in_double => {
390                in_backtick = !in_backtick;
391                filtered.push(ch);
392                i += 1;
393                continue;
394            }
395            _ => {}
396        }
397
398        // Only process comments when not inside quotes
399        if !in_single && !in_double && !in_backtick {
400            // Handle single-line comments: //
401            if i + 1 < chars.len() && ch == '/' && chars[i + 1] == '/' {
402                // Skip to end of line
403                while i < chars.len() && chars[i] != '\n' {
404                    i += 1;
405                }
406                // Don't add the newline yet, continue to next iteration
407                continue;
408            }
409
410            // Handle multi-line comments: /* */
411            if i + 1 < chars.len() && ch == '/' && chars[i + 1] == '*' {
412                i += 2; // Skip /*
413                while i + 1 < chars.len() {
414                    if chars[i] == '*' && chars[i + 1] == '/' {
415                        i += 2; // Skip */
416                        break;
417                    }
418                    i += 1;
419                }
420                continue;
421            }
422        }
423
424        // Handle regular characters and newlines
425        filtered.push(ch);
426        i += 1;
427    }
428
429    // Now process the filtered script line by line for import statements
430    let mut final_filtered = String::new();
431    for (i, line) in filtered.lines().enumerate() {
432        // Split line on semicolons only when not inside quotes/backticks
433        let mut current = String::new();
434        let mut in_single = false;
435        let mut in_double = false;
436        let mut in_backtick = false;
437        let mut escape = false;
438        // track parts along with whether they were followed by a semicolon
439        let mut parts: Vec<(String, bool)> = Vec::new();
440        for ch in line.chars() {
441            if escape {
442                current.push(ch);
443                escape = false;
444                continue;
445            }
446            if ch == '\\' {
447                escape = true;
448                current.push(ch);
449                continue;
450            }
451            match ch {
452                '\'' if !in_double && !in_backtick => {
453                    in_single = !in_single;
454                    current.push(ch);
455                    continue;
456                }
457                '"' if !in_single && !in_backtick => {
458                    in_double = !in_double;
459                    current.push(ch);
460                    continue;
461                }
462                '`' if !in_single && !in_double => {
463                    in_backtick = !in_backtick;
464                    current.push(ch);
465                    continue;
466                }
467                _ => {}
468            }
469            if ch == ';' && !in_single && !in_double && !in_backtick {
470                parts.push((current.clone(), true));
471                current.clear();
472                continue;
473            }
474            current.push(ch);
475        }
476        // If there is a trailing part (possibly no trailing semicolon), add it
477        if !current.is_empty() {
478            parts.push((current, false));
479        }
480
481        for (part, had_semicolon) in parts.iter() {
482            let p = part.trim();
483            if p.is_empty() {
484                continue;
485            }
486            log::trace!("script part[{i}]='{p}'");
487            if p.starts_with("import * as") && p.contains("from") {
488                log::debug!("skipping import part[{i}]: \"{p}\"");
489                continue;
490            }
491            final_filtered.push_str(p);
492            // Re-add semicolon if the original part was followed by a semicolon
493            if *had_semicolon {
494                final_filtered.push(';');
495            }
496        }
497        final_filtered.push('\n');
498    }
499
500    // Remove any trailing newline(s) added during filtering to avoid an extra
501    // empty statement at the end when tokenizing/parsing.
502    final_filtered.trim().to_string()
503}
504
505/// Initialize global built-in constructors in the environment
506pub fn initialize_global_constructors(env: &JSObjectDataPtr) -> Result<(), JSError> {
507    // Create Error constructor object early so its prototype exists.
508    let error_ctor = ensure_constructor_object(env, "Error", "__is_error_constructor")?;
509
510    // Ensure Error.prototype.toString uses our handler
511    if let Some(proto_val) = obj_get_key_value(&error_ctor, &"prototype".into())? {
512        if let Value::Object(proto_obj) = &*proto_val.borrow() {
513            obj_set_key_value(
514                proto_obj,
515                &"toString".into(),
516                Value::Function("Error.prototype.toString".to_string()),
517            )?;
518        }
519    }
520
521    // Create common Error sub-constructors and point their prototype.toString to Error.prototype.toString
522    let error_types = ["TypeError", "SyntaxError", "ReferenceError", "RangeError", "EvalError", "URIError"];
523    for t in error_types.iter() {
524        let ctor = ensure_constructor_object(env, t, &format!("__is_{}_constructor", t.to_lowercase()))?;
525        if let Some(proto_val) = obj_get_key_value(&ctor, &"prototype".into())? {
526            if let Value::Object(proto_obj) = &*proto_val.borrow() {
527                obj_set_key_value(
528                    proto_obj,
529                    &"toString".into(),
530                    Value::Function("Error.prototype.toString".to_string()),
531                )?;
532            }
533        }
534    }
535
536    let mut env_borrow = env.borrow_mut();
537
538    // Object constructor (object with static methods) and Object.prototype
539    let object_obj = new_js_object_data();
540
541    // Add static Object.* methods (handlers routed by presence of keys)
542    obj_set_key_value(&object_obj, &"keys".into(), Value::Function("Object.keys".to_string()))?;
543    obj_set_key_value(&object_obj, &"values".into(), Value::Function("Object.values".to_string()))?;
544    obj_set_key_value(&object_obj, &"assign".into(), Value::Function("Object.assign".to_string()))?;
545    obj_set_key_value(&object_obj, &"create".into(), Value::Function("Object.create".to_string()))?;
546    obj_set_key_value(
547        &object_obj,
548        &"getOwnPropertySymbols".into(),
549        Value::Function("Object.getOwnPropertySymbols".to_string()),
550    )?;
551    obj_set_key_value(
552        &object_obj,
553        &"getOwnPropertyNames".into(),
554        Value::Function("Object.getOwnPropertyNames".to_string()),
555    )?;
556    obj_set_key_value(
557        &object_obj,
558        &"getOwnPropertyDescriptors".into(),
559        Value::Function("Object.getOwnPropertyDescriptors".to_string()),
560    )?;
561
562    // Create Object.prototype and add prototype-level helpers
563    let object_prototype = new_js_object_data();
564    obj_set_key_value(
565        &object_prototype,
566        &"hasOwnProperty".into(),
567        Value::Function("Object.prototype.hasOwnProperty".to_string()),
568    )?;
569    obj_set_key_value(
570        &object_prototype,
571        &"isPrototypeOf".into(),
572        Value::Function("Object.prototype.isPrototypeOf".to_string()),
573    )?;
574    obj_set_key_value(
575        &object_prototype,
576        &"propertyIsEnumerable".into(),
577        Value::Function("Object.prototype.propertyIsEnumerable".to_string()),
578    )?;
579    obj_set_key_value(
580        &object_prototype,
581        &"toString".into(),
582        Value::Function("Object.prototype.toString".to_string()),
583    )?;
584    obj_set_key_value(
585        &object_prototype,
586        &"valueOf".into(),
587        Value::Function("Object.prototype.valueOf".to_string()),
588    )?;
589    // Add toLocaleString to Object.prototype that delegates to toString/locale handling
590    obj_set_key_value(
591        &object_prototype,
592        &"toLocaleString".into(),
593        Value::Function("Object.prototype.toLocaleString".to_string()),
594    )?;
595
596    // wire prototype reference onto constructor
597    obj_set_key_value(&object_obj, &"prototype".into(), Value::Object(object_prototype.clone()))?;
598
599    // expose Object constructor as an object with static methods
600    env_borrow.insert(
601        PropertyKey::String("Object".to_string()),
602        Rc::new(RefCell::new(Value::Object(object_obj))),
603    );
604
605    // Number constructor - handled by evaluate_var
606    // env_borrow.insert(PropertyKey::String("Number".to_string()), Rc::new(RefCell::new(Value::Function("Number".to_string()))));
607
608    // Boolean and String constructors are created lazily by `evaluate_var`
609    // to allow creation of singleton constructor objects with prototypes.
610
611    // Array constructor (already handled by js_array module)
612    env_borrow.insert(
613        PropertyKey::String("Array".to_string()),
614        Rc::new(RefCell::new(Value::Function("Array".to_string()))),
615    );
616
617    // Date constructor (already handled by js_date module)
618    env_borrow.insert(
619        PropertyKey::String("Date".to_string()),
620        Rc::new(RefCell::new(Value::Function("Date".to_string()))),
621    );
622
623    // RegExp constructor (already handled by js_regexp module)
624    env_borrow.insert(
625        PropertyKey::String("RegExp".to_string()),
626        Rc::new(RefCell::new(Value::Function("RegExp".to_string()))),
627    );
628
629    // Symbol constructor
630    env_borrow.insert(
631        PropertyKey::String("Symbol".to_string()),
632        Rc::new(RefCell::new(Value::Function("Symbol".to_string()))),
633    );
634
635    // Map constructor
636    env_borrow.insert(
637        PropertyKey::String("Map".to_string()),
638        Rc::new(RefCell::new(Value::Function("Map".to_string()))),
639    );
640
641    // Set constructor
642    env_borrow.insert(
643        PropertyKey::String("Set".to_string()),
644        Rc::new(RefCell::new(Value::Function("Set".to_string()))),
645    );
646
647    // Proxy constructor
648    env_borrow.insert(
649        PropertyKey::String("Proxy".to_string()),
650        Rc::new(RefCell::new(Value::Function("Proxy".to_string()))),
651    );
652
653    // WeakMap constructor
654    env_borrow.insert(
655        PropertyKey::String("WeakMap".to_string()),
656        Rc::new(RefCell::new(Value::Function("WeakMap".to_string()))),
657    );
658
659    // WeakSet constructor
660    env_borrow.insert(
661        PropertyKey::String("WeakSet".to_string()),
662        Rc::new(RefCell::new(Value::Function("WeakSet".to_string()))),
663    );
664
665    // Create a few well-known symbols and store them in the well-known symbol registry
666    WELL_KNOWN_SYMBOLS.with(|wk| {
667        let mut map = wk.borrow_mut();
668        // Symbol.iterator
669        let iter_sym_data = Rc::new(SymbolData {
670            description: Some("Symbol.iterator".to_string()),
671        });
672        map.insert("iterator".to_string(), Rc::new(RefCell::new(Value::Symbol(iter_sym_data.clone()))));
673
674        // Symbol.toStringTag
675        let tt_sym_data = Rc::new(SymbolData {
676            description: Some("Symbol.toStringTag".to_string()),
677        });
678        map.insert("toStringTag".to_string(), Rc::new(RefCell::new(Value::Symbol(tt_sym_data.clone()))));
679        // Symbol.toPrimitive
680        let tp_sym_data = Rc::new(SymbolData {
681            description: Some("Symbol.toPrimitive".to_string()),
682        });
683        map.insert("toPrimitive".to_string(), Rc::new(RefCell::new(Value::Symbol(tp_sym_data.clone()))));
684    });
685
686    // Internal promise resolution functions
687    env_borrow.insert(
688        PropertyKey::String("__internal_resolve_promise".to_string()),
689        Rc::new(RefCell::new(Value::Function("__internal_resolve_promise".to_string()))),
690    );
691    env_borrow.insert(
692        PropertyKey::String("__internal_reject_promise".to_string()),
693        Rc::new(RefCell::new(Value::Function("__internal_reject_promise".to_string()))),
694    );
695    env_borrow.insert(
696        PropertyKey::String("__internal_allsettled_state_record_fulfilled".to_string()),
697        Rc::new(RefCell::new(Value::Function(
698            "__internal_allsettled_state_record_fulfilled".to_string(),
699        ))),
700    );
701    env_borrow.insert(
702        PropertyKey::String("__internal_allsettled_state_record_rejected".to_string()),
703        Rc::new(RefCell::new(Value::Function(
704            "__internal_allsettled_state_record_rejected".to_string(),
705        ))),
706    );
707
708    // Initialize TypedArray constructors
709    let arraybuffer_constructor = crate::js_typedarray::make_arraybuffer_constructor()?;
710    env_borrow.insert(
711        PropertyKey::String("ArrayBuffer".to_string()),
712        Rc::new(RefCell::new(Value::Object(arraybuffer_constructor))),
713    );
714
715    // SharedArrayBuffer constructor
716    let shared_arraybuffer_constructor = crate::js_typedarray::make_sharedarraybuffer_constructor()?;
717    env_borrow.insert(
718        PropertyKey::String("SharedArrayBuffer".to_string()),
719        Rc::new(RefCell::new(Value::Object(shared_arraybuffer_constructor))),
720    );
721
722    let dataview_constructor = crate::js_typedarray::make_dataview_constructor()?;
723    env_borrow.insert(
724        PropertyKey::String("DataView".to_string()),
725        Rc::new(RefCell::new(Value::Object(dataview_constructor))),
726    );
727
728    let typedarray_constructors = crate::js_typedarray::make_typedarray_constructors()?;
729    for (name, constructor) in typedarray_constructors {
730        env_borrow.insert(PropertyKey::String(name), Rc::new(RefCell::new(Value::Object(constructor))));
731    }
732
733    // Atomics object
734    let atomics_obj = crate::js_typedarray::make_atomics_object()?;
735    env_borrow.insert(
736        PropertyKey::String("Atomics".to_string()),
737        Rc::new(RefCell::new(Value::Object(atomics_obj))),
738    );
739
740    // setTimeout function
741    env_borrow.insert(
742        PropertyKey::String("setTimeout".to_string()),
743        Rc::new(RefCell::new(Value::Function("setTimeout".to_string()))),
744    );
745
746    // clearTimeout function
747    env_borrow.insert(
748        PropertyKey::String("clearTimeout".to_string()),
749        Rc::new(RefCell::new(Value::Function("clearTimeout".to_string()))),
750    );
751
752    Ok(())
753}