1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::{
builtins::{
object::{Object, ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE},
value::{to_value, ResultValue, Value, ValueData},
},
exec::Interpreter,
};
use gc::{Gc, GcCell};
use rand::random;
pub fn call_symbol(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
let mut sym_instance = Object::default();
sym_instance.kind = ObjectKind::Symbol;
let desc_string = match args.get(0) {
Some(value) => to_value(value.to_string()),
None => Gc::new(ValueData::Undefined),
};
sym_instance.set_internal_slot("Description", desc_string);
sym_instance.set_internal_slot("SymbolData", to_value(random::<i32>()));
let proto = ctx
.realm
.global_obj
.get_field_slice("Symbol")
.get_field_slice(PROTOTYPE);
sym_instance.set_internal_slot(INSTANCE_PROTOTYPE, proto);
Ok(Gc::new(ValueData::Symbol(GcCell::new(sym_instance))))
}
pub fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
let s: Value = this.get_internal_slot("Description");
let full_string = format!(r#"Symbol({})"#, s.to_string());
Ok(to_value(full_string))
}
pub fn create_constructor(global: &Value) -> Value {
let mut symbol_constructor = Object::default();
symbol_constructor.set_internal_method("call", call_symbol);
let mut symbol_prototype = Object::default();
let object_prototype = global.get_field_slice("Object").get_field_slice(PROTOTYPE);
symbol_prototype.set_internal_slot(INSTANCE_PROTOTYPE, object_prototype.clone());
symbol_prototype.set_method("toString", to_string);
let symbol_prototype_val = to_value(symbol_prototype);
let symbol_constructor_value = to_value(symbol_constructor);
symbol_prototype_val.set_field_slice("construcotor", symbol_constructor_value.clone());
symbol_constructor_value.set_field_slice(PROTOTYPE, symbol_prototype_val.clone());
symbol_constructor_value
}
#[cfg(test)]
mod tests {
use super::*;
use crate::exec::Executor;
use crate::realm::Realm;
use crate::{forward, forward_val};
#[test]
fn check_symbol_constructor_is_function() {
let global: Gc<ValueData> = ValueData::new_obj(None);
let symbol_constructor = create_constructor(&global);
assert_eq!(symbol_constructor.is_function(), true);
}
#[test]
fn call_symbol_and_check_return_type() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var sym = Symbol();
"#;
forward(&mut engine, init);
let sym = forward_val(&mut engine, "sym").unwrap();
assert_eq!(sym.is_symbol(), true);
}
#[test]
fn print_symbol_expect_description() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var sym = Symbol("Hello");
"#;
forward(&mut engine, init);
let sym = forward_val(&mut engine, "sym.toString()").unwrap();
assert_eq!(sym.to_string(), "Symbol(Hello)");
}
}