1 | #include "jsi.h" |
2 | #include "jsparse.h" |
3 | #include "jscompile.h" |
4 | #include "jsvalue.h" |
5 | #include "jsbuiltin.h" |
6 | |
7 | static void jsB_Function(js_State *J) |
8 | { |
9 | int i, top = js_gettop(J); |
10 | js_Buffer *sb = NULL; |
11 | const char *body; |
12 | js_Ast *parse; |
13 | js_Function *fun; |
14 | |
15 | if (js_try(J)) { |
16 | js_free(J, sb); |
17 | jsP_freeparse(J); |
18 | js_throw(J); |
19 | } |
20 | |
21 | /* p1, p2, ..., pn */ |
22 | if (top > 2) { |
23 | for (i = 1; i < top - 1; ++i) { |
24 | if (i > 1) |
25 | js_putc(J, &sb, ','); |
26 | js_puts(J, &sb, js_tostring(J, i)); |
27 | } |
28 | js_putc(J, &sb, ')'); |
29 | js_putc(J, &sb, 0); |
30 | } |
31 | |
32 | /* body */ |
33 | body = js_isdefined(J, top - 1) ? js_tostring(J, top - 1) : "" ; |
34 | |
35 | parse = jsP_parsefunction(J, "[string]" , sb ? sb->s : NULL, body); |
36 | fun = jsC_compilefunction(J, parse); |
37 | |
38 | js_endtry(J); |
39 | js_free(J, sb); |
40 | jsP_freeparse(J); |
41 | |
42 | js_newfunction(J, fun, J->GE); |
43 | } |
44 | |
45 | static void jsB_Function_prototype(js_State *J) |
46 | { |
47 | js_pushundefined(J); |
48 | } |
49 | |
50 | static void Fp_toString(js_State *J) |
51 | { |
52 | js_Object *self = js_toobject(J, 0); |
53 | js_Buffer *sb = NULL; |
54 | int i; |
55 | |
56 | if (!js_iscallable(J, 0)) |
57 | js_typeerror(J, "not a function" ); |
58 | |
59 | if (self->type == JS_CFUNCTION || self->type == JS_CSCRIPT) { |
60 | js_Function *F = self->u.f.function; |
61 | |
62 | if (js_try(J)) { |
63 | js_free(J, sb); |
64 | js_throw(J); |
65 | } |
66 | |
67 | js_puts(J, &sb, "function " ); |
68 | js_puts(J, &sb, F->name); |
69 | js_putc(J, &sb, '('); |
70 | for (i = 0; i < F->numparams; ++i) { |
71 | if (i > 0) js_putc(J, &sb, ','); |
72 | js_puts(J, &sb, F->vartab[i]); |
73 | } |
74 | js_puts(J, &sb, ") { [byte code] }" ); |
75 | js_putc(J, &sb, 0); |
76 | |
77 | js_pushstring(J, sb->s); |
78 | js_endtry(J); |
79 | js_free(J, sb); |
80 | } else if (self->type == JS_CCFUNCTION) { |
81 | if (js_try(J)) { |
82 | js_free(J, sb); |
83 | js_throw(J); |
84 | } |
85 | |
86 | js_puts(J, &sb, "function " ); |
87 | js_puts(J, &sb, self->u.c.name); |
88 | js_puts(J, &sb, "() { [native code] }" ); |
89 | js_putc(J, &sb, 0); |
90 | |
91 | js_pushstring(J, sb->s); |
92 | js_endtry(J); |
93 | js_free(J, sb); |
94 | } else { |
95 | js_pushliteral(J, "function () { }" ); |
96 | } |
97 | } |
98 | |
99 | static void Fp_apply(js_State *J) |
100 | { |
101 | int i, n; |
102 | |
103 | if (!js_iscallable(J, 0)) |
104 | js_typeerror(J, "not a function" ); |
105 | |
106 | js_copy(J, 0); |
107 | js_copy(J, 1); |
108 | |
109 | if (js_isnull(J, 2) || js_isundefined(J, 2)) { |
110 | n = 0; |
111 | } else { |
112 | n = js_getlength(J, 2); |
113 | for (i = 0; i < n; ++i) |
114 | js_getindex(J, 2, i); |
115 | } |
116 | |
117 | js_call(J, n); |
118 | } |
119 | |
120 | static void Fp_call(js_State *J) |
121 | { |
122 | int i, top = js_gettop(J); |
123 | |
124 | if (!js_iscallable(J, 0)) |
125 | js_typeerror(J, "not a function" ); |
126 | |
127 | for (i = 0; i < top; ++i) |
128 | js_copy(J, i); |
129 | |
130 | js_call(J, top - 2); |
131 | } |
132 | |
133 | static void callbound(js_State *J) |
134 | { |
135 | int top = js_gettop(J); |
136 | int i, fun, args, n; |
137 | |
138 | fun = js_gettop(J); |
139 | js_currentfunction(J); |
140 | js_getproperty(J, fun, "__TargetFunction__" ); |
141 | js_getproperty(J, fun, "__BoundThis__" ); |
142 | |
143 | args = js_gettop(J); |
144 | js_getproperty(J, fun, "__BoundArguments__" ); |
145 | n = js_getlength(J, args); |
146 | for (i = 0; i < n; ++i) |
147 | js_getindex(J, args, i); |
148 | js_remove(J, args); |
149 | |
150 | for (i = 1; i < top; ++i) |
151 | js_copy(J, i); |
152 | |
153 | js_call(J, n + top - 1); |
154 | } |
155 | |
156 | static void constructbound(js_State *J) |
157 | { |
158 | int top = js_gettop(J); |
159 | int i, fun, args, n; |
160 | |
161 | fun = js_gettop(J); |
162 | js_currentfunction(J); |
163 | js_getproperty(J, fun, "__TargetFunction__" ); |
164 | |
165 | args = js_gettop(J); |
166 | js_getproperty(J, fun, "__BoundArguments__" ); |
167 | n = js_getlength(J, args); |
168 | for (i = 0; i < n; ++i) |
169 | js_getindex(J, args, i); |
170 | js_remove(J, args); |
171 | |
172 | for (i = 1; i < top; ++i) |
173 | js_copy(J, i); |
174 | |
175 | js_construct(J, n + top - 1); |
176 | } |
177 | |
178 | static void Fp_bind(js_State *J) |
179 | { |
180 | int i, top = js_gettop(J); |
181 | int n; |
182 | |
183 | if (!js_iscallable(J, 0)) |
184 | js_typeerror(J, "not a function" ); |
185 | |
186 | n = js_getlength(J, 0); |
187 | if (n > top - 2) |
188 | n -= top - 2; |
189 | else |
190 | n = 0; |
191 | |
192 | /* Reuse target function's prototype for HasInstance check. */ |
193 | js_getproperty(J, 0, "prototype" ); |
194 | js_newcconstructor(J, callbound, constructbound, "[bind]" , n); |
195 | |
196 | /* target function */ |
197 | js_copy(J, 0); |
198 | js_defproperty(J, -2, "__TargetFunction__" , JS_READONLY | JS_DONTENUM | JS_DONTCONF); |
199 | |
200 | /* bound this */ |
201 | js_copy(J, 1); |
202 | js_defproperty(J, -2, "__BoundThis__" , JS_READONLY | JS_DONTENUM | JS_DONTCONF); |
203 | |
204 | /* bound arguments */ |
205 | js_newarray(J); |
206 | for (i = 2; i < top; ++i) { |
207 | js_copy(J, i); |
208 | js_setindex(J, -2, i - 2); |
209 | } |
210 | js_defproperty(J, -2, "__BoundArguments__" , JS_READONLY | JS_DONTENUM | JS_DONTCONF); |
211 | } |
212 | |
213 | void jsB_initfunction(js_State *J) |
214 | { |
215 | J->Function_prototype->u.c.name = "Function.prototype" ; |
216 | J->Function_prototype->u.c.function = jsB_Function_prototype; |
217 | J->Function_prototype->u.c.constructor = NULL; |
218 | J->Function_prototype->u.c.length = 0; |
219 | |
220 | js_pushobject(J, J->Function_prototype); |
221 | { |
222 | jsB_propf(J, "Function.prototype.toString" , Fp_toString, 2); |
223 | jsB_propf(J, "Function.prototype.apply" , Fp_apply, 2); |
224 | jsB_propf(J, "Function.prototype.call" , Fp_call, 1); |
225 | jsB_propf(J, "Function.prototype.bind" , Fp_bind, 1); |
226 | } |
227 | js_newcconstructor(J, jsB_Function, jsB_Function, "Function" , 1); |
228 | js_defglobal(J, "Function" , JS_DONTENUM); |
229 | } |
230 | |