///|
/// Map and Set built-in implementations
///
/// This module provides ES6 Map and Set collections with:
/// - SameValueZero equality for keys/values (NaN === NaN, +0 === -0)
/// - Insertion order preservation
/// - Iterator protocol support
/// - Standard methods (get/set/has/delete/clear for Map, add/has/delete/clear for Set)
///|
/// Global storage for Map prototype
let map_prototype_ref : Ref[Value?] = { val: None }
///|
/// Global storage for Set prototype
let set_prototype_ref : Ref[Value?] = { val: None }
///|
/// Get Map.prototype methods for a Map instance
pub fn get_map_method(_data : MapData, prop : String) -> Value {
match map_prototype_ref.val {
Some(proto) =>
match proto {
Object(proto_data) =>
match proto_data.properties.get(prop) {
Some(m) => m
None => Undefined
}
_ => Undefined
}
None => Undefined
}
}
///|
/// Get Set.prototype methods for a Set instance
pub fn get_set_method(_data : SetData, prop : String) -> Value {
match set_prototype_ref.val {
Some(proto) =>
match proto {
Object(proto_data) =>
match proto_data.properties.get(prop) {
Some(m) => m
None => Undefined
}
_ => Undefined
}
None => Undefined
}
}
///|
/// Setup Map and Set constructors and prototypes
pub fn setup_map_set_builtins(env : Environment) -> Unit {
setup_map_builtins(env)
setup_set_builtins(env)
}
///|
/// Setup Map constructor and prototype
fn setup_map_builtins(env : Environment) -> Unit {
let iterator_sym = get_iterator_symbol()
// Map.prototype methods
let map_proto_props : Map[String, Value] = {}
// Map.prototype.get(key)
map_proto_props["get"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("get", fn(this_val, args) {
match this_val {
Map(data) => {
let key = if args.length() > 0 { args[0] } else { Undefined }
// Find key using SameValueZero
for i = 0; i < data.entries.length(); i = i + 1 {
let (k, v) = data.entries[i]
if same_value_zero(k, key) {
return v
}
}
Undefined
}
_ =>
raise @errors.TypeError(
message="Method Map.prototype.get called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.set(key, value)
map_proto_props["set"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("set", fn(this_val, args) {
match this_val {
Map(data) => {
let key = if args.length() > 0 { args[0] } else { Undefined }
let value = if args.length() > 1 { args[1] } else { Undefined }
// Find existing key using SameValueZero
for i = 0; i < data.entries.length(); i = i + 1 {
let (k, _) = data.entries[i]
if same_value_zero(k, key) {
// Update existing entry
data.entries[i] = (key, value)
return this_val
}
}
// Add new entry
data.entries.push((key, value))
this_val
}
_ =>
raise @errors.TypeError(
message="Method Map.prototype.set called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.has(key)
map_proto_props["has"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("has", fn(this_val, args) {
match this_val {
Map(data) => {
let key = if args.length() > 0 { args[0] } else { Undefined }
// Find key using SameValueZero
for i = 0; i < data.entries.length(); i = i + 1 {
let (k, _) = data.entries[i]
if same_value_zero(k, key) {
return Bool(true)
}
}
Bool(false)
}
_ =>
raise @errors.TypeError(
message="Method Map.prototype.has called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.delete(key)
map_proto_props["delete"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("delete", fn(this_val, args) {
match this_val {
Map(data) => {
let key = if args.length() > 0 { args[0] } else { Undefined }
// Find and remove key using SameValueZero
for i = 0; i < data.entries.length(); i = i + 1 {
let (k, _) = data.entries[i]
if same_value_zero(k, key) {
let _ = data.entries.remove(i)
return Bool(true)
}
}
Bool(false)
}
_ =>
raise @errors.TypeError(
message="Method Map.prototype.delete called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.clear()
map_proto_props["clear"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("clear", fn(this_val, _args) {
match this_val {
Map(data) => {
data.entries.clear()
Undefined
}
_ =>
raise @errors.TypeError(
message="Method Map.prototype.clear called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.forEach(callback, thisArg?)
map_proto_props["forEach"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
InterpreterCallable("forEach", fn(interp, this_val, args) {
match this_val {
Map(data) => {
let callback = if args.length() > 0 { args[0] } else { Undefined }
let this_arg = if args.length() > 1 { args[1] } else { Undefined }
let loc = @token.Loc::default()
// Iterate over entries
for i = 0; i < data.entries.length(); i = i + 1 {
let (key, value) = data.entries[i]
// Call callback(value, key, map)
let _ = interp.call_value(
callback,
this_arg,
[value, key, this_val],
loc,
)
}
Undefined
}
_ =>
raise @errors.TypeError(
message="Method Map.prototype.forEach called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.keys() - returns iterator of keys
map_proto_props["keys"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("keys", fn(this_val, _args) {
match this_val {
Map(data) => make_map_keys_iterator(data)
_ =>
raise @errors.TypeError(
message="Method Map.prototype.keys called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.values() - returns iterator of values
map_proto_props["values"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("values", fn(this_val, _args) {
match this_val {
Map(data) => make_map_values_iterator(data)
_ =>
raise @errors.TypeError(
message="Method Map.prototype.values called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Map.prototype.entries() - returns iterator of [key, value] pairs
map_proto_props["entries"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("entries", fn(this_val, _args) {
match this_val {
Map(data) => make_map_entries_iterator(data)
_ =>
raise @errors.TypeError(
message="Method Map.prototype.entries called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Create Map prototype
let map_proto : Value = Object({
properties: map_proto_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Map",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Store Map prototype globally for get_map_method access
map_prototype_ref.val = Some(map_proto)
// Add Map.prototype[Symbol.iterator] = Map.prototype.entries
match map_proto {
Object(data) =>
data.symbol_properties[iterator_sym.id] = map_proto_props["entries"]
_ => ()
}
// Add size getter to Map.prototype
// Note: In full ES6, size is a getter. We simulate it by checking in get_property
// For now, we'll add it as a special method that returns the size
map_proto_props["size"] = Number(0.0) // Placeholder - will be handled specially
// Map constructor
let map_ctor = Object({
properties: { "prototype": map_proto },
symbol_properties: {},
prototype: Null,
callable: Some(
InterpreterCallable("Map", fn(interp, _this_val, args) {
// Create new Map instance
let new_map : Value = Map({ entries: [] })
let loc = @token.Loc::default()
// If iterable provided, populate map
if args.length() > 0 {
let iterable = args[0]
if not(
match iterable {
Undefined | Null => true
_ => false
},
) {
// Get iterator from iterable using Symbol.iterator
let iterator_sym = get_iterator_symbol()
let iterator_method = interp.get_computed_property(
iterable,
Symbol(iterator_sym),
loc,
)
let iterator = match iterator_method {
Object(data) =>
match data.callable {
Some(_) =>
interp.call_value(iterator_method, iterable, [], loc)
None =>
raise @errors.TypeError(
message="Result of the Symbol.iterator method is not an object",
)
}
_ =>
raise @errors.TypeError(
message="\{type_of(iterable)} is not iterable",
)
}
// Iterate over the iterator
while true {
let next_method = interp.get_property(iterator, "next", loc)
let result = interp.call_value(next_method, iterator, [], loc)
let done = match interp.get_property(result, "done", loc) {
Bool(b) => b
_ => false
}
if done {
break
}
let value = interp.get_property(result, "value", loc)
// Value should be [key, value] pair or array-like with '0' and '1' properties
// Try to get key and value from the entry
let key = interp.get_computed_property(value, Number(0.0), loc)
let val = interp.get_computed_property(value, Number(1.0), loc)
// Add to map using same SameValueZero upsert logic as Map.prototype.set
match new_map {
Map(data) => {
// Find existing key using SameValueZero
let mut found = false
for i = 0; i < data.entries.length(); i = i + 1 {
let (k, _) = data.entries[i]
if same_value_zero(k, key) {
// Update existing entry
data.entries[i] = (key, val)
found = true
break
}
}
if not(found) {
// Add new entry
data.entries.push((key, val))
}
}
_ => ()
}
}
}
}
new_map
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
env.def_builtin("Map", map_ctor)
// Set Map.prototype.constructor = Map
match map_proto {
Object(data) => {
data.properties["constructor"] = map_ctor
data.descriptors["constructor"] = { writable: true, enumerable: false, configurable: true }
}
_ => ()
}
}
///|
/// Setup Set constructor and prototype
fn setup_set_builtins(env : Environment) -> Unit {
let iterator_sym = get_iterator_symbol()
// Set.prototype methods
let set_proto_props : Map[String, Value] = {}
// Set.prototype.add(value)
set_proto_props["add"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("add", fn(this_val, args) {
match this_val {
Set(data) => {
let value = if args.length() > 0 { args[0] } else { Undefined }
// Check if value already exists using SameValueZero
for i = 0; i < data.values.length(); i = i + 1 {
if same_value_zero(data.values[i], value) {
return this_val
}
}
// Add new value
data.values.push(value)
this_val
}
_ =>
raise @errors.TypeError(
message="Method Set.prototype.add called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Set.prototype.has(value)
set_proto_props["has"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("has", fn(this_val, args) {
match this_val {
Set(data) => {
let value = if args.length() > 0 { args[0] } else { Undefined }
// Find value using SameValueZero
for i = 0; i < data.values.length(); i = i + 1 {
if same_value_zero(data.values[i], value) {
return Bool(true)
}
}
Bool(false)
}
_ =>
raise @errors.TypeError(
message="Method Set.prototype.has called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Set.prototype.delete(value)
set_proto_props["delete"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("delete", fn(this_val, args) {
match this_val {
Set(data) => {
let value = if args.length() > 0 { args[0] } else { Undefined }
// Find and remove value using SameValueZero
for i = 0; i < data.values.length(); i = i + 1 {
if same_value_zero(data.values[i], value) {
let _ = data.values.remove(i)
return Bool(true)
}
}
Bool(false)
}
_ =>
raise @errors.TypeError(
message="Method Set.prototype.delete called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Set.prototype.clear()
set_proto_props["clear"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("clear", fn(this_val, _args) {
match this_val {
Set(data) => {
data.values.clear()
Undefined
}
_ =>
raise @errors.TypeError(
message="Method Set.prototype.clear called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Set.prototype.forEach(callback, thisArg?)
set_proto_props["forEach"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
InterpreterCallable("forEach", fn(interp, this_val, args) {
match this_val {
Set(data) => {
let callback = if args.length() > 0 { args[0] } else { Undefined }
let this_arg = if args.length() > 1 { args[1] } else { Undefined }
let loc = @token.Loc::default()
// Iterate over values
for i = 0; i < data.values.length(); i = i + 1 {
let value = data.values[i]
// Call callback(value, value, set) - note: Set forEach passes value twice
let _ = interp.call_value(
callback,
this_arg,
[value, value, this_val],
loc,
)
}
Undefined
}
_ =>
raise @errors.TypeError(
message="Method Set.prototype.forEach called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Set.prototype.keys() - returns iterator of values (same as values())
set_proto_props["keys"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("keys", fn(this_val, _args) {
match this_val {
Set(data) => make_set_values_iterator(data)
_ =>
raise @errors.TypeError(
message="Method Set.prototype.keys called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Set.prototype.values() - returns iterator of values
set_proto_props["values"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("values", fn(this_val, _args) {
match this_val {
Set(data) => make_set_values_iterator(data)
_ =>
raise @errors.TypeError(
message="Method Set.prototype.values called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Set.prototype.entries() - returns iterator of [value, value] pairs
set_proto_props["entries"] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("entries", fn(this_val, _args) {
match this_val {
Set(data) => make_set_entries_iterator(data)
_ =>
raise @errors.TypeError(
message="Method Set.prototype.entries called on incompatible receiver",
)
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Create Set prototype
let set_proto : Value = Object({
properties: set_proto_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Set",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Store Set prototype globally for get_set_method access
set_prototype_ref.val = Some(set_proto)
// Add Set.prototype[Symbol.iterator] = Set.prototype.values
match set_proto {
Object(data) =>
data.symbol_properties[iterator_sym.id] = set_proto_props["values"]
_ => ()
}
// Add size getter placeholder
set_proto_props["size"] = Number(0.0) // Placeholder - will be handled specially
// Set constructor
let set_ctor = Object({
properties: { "prototype": set_proto },
symbol_properties: {},
prototype: Null,
callable: Some(
InterpreterCallable("Set", fn(interp, _this_val, args) {
// Create new Set instance
let new_set : Value = Set({ values: [] })
let loc = @token.Loc::default()
// If iterable provided, populate set
if args.length() > 0 {
let iterable = args[0]
if not(
match iterable {
Undefined | Null => true
_ => false
},
) {
// Get iterator from iterable using Symbol.iterator
let iterator_sym = get_iterator_symbol()
let iterator_method = interp.get_computed_property(
iterable,
Symbol(iterator_sym),
loc,
)
let iterator = match iterator_method {
Object(data) =>
match data.callable {
Some(_) =>
interp.call_value(iterator_method, iterable, [], loc)
None =>
raise @errors.TypeError(
message="Result of the Symbol.iterator method is not an object",
)
}
_ =>
raise @errors.TypeError(
message="\{type_of(iterable)} is not iterable",
)
}
// Iterate over the iterator
while true {
let next_method = interp.get_property(iterator, "next", loc)
let result = interp.call_value(next_method, iterator, [], loc)
let done = match interp.get_property(result, "done", loc) {
Bool(b) => b
_ => false
}
if done {
break
}
let value = interp.get_property(result, "value", loc)
// Add to set (using SameValueZero)
match new_set {
Set(data) => {
let mut found = false
for i = 0; i < data.values.length(); i = i + 1 {
if same_value_zero(data.values[i], value) {
found = true
break
}
}
if not(found) {
data.values.push(value)
}
}
_ => ()
}
}
}
}
new_set
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
env.def_builtin("Set", set_ctor)
// Set Set.prototype.constructor = Set
match set_proto {
Object(data) => {
data.properties["constructor"] = set_ctor
data.descriptors["constructor"] = { writable: true, enumerable: false, configurable: true }
}
_ => ()
}
}
///|
/// Create a Map keys iterator
fn make_map_keys_iterator(map_data : MapData) -> Value {
let iterator_sym = get_iterator_symbol()
let index_ref : Ref[Int] = { val: 0 }
let next_method = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
NativeCallable("next", fn(_args) {
let idx = index_ref.val
if idx < map_data.entries.length() {
let (key, _) = map_data.entries[idx]
index_ref.val = idx + 1
let result_props : Map[String, Value] = {}
result_props["value"] = key
result_props["done"] = Bool(false)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
} else {
let result_props : Map[String, Value] = {}
result_props["value"] = Undefined
result_props["done"] = Bool(true)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
let iter_props : Map[String, Value] = {}
iter_props["next"] = next_method
let iter_obj = Object({
properties: iter_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Map Iterator",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Add [Symbol.iterator] that returns the iterator itself
match iter_obj {
Object(data) =>
data.symbol_properties[iterator_sym.id] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("[Symbol.iterator]", fn(this_val, _args) { this_val }),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
_ => ()
}
iter_obj
}
///|
/// Create a Map values iterator
fn make_map_values_iterator(map_data : MapData) -> Value {
let iterator_sym = get_iterator_symbol()
let index_ref : Ref[Int] = { val: 0 }
let next_method = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
NativeCallable("next", fn(_args) {
let idx = index_ref.val
if idx < map_data.entries.length() {
let (_, value) = map_data.entries[idx]
index_ref.val = idx + 1
let result_props : Map[String, Value] = {}
result_props["value"] = value
result_props["done"] = Bool(false)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
} else {
let result_props : Map[String, Value] = {}
result_props["value"] = Undefined
result_props["done"] = Bool(true)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
let iter_props : Map[String, Value] = {}
iter_props["next"] = next_method
let iter_obj = Object({
properties: iter_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Map Iterator",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Add [Symbol.iterator] that returns the iterator itself
match iter_obj {
Object(data) =>
data.symbol_properties[iterator_sym.id] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("[Symbol.iterator]", fn(this_val, _args) { this_val }),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
_ => ()
}
iter_obj
}
///|
/// Create a Map entries iterator
fn make_map_entries_iterator(map_data : MapData) -> Value {
let iterator_sym = get_iterator_symbol()
let index_ref : Ref[Int] = { val: 0 }
let next_method = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
NativeCallable("next", fn(_args) {
let idx = index_ref.val
if idx < map_data.entries.length() {
let (key, value) = map_data.entries[idx]
index_ref.val = idx + 1
// Return [key, value] array
let entry_array = Array({ elements: [key, value] })
let result_props : Map[String, Value] = {}
result_props["value"] = entry_array
result_props["done"] = Bool(false)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
} else {
let result_props : Map[String, Value] = {}
result_props["value"] = Undefined
result_props["done"] = Bool(true)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
let iter_props : Map[String, Value] = {}
iter_props["next"] = next_method
let iter_obj = Object({
properties: iter_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Map Iterator",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Add [Symbol.iterator] that returns the iterator itself
match iter_obj {
Object(data) =>
data.symbol_properties[iterator_sym.id] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("[Symbol.iterator]", fn(this_val, _args) { this_val }),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
_ => ()
}
iter_obj
}
///|
/// Create a Set values iterator
fn make_set_values_iterator(set_data : SetData) -> Value {
let iterator_sym = get_iterator_symbol()
let index_ref : Ref[Int] = { val: 0 }
let next_method = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
NativeCallable("next", fn(_args) {
let idx = index_ref.val
if idx < set_data.values.length() {
let value = set_data.values[idx]
index_ref.val = idx + 1
let result_props : Map[String, Value] = {}
result_props["value"] = value
result_props["done"] = Bool(false)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
} else {
let result_props : Map[String, Value] = {}
result_props["value"] = Undefined
result_props["done"] = Bool(true)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
let iter_props : Map[String, Value] = {}
iter_props["next"] = next_method
let iter_obj = Object({
properties: iter_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Set Iterator",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Add [Symbol.iterator] that returns the iterator itself
match iter_obj {
Object(data) =>
data.symbol_properties[iterator_sym.id] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("[Symbol.iterator]", fn(this_val, _args) { this_val }),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
_ => ()
}
iter_obj
}
///|
/// Create a Set entries iterator (returns [value, value] pairs)
fn make_set_entries_iterator(set_data : SetData) -> Value {
let iterator_sym = get_iterator_symbol()
let index_ref : Ref[Int] = { val: 0 }
let next_method = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
NativeCallable("next", fn(_args) {
let idx = index_ref.val
if idx < set_data.values.length() {
let value = set_data.values[idx]
index_ref.val = idx + 1
// Return [value, value] array (Set entries are [value, value] pairs)
let entry_array = Array({ elements: [value, value] })
let result_props : Map[String, Value] = {}
result_props["value"] = entry_array
result_props["done"] = Bool(false)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
} else {
let result_props : Map[String, Value] = {}
result_props["value"] = Undefined
result_props["done"] = Bool(true)
Object({
properties: result_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Object",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
}
}),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
let iter_props : Map[String, Value] = {}
iter_props["next"] = next_method
let iter_obj = Object({
properties: iter_props,
symbol_properties: {},
prototype: Null,
callable: None,
class_name: "Set Iterator",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
// Add [Symbol.iterator] that returns the iterator itself
match iter_obj {
Object(data) =>
data.symbol_properties[iterator_sym.id] = Object({
properties: {},
symbol_properties: {},
prototype: Null,
callable: Some(
MethodCallable("[Symbol.iterator]", fn(this_val, _args) { this_val }),
),
class_name: "Function",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
_ => ()
}
iter_obj
}