3
3
//! The `GcObject` is a garbage collected Object.
4
4
5
5
use super :: Object ;
6
+ use crate :: {
7
+ builtins:: {
8
+ function:: { create_unmapped_arguments_object, BuiltInFunction , Function } ,
9
+ Value ,
10
+ } ,
11
+ environment:: {
12
+ function_environment_record:: BindingStatus , lexical_environment:: new_function_environment,
13
+ } ,
14
+ Executable , Interpreter , Result ,
15
+ } ;
6
16
use gc:: { Finalize , Gc , GcCell , GcCellRef , GcCellRefMut , Trace } ;
17
+ use std:: result:: Result as StdResult ;
7
18
use std:: {
8
19
cell:: RefCell ,
9
20
collections:: HashSet ,
@@ -31,12 +42,12 @@ impl GcObject {
31
42
}
32
43
33
44
#[ inline]
34
- pub fn try_borrow ( & self ) -> Result < GcCellRef < ' _ , Object > , BorrowError > {
45
+ pub fn try_borrow ( & self ) -> StdResult < GcCellRef < ' _ , Object > , BorrowError > {
35
46
self . 0 . try_borrow ( ) . map_err ( |_| BorrowError )
36
47
}
37
48
38
49
#[ inline]
39
- pub fn try_borrow_mut ( & self ) -> Result < GcCellRefMut < ' _ , Object > , BorrowMutError > {
50
+ pub fn try_borrow_mut ( & self ) -> StdResult < GcCellRefMut < ' _ , Object > , BorrowMutError > {
40
51
self . 0 . try_borrow_mut ( ) . map_err ( |_| BorrowMutError )
41
52
}
42
53
@@ -45,6 +56,151 @@ impl GcObject {
45
56
pub fn equals ( lhs : & Self , rhs : & Self ) -> bool {
46
57
std:: ptr:: eq ( lhs. as_ref ( ) , rhs. as_ref ( ) )
47
58
}
59
+
60
+ /// This will handle calls for both ordinary and built-in functions
61
+ ///
62
+ /// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
63
+ /// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist>
64
+ pub fn call ( & self , this : & Value , args : & [ Value ] , ctx : & mut Interpreter ) -> Result < Value > {
65
+ let this_function_object = self . clone ( ) ;
66
+ let object = self . borrow ( ) ;
67
+ if let Some ( function) = object. as_function ( ) {
68
+ if function. is_callable ( ) {
69
+ match function {
70
+ Function :: BuiltIn ( BuiltInFunction ( function) , _) => function ( this, args, ctx) ,
71
+ Function :: Ordinary {
72
+ body,
73
+ params,
74
+ environment,
75
+ flags,
76
+ } => {
77
+ // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
78
+ // <https://tc39.es/ecma262/#sec-prepareforordinarycall>
79
+ let local_env = new_function_environment (
80
+ this_function_object,
81
+ if flags. is_lexical_this_mode ( ) {
82
+ None
83
+ } else {
84
+ Some ( this. clone ( ) )
85
+ } ,
86
+ Some ( environment. clone ( ) ) ,
87
+ // Arrow functions do not have a this binding https://tc39.es/ecma262/#sec-function-environment-records
88
+ if flags. is_lexical_this_mode ( ) {
89
+ BindingStatus :: Lexical
90
+ } else {
91
+ BindingStatus :: Uninitialized
92
+ } ,
93
+ ) ;
94
+
95
+ // Add argument bindings to the function environment
96
+ for ( i, param) in params. iter ( ) . enumerate ( ) {
97
+ // Rest Parameters
98
+ if param. is_rest_param ( ) {
99
+ function. add_rest_param ( param, i, args, ctx, & local_env) ;
100
+ break ;
101
+ }
102
+
103
+ let value = args. get ( i) . cloned ( ) . unwrap_or_else ( Value :: undefined) ;
104
+ function. add_arguments_to_environment ( param, value, & local_env) ;
105
+ }
106
+
107
+ // Add arguments object
108
+ let arguments_obj = create_unmapped_arguments_object ( args) ;
109
+ local_env
110
+ . borrow_mut ( )
111
+ . create_mutable_binding ( "arguments" . to_string ( ) , false ) ;
112
+ local_env
113
+ . borrow_mut ( )
114
+ . initialize_binding ( "arguments" , arguments_obj) ;
115
+
116
+ ctx. realm . environment . push ( local_env) ;
117
+
118
+ // Call body should be set before reaching here
119
+ let result = body. run ( ctx) ;
120
+
121
+ // local_env gets dropped here, its no longer needed
122
+ ctx. realm . environment . pop ( ) ;
123
+ result
124
+ }
125
+ }
126
+ } else {
127
+ ctx. throw_type_error ( "function object is not callable" )
128
+ }
129
+ } else {
130
+ ctx. throw_type_error ( "not a function" )
131
+ }
132
+ }
133
+
134
+ /// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget>
135
+ pub fn construct ( & self , this : & Value , args : & [ Value ] , ctx : & mut Interpreter ) -> Result < Value > {
136
+ let this_function_object = self . clone ( ) ;
137
+ let object = self . borrow ( ) ;
138
+ if let Some ( function) = object. as_function ( ) {
139
+ if function. is_constructable ( ) {
140
+ match function {
141
+ Function :: BuiltIn ( BuiltInFunction ( function) , _) => {
142
+ function ( this, args, ctx) ?;
143
+ Ok ( this. clone ( ) )
144
+ }
145
+ Function :: Ordinary {
146
+ body,
147
+ params,
148
+ environment,
149
+ flags,
150
+ } => {
151
+ // Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
152
+ // <https://tc39.es/ecma262/#sec-prepareforordinarycall>
153
+ let local_env = new_function_environment (
154
+ this_function_object,
155
+ Some ( this. clone ( ) ) ,
156
+ Some ( environment. clone ( ) ) ,
157
+ // Arrow functions do not have a this binding https://tc39.es/ecma262/#sec-function-environment-records
158
+ if flags. is_lexical_this_mode ( ) {
159
+ BindingStatus :: Lexical
160
+ } else {
161
+ BindingStatus :: Uninitialized
162
+ } ,
163
+ ) ;
164
+
165
+ // Add argument bindings to the function environment
166
+ for ( i, param) in params. iter ( ) . enumerate ( ) {
167
+ // Rest Parameters
168
+ if param. is_rest_param ( ) {
169
+ function. add_rest_param ( param, i, args, ctx, & local_env) ;
170
+ break ;
171
+ }
172
+
173
+ let value = args. get ( i) . cloned ( ) . unwrap_or_else ( Value :: undefined) ;
174
+ function. add_arguments_to_environment ( param, value, & local_env) ;
175
+ }
176
+
177
+ // Add arguments object
178
+ let arguments_obj = create_unmapped_arguments_object ( args) ;
179
+ local_env
180
+ . borrow_mut ( )
181
+ . create_mutable_binding ( "arguments" . to_string ( ) , false ) ;
182
+ local_env
183
+ . borrow_mut ( )
184
+ . initialize_binding ( "arguments" , arguments_obj) ;
185
+
186
+ ctx. realm . environment . push ( local_env) ;
187
+
188
+ // Call body should be set before reaching here
189
+ let _ = body. run ( ctx) ;
190
+
191
+ // local_env gets dropped here, its no longer needed
192
+ let binding = ctx. realm . environment . get_this_binding ( ) ;
193
+ Ok ( binding)
194
+ }
195
+ }
196
+ } else {
197
+ let name = this. get_field ( "name" ) . display ( ) . to_string ( ) ;
198
+ ctx. throw_type_error ( format ! ( "{} is not a constructor" , name) )
199
+ }
200
+ } else {
201
+ ctx. throw_type_error ( "not a function" )
202
+ }
203
+ }
48
204
}
49
205
50
206
impl AsRef < GcCell < Object > > for GcObject {
0 commit comments