jsfunction.c 4.6 KB

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