1#include "jsi.h"
2#include "jsparse.h"
3#include "jscompile.h"
4#include "jsvalue.h"
5#include "jsbuiltin.h"
6
7static 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
45static void jsB_Function_prototype(js_State *J)
46{
47 js_pushundefined(J);
48}
49
50static 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
99static 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
120static 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
133static 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
156static 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
178static 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
213void 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