2003/05/12 05:10:30
[org.ibex.core.git] / src / org / mozilla / javascript / NativeFunction.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
2  *\r
3  * The contents of this file are subject to the Netscape Public\r
4  * License Version 1.1 (the "License"); you may not use this file\r
5  * except in compliance with the License. You may obtain a copy of\r
6  * the License at http://www.mozilla.org/NPL/\r
7  *\r
8  * Software distributed under the License is distributed on an "AS\r
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
10  * implied. See the License for the specific language governing\r
11  * rights and limitations under the License.\r
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\r
16  * The Initial Developer of the Original Code is Netscape\r
17  * Communications Corporation.  Portions created by Netscape are\r
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s): \r
22  * Norris Boyd\r
23  * Igor Bukanov\r
24  * Roger Lawrence\r
25  * Mike McCabe\r
26  *\r
27  * Alternatively, the contents of this file may be used under the\r
28  * terms of the GNU Public License (the "GPL"), in which case the\r
29  * provisions of the GPL are applicable instead of those above.\r
30  * If you wish to allow use of your version of this file only\r
31  * under the terms of the GPL and not to allow others to use your\r
32  * version of this file under the NPL, indicate your decision by\r
33  * deleting the provisions above and replace them with the notice\r
34  * and other provisions required by the GPL.  If you do not delete\r
35  * the provisions above, a recipient may use your version of this\r
36  * file under either the NPL or the GPL.\r
37  */\r
38 \r
39 package org.mozilla.javascript;\r
40 \r
41 import java.util.Hashtable;\r
42 \r
43 /**\r
44  * This class implements the Function native object.\r
45  * See ECMA 15.3.\r
46  * @author Norris Boyd\r
47  */\r
48 public class NativeFunction extends BaseFunction {\r
49 \r
50     private boolean nextIs(int i, int token) {\r
51         if (i + 1 < source.length())\r
52             return source.charAt(i + 1) == token;\r
53         return false;\r
54     }\r
55 \r
56     // how much to indent\r
57     private final static int OFFSET = 4;\r
58 \r
59     // less how much for case labels\r
60     private final static int SETBACK = 2;\r
61 \r
62     // whether to do a debug print of the source information, when\r
63     // decompiling.\r
64     private static final boolean printSource = false;\r
65 \r
66     /**\r
67      * Decompile the source information associated with this js\r
68      * function/script back into a string.  For the most part, this\r
69      * just means translating tokens back to their string\r
70      * representations; there's a little bit of lookahead logic to\r
71      * decide the proper spacing/indentation.  Most of the work in\r
72      * mapping the original source to the prettyprinted decompiled\r
73      * version is done by the parser.\r
74      *\r
75      * Note that support for Context.decompileFunctionBody is hacked\r
76      * on through special cases; I suspect that js makes a distinction\r
77      * between function header and function body that rhino\r
78      * decompilation does not.\r
79      *\r
80      * @param cx Current context\r
81      *\r
82      * @param indent How much to indent the decompiled result\r
83      *\r
84      * @param justbody Whether the decompilation should omit the\r
85      * function header and trailing brace.\r
86      */\r
87 \r
88     public String decompile(Context cx, int indent, boolean justbody) {\r
89         StringBuffer result = new StringBuffer();\r
90         decompile(indent, true, justbody, result);\r
91         return result.toString(); \r
92         \r
93     }\r
94     \r
95     private void decompile(int indent, boolean toplevel, boolean justbody,\r
96                            StringBuffer result) \r
97     {\r
98         if (source == null) {\r
99             if (!justbody) {\r
100                 result.append("function ");\r
101                 result.append(getFunctionName());\r
102                 result.append("() {\n\t");\r
103             }\r
104             result.append("[native code]\n");\r
105             if (!justbody) {\r
106                 result.append("}\n");\r
107             }\r
108             return;\r
109         }\r
110 \r
111         // Spew tokens in source, for debugging.\r
112         // as TYPE number char\r
113         if (printSource) {\r
114             System.err.println("length:" + source.length());\r
115             for (int i = 0; i < source.length(); i++) {\r
116                 // Note that tokenToName will fail unless Context.printTrees\r
117                 // is true.\r
118                 String tokenname = TokenStream.tokenToName(source.charAt(i));\r
119                 if (tokenname == null)\r
120                     tokenname = "---";\r
121                 String pad = tokenname.length() > 7\r
122                     ? "\t"\r
123                     : "\t\t";\r
124                 System.err.println\r
125                     (tokenname\r
126                      + pad + (int)source.charAt(i)\r
127                      + "\t'" + ScriptRuntime.escapeString\r
128                      (source.substring(i, i+1))\r
129                      + "'");\r
130             }\r
131             System.err.println();\r
132         }\r
133 \r
134         int i = 0;\r
135 \r
136         if (source.length() > 0) {\r
137             /* special-case FUNCTION as the first token; if it is,\r
138              * (and it's not followed by a NAME or LP) then we're\r
139              * decompiling a function (and not the toplevel script.)\r
140 \r
141              * FUNCTION appearing elsewhere is an escape that means we'll\r
142              * need to call toString of the given function (object).\r
143 \r
144              * If not at the top level, don't add an initial indent;\r
145              * let the caller do it, so functions as expressions look\r
146              * reasonable.  */\r
147 \r
148             if (toplevel) {\r
149                 // add an initial newline to exactly match js.\r
150                 if (!justbody)\r
151                     result.append('\n');\r
152                 for (int j = 0; j < indent; j++)\r
153                     result.append(' ');\r
154             }\r
155 \r
156             if (source.charAt(0) == TokenStream.FUNCTION\r
157                 // make sure it's not a script that begins with a\r
158                 // reference to a function definition.\r
159                 && source.length() > 1\r
160                 && (source.charAt(1) == TokenStream.NAME\r
161                     || source.charAt(1) == TokenStream.LP))\r
162             {\r
163                 if (!justbody) {\r
164                     result.append("function ");\r
165 \r
166                     /* version != 1.2 Function constructor behavior - if\r
167                      * there's no function name in the source info, and\r
168                      * the names[0] entry is the empty string, then it must\r
169                      * have been created by the Function constructor;\r
170                      * print 'anonymous' as the function name if the\r
171                      * version (under which the function was compiled) is\r
172                      * less than 1.2... or if it's greater than 1.2, because\r
173                      * we need to be closer to ECMA.  (ToSource, please?)\r
174                      */\r
175                     if (nextIs(i, TokenStream.LP)\r
176                         && this.version != Context.VERSION_1_2\r
177                         && this.functionName != null \r
178                         && this.functionName.equals("anonymous"))\r
179                         result.append("anonymous");\r
180                     i++;\r
181                 } else {\r
182                     /* Skip past the entire function header to the next EOL.\r
183                      * Depends on how NAMEs are encoded.\r
184                      */\r
185                     while (i < source.length()\r
186                            && (source.charAt(i) != TokenStream.EOL\r
187                                // the length char of a NAME sequence\r
188                                // can look like an EOL.\r
189                                || (i > 0\r
190                                    && source.charAt(i-1) == TokenStream.NAME)))\r
191                     {\r
192                         i++;\r
193                     }\r
194                     // Skip past the EOL, too.\r
195                     i++;\r
196                 }\r
197             }\r
198         }\r
199 \r
200         while (i < source.length()) {\r
201             int stop;\r
202             switch(source.charAt(i)) {\r
203             case TokenStream.NAME:\r
204             case TokenStream.OBJECT:  // re-wrapped in '/'s in parser...\r
205                 /* NAMEs are encoded as NAME, (char) length, string...\r
206                  * Note that lookahead for detecting labels depends on\r
207                  * this encoding; change there if this changes.\r
208 \r
209                  * Also change function-header skipping code above,\r
210                  * used when decompling under decompileFunctionBody.\r
211                  */\r
212                 i++;\r
213                 stop = i + (int)source.charAt(i);\r
214                 result.append(source.substring(i + 1, stop + 1));\r
215                 i = stop;\r
216                 break;\r
217 \r
218             case TokenStream.NUMBER:\r
219                 i++;\r
220                 long lbits = 0;\r
221                 switch(source.charAt(i)) {\r
222                 case 'S':\r
223                     i++;\r
224                     result.append((int)source.charAt(i));\r
225                     break;\r
226 \r
227                 case 'J':\r
228                     i++;\r
229                     lbits |= (long)source.charAt(i++) << 48;\r
230                     lbits |= (long)source.charAt(i++) << 32;\r
231                     lbits |= (long)source.charAt(i++) << 16;\r
232                     lbits |= (long)source.charAt(i);\r
233 \r
234                     result.append(lbits);\r
235                     break;\r
236                 case 'D':\r
237                     i++;\r
238 \r
239                     lbits |= (long)source.charAt(i++) << 48;\r
240                     lbits |= (long)source.charAt(i++) << 32;\r
241                     lbits |= (long)source.charAt(i++) << 16;\r
242                     lbits |= (long)source.charAt(i);\r
243 \r
244                     double dval = Double.longBitsToDouble(lbits);\r
245                     result.append(ScriptRuntime.numberToString(dval, 10));\r
246                     break;\r
247                 }\r
248                 break;\r
249 \r
250             case TokenStream.STRING:\r
251                 i++;\r
252                 stop = i + (int)source.charAt(i);\r
253                 result.append('"');\r
254                 result.append(ScriptRuntime.escapeString\r
255                               (source.substring(i + 1, stop + 1)));\r
256                 result.append('"');\r
257                 i = stop;\r
258                 break;\r
259 \r
260             case TokenStream.PRIMARY:\r
261                 i++;\r
262                 switch(source.charAt(i)) {\r
263                 case TokenStream.TRUE:\r
264                     result.append("true");\r
265                     break;\r
266 \r
267                 case TokenStream.FALSE:\r
268                     result.append("false");\r
269                     break;\r
270 \r
271                 case TokenStream.NULL:\r
272                     result.append("null");\r
273                     break;\r
274 \r
275                 case TokenStream.THIS:\r
276                     result.append("this");\r
277                     break;\r
278 \r
279                 case TokenStream.TYPEOF:\r
280                     result.append("typeof");\r
281                     break;\r
282 \r
283                 case TokenStream.VOID:\r
284                     result.append("void");\r
285                     break;\r
286 \r
287                 case TokenStream.UNDEFINED:\r
288                     result.append("undefined");\r
289                     break;\r
290                 }\r
291                 break;\r
292 \r
293             case TokenStream.FUNCTION: {\r
294                 /* decompile a FUNCTION token as an escape; call\r
295                  * toString on the nth enclosed nested function,\r
296                  * where n is given by the byte that follows.\r
297                  */\r
298 \r
299                 i++;\r
300                 int functionNumber = source.charAt(i);\r
301                 if (nestedFunctions == null\r
302                     || functionNumber > nestedFunctions.length)\r
303                 {\r
304                     String message;\r
305                     if (functionName != null && functionName.length() > 0) {\r
306                         message = Context.getMessage2\r
307                             ("msg.no.function.ref.found.in", \r
308                              new Integer((int)source.charAt(i)), functionName);\r
309                     } else {\r
310                         message = Context.getMessage1\r
311                             ("msg.no.function.ref.found", \r
312                              new Integer((int)source.charAt(i)));\r
313                     }\r
314                     throw Context.reportRuntimeError(message);\r
315                 }\r
316                 nestedFunctions[functionNumber].\r
317                     decompile(indent, false, false, result);\r
318                 break;\r
319             }\r
320             case TokenStream.COMMA:\r
321                 result.append(", ");\r
322                 break;\r
323 \r
324             case TokenStream.LC:\r
325                 if (nextIs(i, TokenStream.EOL))\r
326                     indent += OFFSET;\r
327                 result.append('{');\r
328                 break;\r
329 \r
330             case TokenStream.RC:\r
331                 /* don't print the closing RC if it closes the\r
332                  * toplevel function and we're called from\r
333                  * decompileFunctionBody.\r
334                  */\r
335                 if (justbody && toplevel && i + 1 == source.length())\r
336                     break;\r
337 \r
338                 if (nextIs(i, TokenStream.EOL))\r
339                     indent -= OFFSET;\r
340                 if (nextIs(i, TokenStream.WHILE)\r
341                     || nextIs(i, TokenStream.ELSE)) {\r
342                     indent -= OFFSET;\r
343                     result.append("} ");\r
344                 }\r
345                 else\r
346                     result.append('}');\r
347                 break;\r
348 \r
349             case TokenStream.LP:\r
350                 result.append('(');\r
351                 break;\r
352 \r
353             case TokenStream.RP:\r
354                 if (nextIs(i, TokenStream.LC))\r
355                     result.append(") ");\r
356                 else\r
357                     result.append(')');\r
358                 break;\r
359 \r
360             case TokenStream.LB:\r
361                 result.append('[');\r
362                 break;\r
363 \r
364             case TokenStream.RB:\r
365                 result.append(']');\r
366                 break;\r
367 \r
368             case TokenStream.EOL:\r
369                 result.append('\n');\r
370 \r
371                 /* add indent if any tokens remain,\r
372                  * less setback if next token is\r
373                  * a label, case or default.\r
374                  */\r
375                 if (i + 1 < source.length()) {\r
376                     int less = 0;\r
377                     if (nextIs(i, TokenStream.CASE)\r
378                         || nextIs(i, TokenStream.DEFAULT))\r
379                         less = SETBACK;\r
380                     else if (nextIs(i, TokenStream.RC))\r
381                         less = OFFSET;\r
382 \r
383                     /* elaborate check against label... skip past a\r
384                      * following inlined NAME and look for a COLON.\r
385                      * Depends on how NAME is encoded.\r
386                      */\r
387                     else if (nextIs(i, TokenStream.NAME)) {\r
388                         int skip = source.charAt(i + 2);\r
389                         if (source.charAt(i + skip + 3) == TokenStream.COLON)\r
390                             less = OFFSET;\r
391                     }\r
392 \r
393                     for (; less < indent; less++)\r
394                         result.append(' ');\r
395                 }\r
396                 break;\r
397 \r
398             case TokenStream.DOT:\r
399                 result.append('.');\r
400                 break;\r
401 \r
402             case TokenStream.NEW:\r
403                 result.append("new ");\r
404                 break;\r
405 \r
406             case TokenStream.DELPROP:\r
407                 result.append("delete ");\r
408                 break;\r
409 \r
410             case TokenStream.IF:\r
411                 result.append("if ");\r
412                 break;\r
413 \r
414             case TokenStream.ELSE:\r
415                 result.append("else ");\r
416                 break;\r
417 \r
418             case TokenStream.FOR:\r
419                 result.append("for ");\r
420                 break;\r
421 \r
422             case TokenStream.IN:\r
423                 result.append(" in ");\r
424                 break;\r
425 \r
426             case TokenStream.WITH:\r
427                 result.append("with ");\r
428                 break;\r
429 \r
430             case TokenStream.WHILE:\r
431                 result.append("while ");\r
432                 break;\r
433 \r
434             case TokenStream.DO:\r
435                 result.append("do ");\r
436                 break;\r
437 \r
438             case TokenStream.TRY:\r
439                 result.append("try ");\r
440                 break;\r
441 \r
442             case TokenStream.CATCH:\r
443                 result.append("catch ");\r
444                 break;\r
445 \r
446             case TokenStream.FINALLY:\r
447                 result.append("finally ");\r
448                 break;\r
449 \r
450             case TokenStream.THROW:\r
451                 result.append("throw ");\r
452                 break;\r
453 \r
454             case TokenStream.SWITCH:\r
455                 result.append("switch ");\r
456                 break;\r
457 \r
458             case TokenStream.BREAK:\r
459                 if (nextIs(i, TokenStream.NAME))\r
460                     result.append("break ");\r
461                 else\r
462                     result.append("break");\r
463                 break;\r
464 \r
465             case TokenStream.CONTINUE:\r
466                 if (nextIs(i, TokenStream.NAME))\r
467                     result.append("continue ");\r
468                 else\r
469                     result.append("continue");\r
470                 break;\r
471 \r
472             case TokenStream.CASE:\r
473                 result.append("case ");\r
474                 break;\r
475 \r
476             case TokenStream.DEFAULT:\r
477                 result.append("default");\r
478                 break;\r
479 \r
480             case TokenStream.RETURN:\r
481                 if (nextIs(i, TokenStream.SEMI))\r
482                     result.append("return");\r
483                 else\r
484                     result.append("return ");\r
485                 break;\r
486 \r
487             case TokenStream.VAR:\r
488                 result.append("var ");\r
489                 break;\r
490 \r
491             case TokenStream.SEMI:\r
492                 if (nextIs(i, TokenStream.EOL))\r
493                     // statement termination\r
494                     result.append(';');\r
495                 else\r
496                     // separators in FOR\r
497                     result.append("; ");\r
498                 break;\r
499 \r
500             case TokenStream.ASSIGN:\r
501                 i++;\r
502                 switch(source.charAt(i)) {\r
503                 case TokenStream.NOP:\r
504                     result.append(" = ");\r
505                     break;\r
506 \r
507                 case TokenStream.ADD:\r
508                     result.append(" += ");\r
509                     break;\r
510 \r
511                 case TokenStream.SUB:\r
512                     result.append(" -= ");\r
513                     break;\r
514 \r
515                 case TokenStream.MUL:\r
516                     result.append(" *= ");\r
517                     break;\r
518 \r
519                 case TokenStream.DIV:\r
520                     result.append(" /= ");\r
521                     break;\r
522 \r
523                 case TokenStream.MOD:\r
524                     result.append(" %= ");\r
525                     break;\r
526 \r
527                 case TokenStream.BITOR:\r
528                     result.append(" |= ");\r
529                     break;\r
530 \r
531                 case TokenStream.BITXOR:\r
532                     result.append(" ^= ");\r
533                     break;\r
534 \r
535                 case TokenStream.BITAND:\r
536                     result.append(" &= ");\r
537                     break;\r
538 \r
539                 case TokenStream.LSH:\r
540                     result.append(" <<= ");\r
541                     break;\r
542 \r
543                 case TokenStream.RSH:\r
544                     result.append(" >>= ");\r
545                     break;\r
546 \r
547                 case TokenStream.URSH:\r
548                     result.append(" >>>= ");\r
549                     break;\r
550                 }\r
551                 break;\r
552 \r
553             case TokenStream.HOOK:\r
554                 result.append(" ? ");\r
555                 break;\r
556 \r
557             case TokenStream.OBJLIT:\r
558                 // pun OBJLIT to mean colon in objlit property initialization.\r
559                 // this needs to be distinct from COLON in the general case\r
560                 // to distinguish from the colon in a ternary... which needs\r
561                 // different spacing.\r
562                 result.append(':');\r
563                 break;\r
564 \r
565             case TokenStream.COLON:\r
566                 if (nextIs(i, TokenStream.EOL))\r
567                     // it's the end of a label\r
568                     result.append(':');\r
569                 else\r
570                     // it's the middle part of a ternary\r
571                     result.append(" : ");\r
572                 break;\r
573 \r
574             case TokenStream.OR:\r
575                 result.append(" || ");\r
576                 break;\r
577 \r
578             case TokenStream.AND:\r
579                 result.append(" && ");\r
580                 break;\r
581 \r
582             case TokenStream.BITOR:\r
583                 result.append(" | ");\r
584                 break;\r
585 \r
586             case TokenStream.BITXOR:\r
587                 result.append(" ^ ");\r
588                 break;\r
589 \r
590             case TokenStream.BITAND:\r
591                 result.append(" & ");\r
592                 break;\r
593 \r
594             case TokenStream.EQOP:\r
595                 i++;\r
596                 switch(source.charAt(i)) {\r
597                 case TokenStream.SHEQ:\r
598                     /*\r
599                      * Emulate the C engine; if we're under version\r
600                      * 1.2, then the == operator behaves like the ===\r
601                      * operator (and the source is generated by\r
602                      * decompiling a === opcode), so print the ===\r
603                      * operator as ==.\r
604                      */\r
605                     result.append(this.version == Context.VERSION_1_2 ? " == "\r
606                                   : " === ");\r
607                     break;\r
608 \r
609                 case TokenStream.SHNE:\r
610                     result.append(this.version == Context.VERSION_1_2 ? " != "\r
611                                   : " !== ");\r
612                     break;\r
613 \r
614                 case TokenStream.EQ:\r
615                     result.append(" == ");\r
616                     break;\r
617 \r
618                 case TokenStream.NE:\r
619                     result.append(" != ");\r
620                     break;\r
621                 }\r
622                 break;\r
623 \r
624             case TokenStream.RELOP:\r
625                 i++;\r
626                 switch(source.charAt(i)) {\r
627                 case TokenStream.LE:\r
628                     result.append(" <= ");\r
629                     break;\r
630 \r
631                 case TokenStream.LT:\r
632                     result.append(" < ");\r
633                     break;\r
634 \r
635                 case TokenStream.GE:\r
636                     result.append(" >= ");\r
637                     break;\r
638 \r
639                 case TokenStream.GT:\r
640                     result.append(" > ");\r
641                     break;\r
642 \r
643                 case TokenStream.INSTANCEOF:\r
644                     result.append(" instanceof ");\r
645                     break;\r
646                 }\r
647                 break;\r
648 \r
649             case TokenStream.SHOP:\r
650                 i++;\r
651                 switch(source.charAt(i)) {\r
652                 case TokenStream.LSH:\r
653                     result.append(" << ");\r
654                     break;\r
655 \r
656                 case TokenStream.RSH:\r
657                     result.append(" >> ");\r
658                     break;\r
659 \r
660                 case TokenStream.URSH:\r
661                     result.append(" >>> ");\r
662                     break;\r
663                 }\r
664                 break;\r
665 \r
666             case TokenStream.UNARYOP:\r
667                 i++;\r
668                 switch(source.charAt(i)) {\r
669                 case TokenStream.TYPEOF:\r
670                     result.append("typeof ");\r
671                     break;\r
672 \r
673                 case TokenStream.VOID:\r
674                     result.append("void ");\r
675                     break;\r
676 \r
677                 case TokenStream.NOT:\r
678                     result.append('!');\r
679                     break;\r
680 \r
681                 case TokenStream.BITNOT:\r
682                     result.append('~');\r
683                     break;\r
684 \r
685                 case TokenStream.ADD:\r
686                     result.append('+');\r
687                     break;\r
688 \r
689                 case TokenStream.SUB:\r
690                     result.append('-');\r
691                     break;\r
692                 }\r
693                 break;\r
694 \r
695             case TokenStream.INC:\r
696                 result.append("++");\r
697                 break;\r
698 \r
699             case TokenStream.DEC:\r
700                 result.append("--");\r
701                 break;\r
702 \r
703             case TokenStream.ADD:\r
704                 result.append(" + ");\r
705                 break;\r
706 \r
707             case TokenStream.SUB:\r
708                 result.append(" - ");\r
709                 break;\r
710 \r
711             case TokenStream.MUL:\r
712                 result.append(" * ");\r
713                 break;\r
714 \r
715             case TokenStream.DIV:\r
716                 result.append(" / ");\r
717                 break;\r
718 \r
719             case TokenStream.MOD:\r
720                 result.append(" % ");\r
721                 break;\r
722 \r
723             default: \r
724                 // If we don't know how to decompile it, raise an exception.\r
725                 throw new RuntimeException("Unknown token " + \r
726                                            source.charAt(i));\r
727             }\r
728             i++;\r
729         }\r
730 \r
731         // add that trailing newline if it's an outermost function.\r
732         if (toplevel && !justbody)\r
733             result.append('\n');\r
734     }\r
735 \r
736     public int getLength() {\r
737         Context cx = Context.getContext();\r
738         if (cx != null && cx.getLanguageVersion() != Context.VERSION_1_2)\r
739             return argCount;\r
740         NativeCall activation = getActivation(cx);\r
741         if (activation == null)\r
742             return argCount;\r
743         return activation.getOriginalArguments().length;\r
744     }\r
745 \r
746     public int getArity() {\r
747         return argCount;\r
748     }\r
749 \r
750     public String getFunctionName() {\r
751         if (functionName == null)\r
752             return "";\r
753         if (functionName.equals("anonymous")) {\r
754             Context cx = Context.getCurrentContext();\r
755             if (cx != null && cx.getLanguageVersion() == Context.VERSION_1_2)\r
756                 return "";\r
757         }\r
758         return functionName;\r
759     }\r
760 \r
761     /**\r
762      * For backwards compatibility keep an old method name used by\r
763      * Batik and possibly others.\r
764      */\r
765     public String jsGet_name() {\r
766         return getFunctionName();\r
767     }\r
768 \r
769     /**\r
770      * The "argsNames" array has the following information:\r
771      * argNames[0] through argNames[argCount - 1]: the names of the parameters\r
772      * argNames[argCount] through argNames[args.length-1]: the names of the\r
773      * variables declared in var statements\r
774      */\r
775     protected String[] argNames;\r
776     protected short argCount;\r
777     protected short version;\r
778 \r
779     /**\r
780      * An encoded representation of the function source, for\r
781      * decompiling.  Needs to be visible (only) to generated\r
782      * subclasses of NativeFunction.\r
783      */\r
784     protected String source;\r
785 \r
786     /**\r
787      * An array of NativeFunction values for each nested function.\r
788      * Used internally, and also for decompiling nested functions.\r
789      */\r
790     public NativeFunction[] nestedFunctions;\r
791 \r
792     // For all generated subclass objects debug_level is set to 0 or higher.\r
793     // So, if debug_level remains -1 in some object, then that object is\r
794     // known to have not been generated.\r
795     public int debug_level = -1;\r
796     public String debug_srcName;\r
797 }\r
798 \r