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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use crate::{
builtins::{
object::Object,
property::Property,
value::{to_value, ResultValue, Value, ValueData},
},
exec::Interpreter,
syntax::ast::expr::Expr,
};
use gc::{custom_trace, Gc};
use gc_derive::{Finalize, Trace};
use std::fmt::{self, Debug};
pub type NativeFunctionData = fn(&Value, &[Value], &mut Interpreter) -> ResultValue;
#[derive(Trace, Finalize, Debug, Clone)]
pub enum Function {
NativeFunc(NativeFunction),
RegularFunc(RegularFunction),
}
#[derive(Trace, Finalize, Debug, Clone)]
pub struct RegularFunction {
pub object: Object,
pub expr: Expr,
pub args: Vec<Expr>,
}
impl RegularFunction {
#[allow(clippy::cast_possible_wrap)]
pub fn new(expr: Expr, args: Vec<Expr>) -> Self {
let mut object = Object::default();
object.properties.insert(
"arguments".to_string(),
Property::default().value(Gc::new(ValueData::Integer(args.len() as i32))),
);
Self { object, expr, args }
}
}
#[derive(Finalize, Clone)]
pub struct NativeFunction {
pub object: Object,
pub data: NativeFunctionData,
}
impl NativeFunction {
pub fn new(data: NativeFunctionData) -> Self {
let object = Object::default();
Self { object, data }
}
}
impl Debug for NativeFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?;
for (key, val) in self.object.properties.iter() {
write!(
f,
"{}: {}",
key,
val.value
.as_ref()
.unwrap_or(&Gc::new(ValueData::Undefined))
.clone()
)?;
}
write!(f, "}}")
}
}
unsafe impl gc::Trace for NativeFunction {
custom_trace!(this, mark(&this.object));
}
pub fn _create() -> Value {
let function: Object = Object::default();
to_value(function)
}
pub fn init(global: &Value) {
let global_ptr = global;
global_ptr.set_field_slice("Function", _create());
}
pub fn create_unmapped_arguments_object(arguments_list: Vec<Value>) -> Value {
let len = arguments_list.len();
let mut obj = Object::default();
obj.set_internal_slot("ParameterMap", Gc::new(ValueData::Undefined));
let mut length = Property::default();
length = length.writable(true).value(to_value(len));
obj.define_own_property("length".to_string(), length);
let mut index: usize = 0;
while index < len {
let val = arguments_list.get(index).expect("Could not get argument");
let mut prop = Property::default();
prop = prop
.value(val.clone())
.enumerable(true)
.writable(true)
.configurable(true);
obj.properties.insert(index.to_string(), prop);
index += 1;
}
to_value(obj)
}
#[cfg(test)]
mod tests {
use crate::exec::Executor;
use crate::realm::Realm;
use crate::{builtins::value::from_value, forward, forward_val};
#[allow(clippy::float_cmp)]
#[test]
fn check_arguments_object() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
function jason(a, b) {
return arguments[0];
}
var val = jason(100, 6);
"#;
forward(&mut engine, init);
let expected_return_val: f64 = 100.0;
let return_val = forward_val(&mut engine, "val").expect("value expected");
assert_eq!(return_val.is_double(), true);
assert_eq!(
from_value::<f64>(return_val).expect("Could not convert value to f64"),
expected_return_val
);
}
}