2003/05/12 05:10:30
[org.ibex.core.git] / src / org / mozilla / javascript / Context.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 or\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-2000 Netscape Communications Corporation. All\r
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s):\r
22  *\r
23  * Patrick Beard\r
24  * Norris Boyd\r
25  * Igor Bukanov\r
26  * Brendan Eich\r
27  * Roger Lawrence\r
28  * Mike McCabe\r
29  * Ian D. Stewart\r
30  * Andi Vajda\r
31  * Andrew Wason\r
32  *\r
33  * Alternatively, the contents of this file may be used under the\r
34  * terms of the GNU Public License (the "GPL"), in which case the\r
35  * provisions of the GPL are applicable instead of those above.\r
36  * If you wish to allow use of your version of this file only\r
37  * under the terms of the GPL and not to allow others to use your\r
38  * version of this file under the NPL, indicate your decision by\r
39  * deleting the provisions above and replace them with the notice\r
40  * and other provisions required by the GPL.  If you do not delete\r
41  * the provisions above, a recipient may use your version of this\r
42  * file under either the NPL or the GPL.\r
43  */\r
44 \r
45 // API class\r
46 \r
47 package org.mozilla.javascript;\r
48 \r
49 import java.beans.*;\r
50 import java.io.*;\r
51 import java.util.Vector;\r
52 import java.util.Enumeration;\r
53 import java.util.Hashtable;\r
54 import java.util.Locale;\r
55 import java.util.ResourceBundle;\r
56 import java.util.ListResourceBundle;\r
57 import java.text.MessageFormat;\r
58 import java.lang.reflect.*;\r
59 import org.mozilla.javascript.debug.*;\r
60 \r
61 /**\r
62  * This class represents the runtime context of an executing script.\r
63  *\r
64  * Before executing a script, an instance of Context must be created\r
65  * and associated with the thread that will be executing the script.\r
66  * The Context will be used to store information about the executing\r
67  * of the script such as the call stack. Contexts are associated with\r
68  * the current thread  using the <a href="#enter()">enter()</a> method.<p>\r
69  *\r
70  * The behavior of the execution engine may be altered through methods\r
71  * such as <a href="#setLanguageVersion>setLanguageVersion</a> and\r
72  * <a href="#setErrorReporter>setErrorReporter</a>.<p>\r
73  *\r
74  * Different forms of script execution are supported. Scripts may be\r
75  * evaluated from the source directly, or first compiled and then later\r
76  * executed. Interactive execution is also supported.<p>\r
77  *\r
78  * Some aspects of script execution, such as type conversions and\r
79  * object creation, may be accessed directly through methods of\r
80  * Context.\r
81  *\r
82  * @see Scriptable\r
83  * @author Norris Boyd\r
84  * @author Brendan Eich\r
85  */\r
86 \r
87 public class Context {\r
88     public static final String languageVersionProperty = "language version";\r
89     public static final String errorReporterProperty   = "error reporter";\r
90     \r
91     /**\r
92      * Create a new Context.\r
93      *\r
94      * Note that the Context must be associated with a thread before\r
95      * it can be used to execute a script.\r
96      *\r
97      * @see org.mozilla.javascript.Context#enter\r
98      */\r
99     public Context() {\r
100         init();\r
101     }\r
102     \r
103     /**\r
104      * Create a new context with the associated security support.\r
105      * \r
106      * @param securitySupport an encapsulation of the functionality \r
107      *        needed to support security for scripts.\r
108      * @see org.mozilla.javascript.SecuritySupport\r
109      */\r
110     public Context(SecuritySupport securitySupport) {\r
111         this.securitySupport = securitySupport;\r
112         init();\r
113     }\r
114     \r
115     private void init() {\r
116         setLanguageVersion(VERSION_DEFAULT);\r
117         optimizationLevel = codegenClass != null ? 0 : -1;\r
118         Object[] array = contextListeners;\r
119         if (array != null) {\r
120             for (int i = array.length; i-- != 0;) {\r
121                 ((ContextListener)array[i]).contextCreated(this);\r
122             }\r
123         }\r
124     }\r
125         \r
126     /**\r
127      * Get a context associated with the current thread, creating\r
128      * one if need be.\r
129      *\r
130      * The Context stores the execution state of the JavaScript\r
131      * engine, so it is required that the context be entered\r
132      * before execution may begin. Once a thread has entered\r
133      * a Context, then getCurrentContext() may be called to find\r
134      * the context that is associated with the current thread.\r
135      * <p>\r
136      * Calling <code>enter()</code> will\r
137      * return either the Context currently associated with the\r
138      * thread, or will create a new context and associate it \r
139      * with the current thread. Each call to <code>enter()</code>\r
140      * must have a matching call to <code>exit()</code>. For example,\r
141      * <pre>\r
142      *      Context cx = Context.enter();\r
143      *      ...\r
144      *      cx.evaluateString(...);\r
145      *      Context.exit();\r
146      * </pre>\r
147      * @return a Context associated with the current thread\r
148      * @see org.mozilla.javascript.Context#getCurrentContext\r
149      * @see org.mozilla.javascript.Context#exit\r
150      */\r
151     public static Context enter() {\r
152         return enter(null);\r
153     }\r
154     \r
155     /**\r
156      * Get a Context associated with the current thread, using\r
157      * the given Context if need be.\r
158      * <p>\r
159      * The same as <code>enter()</code> except that <code>cx</code>\r
160      * is associated with the current thread and returned if \r
161      * the current thread has no associated context and <code>cx</code>\r
162      * is not associated with any other thread.\r
163      * @param cx a Context to associate with the thread if possible\r
164      * @return a Context associated with the current thread\r
165      */\r
166     public static Context enter(Context cx) {\r
167         // There's some duplication of code in this method to avoid\r
168         // unnecessary synchronizations.\r
169         Thread t = Thread.currentThread();\r
170         Context current = (Context) threadContexts.get(t);\r
171         if (current != null) {\r
172             synchronized (current) {\r
173                 current.enterCount++;\r
174             }\r
175         }\r
176         else if (cx != null) {\r
177             synchronized (cx) {\r
178                 if (cx.currentThread == null) {\r
179                     cx.currentThread = t;\r
180                     threadContexts.put(t, cx);\r
181                     cx.enterCount++;\r
182                 }\r
183             }\r
184             current = cx;\r
185         }\r
186         else {\r
187         current = new Context();\r
188         current.currentThread = t;\r
189         threadContexts.put(t, current);\r
190         current.enterCount = 1;\r
191         }\r
192         Object[] array = contextListeners;\r
193         if (array != null) {\r
194             for (int i = array.length; i-- != 0;) {\r
195                 ((ContextListener)array[i]).contextEntered(current);\r
196             }\r
197         }\r
198         return current;\r
199      }\r
200         \r
201     /**\r
202      * Exit a block of code requiring a Context.\r
203      *\r
204      * Calling <code>exit()</code> will remove the association between\r
205      * the current thread and a Context if the prior call to \r
206      * <code>enter()</code> on this thread newly associated a Context \r
207      * with this thread.\r
208      * Once the current thread no longer has an associated Context,\r
209      * it cannot be used to execute JavaScript until it is again associated\r
210      * with a Context.\r
211      *\r
212      * @see org.mozilla.javascript.Context#enter\r
213      */\r
214     public static void exit() {\r
215         Context cx = getCurrentContext();\r
216         boolean released = false;\r
217         if (cx != null) {\r
218             synchronized (cx) {\r
219                 if (--cx.enterCount == 0) {\r
220                     threadContexts.remove(cx.currentThread);\r
221                     cx.currentThread = null;\r
222                     released = true;\r
223                 }\r
224             }\r
225             Object[] array = contextListeners;\r
226             if (array != null) {\r
227                 for (int i = array.length; i-- != 0;) {\r
228                     ContextListener l = (ContextListener)array[i];\r
229                     l.contextExited(cx);\r
230                     if (released) { l.contextReleased(cx); }\r
231                 }\r
232             }\r
233         }\r
234     }\r
235 \r
236     /**\r
237      * Get the current Context.\r
238      *\r
239      * The current Context is per-thread; this method looks up\r
240      * the Context associated with the current thread. <p>\r
241      *\r
242      * @return the Context associated with the current thread, or\r
243      *         null if no context is associated with the current \r
244      *         thread.\r
245      * @see org.mozilla.javascript.Context#enter\r
246      * @see org.mozilla.javascript.Context#exit\r
247      */\r
248     public static Context getCurrentContext() {\r
249         Thread t = Thread.currentThread();\r
250         return (Context) threadContexts.get(t);\r
251     }\r
252     \r
253     public static Context getContextForThread(Thread t) {\r
254         Context ret = (Context) threadContexts.get(t);\r
255         return ret == null ? Context.enter() : ret;\r
256     }\r
257     \r
258     /**\r
259      * Language versions\r
260      *\r
261      * All integral values are reserved for future version numbers.\r
262      */\r
263 \r
264     /**\r
265      * The unknown version.\r
266      */\r
267     public static final int VERSION_UNKNOWN =   -1;\r
268 \r
269     /**\r
270      * The default version.\r
271      */\r
272     public static final int VERSION_DEFAULT =    0;\r
273 \r
274     /**\r
275      * JavaScript 1.0\r
276      */\r
277     public static final int VERSION_1_0 =      100;\r
278 \r
279     /**\r
280      * JavaScript 1.1\r
281      */\r
282     public static final int VERSION_1_1 =      110;\r
283 \r
284     /**\r
285      * JavaScript 1.2\r
286      */\r
287     public static final int VERSION_1_2 =      120;\r
288 \r
289     /**\r
290      * JavaScript 1.3\r
291      */\r
292     public static final int VERSION_1_3 =      130;\r
293 \r
294     /**\r
295      * JavaScript 1.4\r
296      */\r
297     public static final int VERSION_1_4 =      140;\r
298 \r
299     /**\r
300      * JavaScript 1.5\r
301      */\r
302     public static final int VERSION_1_5 =      150;\r
303 \r
304     /**\r
305      * Get the current language version.\r
306      * <p>\r
307      * The language version number affects JavaScript semantics as detailed\r
308      * in the overview documentation.\r
309      *\r
310      * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.\r
311      */\r
312     public int getLanguageVersion() {\r
313        return version;\r
314     }\r
315 \r
316     /**\r
317      * Set the language version.\r
318      *\r
319      * <p>\r
320      * Setting the language version will affect functions and scripts compiled\r
321      * subsequently. See the overview documentation for version-specific\r
322      * behavior.\r
323      *\r
324      * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.\r
325      */\r
326     public void setLanguageVersion(int version) {\r
327         Object[] array = listeners;\r
328         if (array != null && version != this.version) {\r
329             firePropertyChangeImpl(array, languageVersionProperty,\r
330                                new Integer(this.version), \r
331                                new Integer(version));\r
332         }\r
333         this.version = version;\r
334     }\r
335 \r
336     /**\r
337      * Get the implementation version.\r
338      *\r
339      * <p>\r
340      * The implementation version is of the form \r
341      * <pre>\r
342      *    "<i>name langVer</i> <code>release</code> <i>relNum date</i>"\r
343      * </pre>\r
344      * where <i>name</i> is the name of the product, <i>langVer</i> is \r
345      * the language version, <i>relNum</i> is the release number, and \r
346      * <i>date</i> is the release date for that specific \r
347      * release in the form "yyyy mm dd". \r
348      *\r
349      * @return a string that encodes the product, language version, release \r
350      *         number, and date.\r
351      */\r
352      public String getImplementationVersion() {\r
353         return "Rhino 1.5 release 2 2001 07 27";\r
354      }\r
355 \r
356     /**\r
357      * Get the current error reporter.\r
358      *\r
359      * @see org.mozilla.javascript.ErrorReporter\r
360      */\r
361     public ErrorReporter getErrorReporter() {\r
362         if (errorReporter == null) {\r
363             errorReporter = new DefaultErrorReporter();\r
364         }\r
365         return errorReporter;\r
366     }\r
367 \r
368     /**\r
369      * Change the current error reporter.\r
370      *\r
371      * @return the previous error reporter\r
372      * @see org.mozilla.javascript.ErrorReporter\r
373      */\r
374     public ErrorReporter setErrorReporter(ErrorReporter reporter) {\r
375         ErrorReporter result = errorReporter;\r
376         Object[] array = listeners;\r
377         if (array != null && errorReporter != reporter) {\r
378             firePropertyChangeImpl(array, errorReporterProperty,\r
379                                    errorReporter, reporter);\r
380         }\r
381         errorReporter = reporter;\r
382         return result;\r
383     }\r
384 \r
385     /**\r
386      * Get the current locale.  Returns the default locale if none has\r
387      * been set.\r
388      *\r
389      * @see java.util.Locale\r
390      */\r
391 \r
392     public Locale getLocale() {\r
393         if (locale == null)\r
394             locale = Locale.getDefault();\r
395         return locale;\r
396     }\r
397 \r
398     /**\r
399      * Set the current locale.\r
400      *\r
401      * @see java.util.Locale\r
402      */\r
403     public Locale setLocale(Locale loc) {\r
404         Locale result = locale;\r
405         locale = loc;\r
406         return result;\r
407     }\r
408     \r
409     /**\r
410      * Register an object to receive notifications when a bound property\r
411      * has changed\r
412      * @see java.beans.PropertyChangeEvent\r
413      * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)\r
414      * @param  listener  the listener\r
415      */\r
416     public void addPropertyChangeListener(PropertyChangeListener listener) {\r
417         synchronized (this) {\r
418             listeners = ListenerArray.add(listeners, listener);\r
419         }    \r
420     }\r
421     \r
422     /**\r
423      * Remove an object from the list of objects registered to receive \r
424      * notification of changes to a bounded property\r
425      * @see java.beans.PropertyChangeEvent\r
426      * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)\r
427      * @param listener  the listener\r
428      */\r
429     public void removePropertyChangeListener(PropertyChangeListener listener) {\r
430         synchronized (this) {\r
431             listeners = ListenerArray.remove(listeners, listener);\r
432         }\r
433     }\r
434     \r
435     /**\r
436      * Notify any registered listeners that a bounded property has changed\r
437      * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)\r
438      * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)\r
439      * @see java.beans.PropertyChangeListener\r
440      * @see java.beans.PropertyChangeEvent\r
441      * @param  property  the bound property\r
442      * @param  oldValue  the old value\r
443      * @param  newVale   the new value\r
444      */\r
445     void firePropertyChange(String property, Object oldValue,\r
446                             Object newValue)\r
447     {\r
448         Object[] array = listeners;\r
449         if (array != null) {\r
450             firePropertyChangeImpl(array, property, oldValue, newValue);\r
451         }\r
452     }\r
453 \r
454     private void firePropertyChangeImpl(Object[] array, String property,\r
455                                         Object oldValue, Object newValue)\r
456     {\r
457         for (int i = array.length; i-- != 0;) {\r
458             Object obj = array[i];\r
459             if (obj instanceof PropertyChangeListener) {\r
460                 PropertyChangeListener l = (PropertyChangeListener)obj;\r
461                 l.propertyChange(new PropertyChangeEvent(\r
462                     this, property, oldValue, newValue));\r
463             }\r
464     }\r
465     }\r
466                                     \r
467     /**\r
468      * Report a warning using the error reporter for the current thread.\r
469      *\r
470      * @param message the warning message to report\r
471      * @param sourceName a string describing the source, such as a filename\r
472      * @param lineno the starting line number\r
473      * @param lineSource the text of the line (may be null)\r
474      * @param lineOffset the offset into lineSource where problem was detected\r
475      * @see org.mozilla.javascript.ErrorReporter\r
476      */\r
477     public static void reportWarning(String message, String sourceName,\r
478                                      int lineno, String lineSource,\r
479                                      int lineOffset)\r
480     {\r
481         Context cx = Context.getContext();\r
482         cx.getErrorReporter().warning(message, sourceName, lineno,\r
483                                       lineSource, lineOffset);\r
484     }\r
485 \r
486     /**\r
487      * Report a warning using the error reporter for the current thread.\r
488      *\r
489      * @param message the warning message to report\r
490      * @see org.mozilla.javascript.ErrorReporter\r
491      */\r
492     public static void reportWarning(String message) {\r
493         int[] linep = { 0 };\r
494         String filename = getSourcePositionFromStack(linep);\r
495         Context.reportWarning(message, filename, linep[0], null, 0);\r
496     }\r
497 \r
498     /**\r
499      * Report an error using the error reporter for the current thread.\r
500      *\r
501      * @param message the error message to report\r
502      * @param sourceName a string describing the source, such as a filename\r
503      * @param lineno the starting line number\r
504      * @param lineSource the text of the line (may be null)\r
505      * @param lineOffset the offset into lineSource where problem was detected\r
506      * @see org.mozilla.javascript.ErrorReporter\r
507      */\r
508     public static void reportError(String message, String sourceName,\r
509                                    int lineno, String lineSource,\r
510                                    int lineOffset)\r
511     {\r
512         Context cx = getCurrentContext();\r
513         if (cx != null) {\r
514             cx.errorCount++;\r
515             cx.getErrorReporter().error(message, sourceName, lineno,\r
516                                         lineSource, lineOffset);\r
517         } else {\r
518             throw new EvaluatorException(message);\r
519         }\r
520     }\r
521 \r
522     /**\r
523      * Report an error using the error reporter for the current thread.\r
524      *\r
525      * @param message the error message to report\r
526      * @see org.mozilla.javascript.ErrorReporter\r
527      */\r
528     public static void reportError(String message) {\r
529         int[] linep = { 0 };\r
530         String filename = getSourcePositionFromStack(linep);\r
531         Context.reportError(message, filename, linep[0], null, 0);\r
532     }\r
533 \r
534     /**\r
535      * Report a runtime error using the error reporter for the current thread.\r
536      *\r
537      * @param message the error message to report\r
538      * @param sourceName a string describing the source, such as a filename\r
539      * @param lineno the starting line number\r
540      * @param lineSource the text of the line (may be null)\r
541      * @param lineOffset the offset into lineSource where problem was detected\r
542      * @return a runtime exception that will be thrown to terminate the\r
543      *         execution of the script\r
544      * @see org.mozilla.javascript.ErrorReporter\r
545      */\r
546     public static EvaluatorException reportRuntimeError(String message,\r
547                                                       String sourceName,\r
548                                                       int lineno,\r
549                                                       String lineSource,\r
550                                                       int lineOffset)\r
551     {\r
552         Context cx = getCurrentContext();\r
553         if (cx != null) {\r
554             cx.errorCount++;\r
555             return cx.getErrorReporter().\r
556                             runtimeError(message, sourceName, lineno,\r
557                                          lineSource, lineOffset);\r
558         } else {\r
559             throw new EvaluatorException(message);\r
560         }\r
561     }\r
562 \r
563     static EvaluatorException reportRuntimeError0(String messageId) {\r
564         return reportRuntimeError(getMessage0(messageId));\r
565     }\r
566 \r
567     static EvaluatorException reportRuntimeError1\r
568         (String messageId, Object arg1) \r
569     {\r
570         return reportRuntimeError(getMessage1(messageId, arg1));\r
571     }\r
572 \r
573     static EvaluatorException reportRuntimeError2\r
574         (String messageId, Object arg1, Object arg2) \r
575     {\r
576         return reportRuntimeError(getMessage2(messageId, arg1, arg2));\r
577     }\r
578 \r
579     static EvaluatorException reportRuntimeError3\r
580         (String messageId, Object arg1, Object arg2, Object arg3) \r
581     {\r
582         return reportRuntimeError(getMessage3(messageId, arg1, arg2, arg3));\r
583     }\r
584 \r
585     /**\r
586      * Report a runtime error using the error reporter for the current thread.\r
587      *\r
588      * @param message the error message to report\r
589      * @see org.mozilla.javascript.ErrorReporter\r
590      */\r
591     public static EvaluatorException reportRuntimeError(String message) {\r
592         int[] linep = { 0 };\r
593         String filename = getSourcePositionFromStack(linep);\r
594         return Context.reportRuntimeError(message, filename, linep[0], null, 0);\r
595     }\r
596 \r
597     /**\r
598      * Initialize the standard objects.\r
599      *\r
600      * Creates instances of the standard objects and their constructors\r
601      * (Object, String, Number, Date, etc.), setting up 'scope' to act\r
602      * as a global object as in ECMA 15.1.<p>\r
603      *\r
604      * This method must be called to initialize a scope before scripts\r
605      * can be evaluated in that scope.\r
606      *\r
607      * @param scope the scope to initialize, or null, in which case a new\r
608      *        object will be created to serve as the scope\r
609      * @return the initialized scope\r
610      */\r
611     public Scriptable initStandardObjects(ScriptableObject scope) {\r
612         return initStandardObjects(scope, false);\r
613     }\r
614     \r
615     /**\r
616      * Initialize the standard objects.\r
617      *\r
618      * Creates instances of the standard objects and their constructors\r
619      * (Object, String, Number, Date, etc.), setting up 'scope' to act\r
620      * as a global object as in ECMA 15.1.<p>\r
621      *\r
622      * This method must be called to initialize a scope before scripts\r
623      * can be evaluated in that scope.<p>\r
624      * \r
625      * This form of the method also allows for creating "sealed" standard\r
626      * objects. An object that is sealed cannot have properties added or\r
627      * removed. This is useful to create a "superglobal" that can be shared \r
628      * among several top-level objects. Note that sealing is not allowed in\r
629      * the current ECMA/ISO language specification, but is likely for\r
630      * the next version.\r
631      *\r
632      * @param scope the scope to initialize, or null, in which case a new\r
633      *        object will be created to serve as the scope\r
634      * @param sealed whether or not to create sealed standard objects that\r
635      *        cannot be modified. \r
636      * @return the initialized scope\r
637      * @since 1.4R3\r
638      */\r
639     public ScriptableObject initStandardObjects(ScriptableObject scope,\r
640                                                 boolean sealed)\r
641     {\r
642         if (scope == null)\r
643             scope = new NativeObject();\r
644 \r
645         BaseFunction.init(this, scope, sealed);\r
646         NativeObject.init(this, scope, sealed);\r
647 \r
648         Scriptable objectProto = ScriptableObject.getObjectPrototype(scope);\r
649 \r
650         // Function.prototype.__proto__ should be Object.prototype\r
651         Scriptable functionProto = ScriptableObject.getFunctionPrototype(scope);\r
652         functionProto.setPrototype(objectProto);\r
653 \r
654         // Set the prototype of the object passed in if need be\r
655         if (scope.getPrototype() == null)\r
656             scope.setPrototype(objectProto);\r
657 \r
658         // must precede NativeGlobal since it's needed therein\r
659         NativeError.init(this, scope, sealed);\r
660         NativeGlobal.init(this, scope, sealed);\r
661 \r
662         NativeArray.init(this, scope, sealed);\r
663         NativeString.init(this, scope, sealed);\r
664         NativeBoolean.init(this, scope, sealed);\r
665         NativeNumber.init(this, scope, sealed);\r
666         NativeDate.init(this, scope, sealed);\r
667         NativeMath.init(this, scope, sealed);\r
668 \r
669         NativeWith.init(this, scope, sealed);\r
670         NativeCall.init(this, scope, sealed);\r
671         NativeScript.init(this, scope, sealed);\r
672 \r
673         new LazilyLoadedCtor(scope, \r
674                              "RegExp",\r
675                              "org.mozilla.javascript.regexp.NativeRegExp",\r
676                              sealed);\r
677 \r
678         // This creates the Packages and java package roots.\r
679         new LazilyLoadedCtor(scope, \r
680                              "Packages",\r
681                              "org.mozilla.javascript.NativeJavaPackage",\r
682                              sealed);\r
683         new LazilyLoadedCtor(scope, \r
684                              "java", \r
685                              "org.mozilla.javascript.NativeJavaPackage",\r
686                              sealed);\r
687         new LazilyLoadedCtor(scope, \r
688                              "getClass",\r
689                              "org.mozilla.javascript.NativeJavaPackage",\r
690                              sealed);\r
691  \r
692         // Define the JavaAdapter class, allowing it to be overridden.\r
693         String adapterClass = "org.mozilla.javascript.JavaAdapter";\r
694         String adapterProperty = "JavaAdapter";\r
695         try {\r
696             adapterClass = System.getProperty(adapterClass, adapterClass);\r
697             adapterProperty = System.getProperty\r
698                 ("org.mozilla.javascript.JavaAdapterClassName",\r
699                  adapterProperty);\r
700         }\r
701         catch (SecurityException e) {\r
702             // We may not be allowed to get system properties. Just\r
703             // use the default adapter in that case.\r
704         }\r
705 \r
706         new LazilyLoadedCtor(scope, adapterProperty, adapterClass, sealed);\r
707 \r
708         return scope;\r
709     }\r
710     \r
711     /**\r
712      * Get the singleton object that represents the JavaScript Undefined value.\r
713      */\r
714     public static Object getUndefinedValue() {\r
715         return Undefined.instance;\r
716     }\r
717     \r
718     /**\r
719      * Evaluate a JavaScript source string.\r
720      *\r
721      * The provided source name and line number are used for error messages\r
722      * and for producing debug information.\r
723      *\r
724      * @param scope the scope to execute in\r
725      * @param source the JavaScript source\r
726      * @param sourceName a string describing the source, such as a filename\r
727      * @param lineno the starting line number\r
728      * @param securityDomain an arbitrary object that specifies security \r
729      *        information about the origin or owner of the script. For \r
730      *        implementations that don't care about security, this value \r
731      *        may be null.\r
732      * @return the result of evaluating the string\r
733      * @exception JavaScriptException if an uncaught JavaScript exception\r
734      *            occurred while evaluating the source string\r
735      * @see org.mozilla.javascript.SecuritySupport\r
736      */\r
737     public Object evaluateString(Scriptable scope, String source,\r
738                                  String sourceName, int lineno,\r
739                                  Object securityDomain)\r
740         throws JavaScriptException\r
741     {\r
742         try {\r
743             Reader in = new StringReader(source);\r
744             return evaluateReader(scope, in, sourceName, lineno, \r
745                                   securityDomain);\r
746         }\r
747         catch (IOException ioe) {\r
748             // Should never occur because we just made the reader from a String\r
749             throw new RuntimeException();\r
750         }\r
751     }\r
752 \r
753     /**\r
754      * Evaluate a reader as JavaScript source.\r
755      *\r
756      * All characters of the reader are consumed.\r
757      *\r
758      * @param scope the scope to execute in\r
759      * @param in the Reader to get JavaScript source from\r
760      * @param sourceName a string describing the source, such as a filename\r
761      * @param lineno the starting line number\r
762      * @param securityDomain an arbitrary object that specifies security \r
763      *        information about the origin or owner of the script. For \r
764      *        implementations that don't care about security, this value \r
765      *        may be null.\r
766      * @return the result of evaluating the source\r
767      *\r
768      * @exception IOException if an IOException was generated by the Reader\r
769      * @exception JavaScriptException if an uncaught JavaScript exception\r
770      *            occurred while evaluating the Reader\r
771      */\r
772     public Object evaluateReader(Scriptable scope, Reader in,\r
773                                  String sourceName, int lineno,\r
774                                  Object securityDomain)\r
775         throws IOException, JavaScriptException\r
776     {\r
777         Script script = compileReader(scope, in, sourceName, lineno, \r
778                                       securityDomain);\r
779         if (script != null)\r
780             return script.exec(this, scope);\r
781         else\r
782             return null;\r
783     }\r
784 \r
785     /**\r
786      * Check whether a string is ready to be compiled.\r
787      * <p>\r
788      * stringIsCompilableUnit is intended to support interactive compilation of\r
789      * javascript.  If compiling the string would result in an error\r
790      * that might be fixed by appending more source, this method\r
791      * returns false.  In every other case, it returns true.\r
792      * <p>\r
793      * Interactive shells may accumulate source lines, using this\r
794      * method after each new line is appended to check whether the\r
795      * statement being entered is complete.\r
796      *\r
797      * @param source the source buffer to check\r
798      * @return whether the source is ready for compilation\r
799      * @since 1.4 Release 2\r
800      */\r
801     synchronized public boolean stringIsCompilableUnit(String source)\r
802     {\r
803         Reader in = new StringReader(source);\r
804         // no source name or source text manager, because we're just\r
805         // going to throw away the result.\r
806         TokenStream ts = new TokenStream(in, null, null, 1);\r
807 \r
808         // Temporarily set error reporter to always be the exception-throwing\r
809         // DefaultErrorReporter.  (This is why the method is synchronized...)\r
810         ErrorReporter currentReporter = \r
811             setErrorReporter(new DefaultErrorReporter());\r
812 \r
813         boolean errorseen = false;\r
814         try {\r
815             IRFactory irf = new IRFactory(ts, null);\r
816             Parser p = new Parser(irf);\r
817             p.parse(ts);\r
818         } catch (IOException ioe) {\r
819             errorseen = true;\r
820         } catch (EvaluatorException ee) {\r
821             errorseen = true;\r
822         } finally {\r
823             // Restore the old error reporter.\r
824             setErrorReporter(currentReporter);\r
825         }\r
826         // Return false only if an error occurred as a result of reading past\r
827         // the end of the file, i.e. if the source could be fixed by\r
828         // appending more source.\r
829         if (errorseen && ts.eof())\r
830             return false;\r
831         else \r
832             return true;\r
833     }\r
834 \r
835     /**\r
836      * Compiles the source in the given reader.\r
837      * <p>\r
838      * Returns a script that may later be executed.\r
839      * Will consume all the source in the reader.\r
840      *\r
841      * @param scope if nonnull, will be the scope in which the script object\r
842      *        is created. The script object will be a valid JavaScript object\r
843      *        as if it were created using the JavaScript1.3 Script constructor\r
844      * @param in the input reader\r
845      * @param sourceName a string describing the source, such as a filename\r
846      * @param lineno the starting line number for reporting errors\r
847      * @param securityDomain an arbitrary object that specifies security \r
848      *        information about the origin or owner of the script. For \r
849      *        implementations that don't care about security, this value \r
850      *        may be null.\r
851      * @return a script that may later be executed\r
852      * @see org.mozilla.javascript.Script#exec\r
853      * @exception IOException if an IOException was generated by the Reader\r
854      */\r
855     public Script compileReader(Scriptable scope, Reader in, String sourceName,\r
856                                 int lineno, Object securityDomain)\r
857         throws IOException\r
858     {\r
859         return (Script) compile(scope, in, sourceName, lineno, securityDomain, \r
860                                 false);\r
861     }\r
862 \r
863 \r
864     /**\r
865      * Compile a JavaScript function.\r
866      * <p>\r
867      * The function source must be a function definition as defined by\r
868      * ECMA (e.g., "function f(a) { return a; }"). \r
869      *\r
870      * @param scope the scope to compile relative to\r
871      * @param source the function definition source\r
872      * @param sourceName a string describing the source, such as a filename\r
873      * @param lineno the starting line number\r
874      * @param securityDomain an arbitrary object that specifies security \r
875      *        information about the origin or owner of the script. For \r
876      *        implementations that don't care about security, this value \r
877      *        may be null.\r
878      * @return a Function that may later be called\r
879      * @see org.mozilla.javascript.Function\r
880      */\r
881     public Function compileFunction(Scriptable scope, String source,\r
882                                     String sourceName, int lineno,\r
883                                     Object securityDomain)\r
884     {\r
885         Reader in = new StringReader(source);\r
886         try {\r
887             return (Function) compile(scope, in, sourceName, lineno, \r
888                                       securityDomain, true);\r
889         }\r
890         catch (IOException ioe) {\r
891             // Should never happen because we just made the reader\r
892             // from a String\r
893             throw new RuntimeException();\r
894         }\r
895     }\r
896 \r
897     /**\r
898      * Decompile the script.\r
899      * <p>\r
900      * The canonical source of the script is returned.\r
901      *\r
902      * @param script the script to decompile\r
903      * @param scope the scope under which to decompile\r
904      * @param indent the number of spaces to indent the result\r
905      * @return a string representing the script source\r
906      */\r
907      public String decompileScript(Script script, Scriptable scope,\r
908                                    int indent)\r
909     {\r
910         NativeScript ns = (NativeScript) script;\r
911         ns.initScript(scope);\r
912         return ns.decompile(this, indent, false);\r
913     }\r
914 \r
915     /**\r
916      * Decompile a JavaScript Function.\r
917      * <p>\r
918      * Decompiles a previously compiled JavaScript function object to\r
919      * canonical source.\r
920      * <p>\r
921      * Returns function body of '[native code]' if no decompilation\r
922      * information is available.\r
923      *\r
924      * @param fun the JavaScript function to decompile\r
925      * @param indent the number of spaces to indent the result\r
926      * @return a string representing the function source\r
927      */\r
928     public String decompileFunction(Function fun, int indent) {\r
929         if (fun instanceof BaseFunction)\r
930             return ((BaseFunction)fun).decompile(this, indent, false);\r
931         else\r
932             return "function " + fun.getClassName() +\r
933                    "() {\n\t[native code]\n}\n";\r
934     }\r
935 \r
936     /**\r
937      * Decompile the body of a JavaScript Function.\r
938      * <p>\r
939      * Decompiles the body a previously compiled JavaScript Function\r
940      * object to canonical source, omitting the function header and\r
941      * trailing brace.\r
942      *\r
943      * Returns '[native code]' if no decompilation information is available.\r
944      *\r
945      * @param fun the JavaScript function to decompile\r
946      * @param indent the number of spaces to indent the result\r
947      * @return a string representing the function body source.\r
948      */\r
949     public String decompileFunctionBody(Function fun, int indent) {\r
950         if (fun instanceof BaseFunction)\r
951             return ((BaseFunction)fun).decompile(this, indent, true);\r
952         else\r
953             // not sure what the right response here is.  JSRef currently\r
954             // dumps core.\r
955             return "[native code]\n";\r
956     }\r
957 \r
958     /**\r
959      * Create a new JavaScript object.\r
960      *\r
961      * Equivalent to evaluating "new Object()".\r
962      * @param scope the scope to search for the constructor and to evaluate\r
963      *              against\r
964      * @return the new object\r
965      * @exception PropertyException if "Object" cannot be found in\r
966      *            the scope\r
967      * @exception NotAFunctionException if the "Object" found in the scope\r
968      *            is not a function\r
969      * @exception JavaScriptException if an uncaught JavaScript exception\r
970      *            occurred while creating the object\r
971      */\r
972     public Scriptable newObject(Scriptable scope)\r
973         throws PropertyException,\r
974                NotAFunctionException,\r
975                JavaScriptException\r
976     {\r
977         return newObject(scope, "Object", null);\r
978     }\r
979 \r
980     /**\r
981      * Create a new JavaScript object by executing the named constructor.\r
982      *\r
983      * The call <code>newObject(scope, "Foo")</code> is equivalent to\r
984      * evaluating "new Foo()".\r
985      *\r
986      * @param scope the scope to search for the constructor and to evaluate against\r
987      * @param constructorName the name of the constructor to call\r
988      * @return the new object\r
989      * @exception PropertyException if a property with the constructor\r
990      *            name cannot be found in the scope\r
991      * @exception NotAFunctionException if the property found in the scope\r
992      *            is not a function\r
993      * @exception JavaScriptException if an uncaught JavaScript exception\r
994      *            occurred while creating the object\r
995      */\r
996     public Scriptable newObject(Scriptable scope, String constructorName)\r
997         throws PropertyException,\r
998                NotAFunctionException,\r
999                JavaScriptException\r
1000     {\r
1001         return newObject(scope, constructorName, null);\r
1002     }\r
1003 \r
1004     /**\r
1005      * Creates a new JavaScript object by executing the named constructor.\r
1006      *\r
1007      * Searches <code>scope</code> for the named constructor, calls it with\r
1008      * the given arguments, and returns the result.<p>\r
1009      *\r
1010      * The code\r
1011      * <pre>\r
1012      * Object[] args = { "a", "b" };\r
1013      * newObject(scope, "Foo", args)</pre>\r
1014      * is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo\r
1015      * constructor has been defined in <code>scope</code>.\r
1016      *\r
1017      * @param scope The scope to search for the constructor and to evaluate\r
1018      *              against\r
1019      * @param constructorName the name of the constructor to call\r
1020      * @param args the array of arguments for the constructor\r
1021      * @return the new object\r
1022      * @exception PropertyException if a property with the constructor\r
1023      *            name cannot be found in the scope\r
1024      * @exception NotAFunctionException if the property found in the scope\r
1025      *            is not a function\r
1026      * @exception JavaScriptException if an uncaught JavaScript exception\r
1027      *            occurs while creating the object\r
1028      */\r
1029     public Scriptable newObject(Scriptable scope, String constructorName,\r
1030                                 Object[] args)\r
1031         throws PropertyException,\r
1032                NotAFunctionException,\r
1033                JavaScriptException\r
1034     {\r
1035         Object ctorVal = ScriptRuntime.getTopLevelProp(scope, constructorName);\r
1036         if (ctorVal == Scriptable.NOT_FOUND) {\r
1037             String message = getMessage1("msg.ctor.not.found", constructorName);\r
1038             throw new PropertyException(message);\r
1039         }\r
1040         if (!(ctorVal instanceof Function)) {\r
1041             String message = getMessage1("msg.not.ctor", constructorName);\r
1042             throw new NotAFunctionException(message);\r
1043         }\r
1044         Function ctor = (Function) ctorVal;\r
1045         return ctor.construct(this, ctor.getParentScope(),\r
1046                               (args == null) ? ScriptRuntime.emptyArgs : args);\r
1047     }\r
1048 \r
1049     /**\r
1050      * Create an array with a specified initial length.\r
1051      * <p>\r
1052      * @param scope the scope to create the object in\r
1053      * @param length the initial length (JavaScript arrays may have\r
1054      *               additional properties added dynamically).\r
1055      * @return the new array object\r
1056      */\r
1057     public Scriptable newArray(Scriptable scope, int length) {\r
1058         Scriptable result = new NativeArray(length);\r
1059         newArrayHelper(scope, result);\r
1060         return result;\r
1061     }\r
1062 \r
1063     /**\r
1064      * Create an array with a set of initial elements.\r
1065      * <p>\r
1066      * @param scope the scope to create the object in\r
1067      * @param elements the initial elements. Each object in this array\r
1068      *                 must be an acceptable JavaScript type.\r
1069      * @return the new array object\r
1070      */\r
1071     public Scriptable newArray(Scriptable scope, Object[] elements) {\r
1072         Scriptable result = new NativeArray(elements);\r
1073         newArrayHelper(scope, result);\r
1074         return result;\r
1075     }\r
1076     \r
1077     /**\r
1078      * Get the elements of a JavaScript array.\r
1079      * <p>\r
1080      * If the object defines a length property, a Java array with that\r
1081      * length is created and initialized with the values obtained by\r
1082      * calling get() on object for each value of i in [0,length-1]. If\r
1083      * there is not a defined value for a property the Undefined value\r
1084      * is used to initialize the corresponding element in the array. The\r
1085      * Java array is then returned.\r
1086      * If the object doesn't define a length property, null is returned.\r
1087      * @param object the JavaScript array or array-like object\r
1088      * @return a Java array of objects\r
1089      * @since 1.4 release 2\r
1090      */\r
1091     public Object[] getElements(Scriptable object) {\r
1092         double doubleLen = NativeArray.getLengthProperty(object);\r
1093         if (doubleLen != doubleLen)\r
1094             return null;\r
1095         int len = (int) doubleLen;\r
1096         Object[] result = new Object[len];\r
1097         for (int i=0; i < len; i++) {\r
1098             Object elem = object.get(i, object);\r
1099             result[i] = elem == Scriptable.NOT_FOUND ? Undefined.instance \r
1100                                                      : elem;\r
1101         }\r
1102         return result;\r
1103     }\r
1104 \r
1105     /**\r
1106      * Convert the value to a JavaScript boolean value.\r
1107      * <p>\r
1108      * See ECMA 9.2.\r
1109      *\r
1110      * @param value a JavaScript value\r
1111      * @return the corresponding boolean value converted using\r
1112      *         the ECMA rules\r
1113      */\r
1114     public static boolean toBoolean(Object value) {\r
1115         return ScriptRuntime.toBoolean(value);\r
1116     }\r
1117 \r
1118     /**\r
1119      * Convert the value to a JavaScript Number value.\r
1120      * <p>\r
1121      * Returns a Java double for the JavaScript Number.\r
1122      * <p>\r
1123      * See ECMA 9.3.\r
1124      *\r
1125      * @param value a JavaScript value\r
1126      * @return the corresponding double value converted using\r
1127      *         the ECMA rules\r
1128      */\r
1129     public static double toNumber(Object value) {\r
1130         return ScriptRuntime.toNumber(value);\r
1131     }\r
1132 \r
1133     /**\r
1134      * Convert the value to a JavaScript String value.\r
1135      * <p>\r
1136      * See ECMA 9.8.\r
1137      * <p>\r
1138      * @param value a JavaScript value\r
1139      * @return the corresponding String value converted using\r
1140      *         the ECMA rules\r
1141      */\r
1142     public static String toString(Object value) {\r
1143         return ScriptRuntime.toString(value);\r
1144     }\r
1145 \r
1146     /**\r
1147      * Convert the value to an JavaScript object value.\r
1148      * <p>\r
1149      * Note that a scope must be provided to look up the constructors\r
1150      * for Number, Boolean, and String.\r
1151      * <p>\r
1152      * See ECMA 9.9.\r
1153      * <p>\r
1154      * Additionally, arbitrary Java objects and classes will be\r
1155      * wrapped in a Scriptable object with its Java fields and methods\r
1156      * reflected as JavaScript properties of the object.\r
1157      *\r
1158      * @param value any Java object\r
1159      * @param scope global scope containing constructors for Number,\r
1160      *              Boolean, and String\r
1161      * @return new JavaScript object\r
1162      */\r
1163     public static Scriptable toObject(Object value, Scriptable scope) {\r
1164         return ScriptRuntime.toObject(scope, value, null);\r
1165     }\r
1166     \r
1167     /**\r
1168      * Convert the value to an JavaScript object value.\r
1169      * <p>\r
1170      * Note that a scope must be provided to look up the constructors\r
1171      * for Number, Boolean, and String.\r
1172      * <p>\r
1173      * See ECMA 9.9.\r
1174      * <p>\r
1175      * Additionally, arbitrary Java objects and classes will be\r
1176      * wrapped in a Scriptable object with its Java fields and methods\r
1177      * reflected as JavaScript properties of the object. If the \r
1178      * "staticType" parameter is provided, it will be used as the static\r
1179      * type of the Java value to create.\r
1180      *\r
1181      * @param value any Java object\r
1182      * @param scope global scope containing constructors for Number,\r
1183      *              Boolean, and String\r
1184      * @param staticType the static type of the Java value to create\r
1185      * @return new JavaScript object\r
1186      */\r
1187     public static Scriptable toObject(Object value, Scriptable scope, \r
1188                                       Class staticType) {\r
1189         if (value == null && staticType != null)\r
1190             return null;\r
1191         return ScriptRuntime.toObject(scope, value, staticType);\r
1192     }\r
1193 \r
1194     /**\r
1195      * Tell whether debug information is being generated.\r
1196      * @since 1.3\r
1197      */\r
1198     public boolean isGeneratingDebug() {\r
1199         return generatingDebug;\r
1200     }\r
1201 \r
1202     /**\r
1203      * Specify whether or not debug information should be generated.\r
1204      * <p>\r
1205      * Setting the generation of debug information on will set the\r
1206      * optimization level to zero.\r
1207      * @since 1.3\r
1208      */\r
1209     public void setGeneratingDebug(boolean generatingDebug) {\r
1210         generatingDebugChanged = true;\r
1211         if (generatingDebug)\r
1212             setOptimizationLevel(0);\r
1213         this.generatingDebug = generatingDebug;\r
1214     }\r
1215 \r
1216     /**\r
1217      * Tell whether source information is being generated.\r
1218      * @since 1.3\r
1219      */\r
1220     public boolean isGeneratingSource() {\r
1221         return generatingSource;\r
1222     }\r
1223 \r
1224     /**\r
1225      * Specify whether or not source information should be generated.\r
1226      * <p>\r
1227      * Without source information, evaluating the "toString" method\r
1228      * on JavaScript functions produces only "[native code]" for\r
1229      * the body of the function.\r
1230      * Note that code generated without source is not fully ECMA\r
1231      * conformant.\r
1232      * @since 1.3\r
1233      */\r
1234     public void setGeneratingSource(boolean generatingSource) {\r
1235         this.generatingSource = generatingSource;\r
1236     }\r
1237 \r
1238     /**\r
1239      * Get the current optimization level.\r
1240      * <p>\r
1241      * The optimization level is expressed as an integer between -1 and\r
1242      * 9.\r
1243      * @since 1.3\r
1244      *\r
1245      */\r
1246     public int getOptimizationLevel() {\r
1247         return optimizationLevel;\r
1248     }\r
1249 \r
1250     /**\r
1251      * Set the current optimization level.\r
1252      * <p>\r
1253      * The optimization level is expected to be an integer between -1 and\r
1254      * 9. Any negative values will be interpreted as -1, and any values\r
1255      * greater than 9 will be interpreted as 9.\r
1256      * An optimization level of -1 indicates that interpretive mode will\r
1257      * always be used. Levels 0 through 9 indicate that class files may \r
1258      * be generated. Higher optimization levels trade off compile time\r
1259      * performance for runtime performance.\r
1260      * The optimizer level can't be set greater than -1 if the optimizer\r
1261      * package doesn't exist at run time.\r
1262      * @param optimizationLevel an integer indicating the level of\r
1263      *        optimization to perform\r
1264      * @since 1.3\r
1265      *\r
1266      */\r
1267     public void setOptimizationLevel(int optimizationLevel) {\r
1268         if (optimizationLevel < 0) {\r
1269             optimizationLevel = -1;\r
1270         } else if (optimizationLevel > 9) {\r
1271                 optimizationLevel = 9;\r
1272         }\r
1273         if (codegenClass == null)\r
1274             optimizationLevel = -1;\r
1275         this.optimizationLevel = optimizationLevel;\r
1276     }\r
1277 \r
1278     /**\r
1279      * Get the current target class file name.\r
1280      * <p>\r
1281      * If nonnull, requests to compile source will result in one or\r
1282      * more class files being generated.\r
1283      * @since 1.3\r
1284      */\r
1285     public String getTargetClassFileName() {\r
1286         return nameHelper == null\r
1287                ? null \r
1288                : nameHelper.getTargetClassFileName();\r
1289     }\r
1290 \r
1291     /**\r
1292      * Set the current target class file name.\r
1293      * <p>\r
1294      * If nonnull, requests to compile source will result in one or\r
1295      * more class files being generated. If null, classes will only\r
1296      * be generated in memory.\r
1297      *\r
1298      * @since 1.3\r
1299      */\r
1300     public void setTargetClassFileName(String classFileName) {\r
1301         if (nameHelper != null)\r
1302             nameHelper.setTargetClassFileName(classFileName);\r
1303     }\r
1304 \r
1305     /**\r
1306      * Get the current package to generate classes into.\r
1307      *\r
1308      * @since 1.3\r
1309      */\r
1310     public String getTargetPackage() {\r
1311         return (nameHelper == null) ? null : nameHelper.getTargetPackage();\r
1312     }\r
1313 \r
1314     /**\r
1315      * Set the package to generate classes into.\r
1316      *\r
1317      * @since 1.3\r
1318      */\r
1319     public void setTargetPackage(String targetPackage) {\r
1320         if (nameHelper != null)\r
1321             nameHelper.setTargetPackage(targetPackage);\r
1322     }\r
1323 \r
1324     /**\r
1325      * Get the current interface to write class bytes into.\r
1326      *\r
1327      * @see ClassOutput\r
1328      * @since 1.5 Release 2\r
1329      */\r
1330     public ClassOutput getClassOutput() {\r
1331         return nameHelper == null ? null : nameHelper.getClassOutput();\r
1332     }\r
1333 \r
1334     /**\r
1335      * Set the interface to write class bytes into.\r
1336      * Unless setTargetClassFileName() has been called classOutput will be\r
1337      * used each time the javascript compiler has generated the bytecode for a\r
1338      * script class.\r
1339      *\r
1340      * @see ClassOutput\r
1341      * @since 1.5 Release 2\r
1342      */\r
1343     public void setClassOutput(ClassOutput classOutput) {\r
1344         if (nameHelper != null)\r
1345             nameHelper.setClassOutput(classOutput);\r
1346     }\r
1347     \r
1348     /**\r
1349      * Add a Context listener.\r
1350      */\r
1351     public static void addContextListener(ContextListener listener) {\r
1352         synchronized (staticDataLock) {\r
1353             contextListeners = ListenerArray.add(contextListeners, listener);\r
1354         }\r
1355     }\r
1356     \r
1357     /**\r
1358      * Remove a Context listener.\r
1359      * @param listener the listener to remove.\r
1360      */\r
1361     public static void removeContextListener(ContextListener listener) {\r
1362         synchronized (staticDataLock) {\r
1363             contextListeners = ListenerArray.remove(contextListeners, listener);\r
1364         }\r
1365     }\r
1366 \r
1367     /**\r
1368      * Set the security support for this context. \r
1369      * <p> SecuritySupport may only be set if it is currently null.\r
1370      * Otherwise a SecurityException is thrown.\r
1371      * @param supportObj a SecuritySupport object\r
1372      * @throws SecurityException if there is already a SecuritySupport\r
1373      *         object for this Context\r
1374      */\r
1375     public synchronized void setSecuritySupport(SecuritySupport supportObj) {\r
1376         if (securitySupport != null) {\r
1377             throw new SecurityException("Cannot overwrite existing " +\r
1378                                         "SecuritySupport object");\r
1379         }\r
1380         securitySupport = supportObj;\r
1381     }\r
1382         \r
1383     /**\r
1384      * Return true if a security domain is required on calls to\r
1385      * compile and evaluate scripts.\r
1386      *\r
1387      * @since 1.4 Release 2\r
1388      */\r
1389     public static boolean isSecurityDomainRequired() { \r
1390         return requireSecurityDomain;\r
1391     }\r
1392     \r
1393     /**\r
1394      * Returns the security context associated with the innermost\r
1395      * script or function being executed by the interpreter.\r
1396      * @since 1.4 release 2\r
1397      */\r
1398     public Object getInterpreterSecurityDomain() {\r
1399         return interpreterSecurityDomain;\r
1400     }\r
1401     \r
1402     /**\r
1403      * Returns true if the class parameter is a class in the \r
1404      * interpreter. Typically used by embeddings that get a class\r
1405      * context to check security. These embeddings must know \r
1406      * whether to get the security context associated with the\r
1407      * interpreter or not.\r
1408      * \r
1409      * @param cl a class to test whether or not it is an interpreter\r
1410      *           class\r
1411      * @return true if cl is an interpreter class\r
1412      * @since 1.4 release 2\r
1413      */\r
1414     public boolean isInterpreterClass(Class cl) {\r
1415         return cl == Interpreter.class;\r
1416     }\r
1417     \r
1418     /**\r
1419      * Set the class that the generated target will extend.\r
1420      * \r
1421      * @param extendsClass the class it extends\r
1422      */\r
1423     public void setTargetExtends(Class extendsClass) {\r
1424         if (nameHelper != null) {\r
1425             nameHelper.setTargetExtends(extendsClass);\r
1426         }\r
1427     }\r
1428        \r
1429     /**\r
1430      * Set the interfaces that the generated target will implement.\r
1431      * \r
1432      * @param implementsClasses an array of Class objects, one for each\r
1433      *                          interface the target will extend\r
1434      */\r
1435     public void setTargetImplements(Class[] implementsClasses) {\r
1436         if (nameHelper != null) {\r
1437             nameHelper.setTargetImplements(implementsClasses);\r
1438         }\r
1439     }\r
1440         \r
1441     /**\r
1442      * Get a value corresponding to a key.\r
1443      * <p>\r
1444      * Since the Context is associated with a thread it can be \r
1445      * used to maintain values that can be later retrieved using \r
1446      * the current thread. \r
1447      * <p>\r
1448      * Note that the values are maintained with the Context, so\r
1449      * if the Context is disassociated from the thread the values\r
1450      * cannot be retreived. Also, if private data is to be maintained\r
1451      * in this manner the key should be a java.lang.Object \r
1452      * whose reference is not divulged to untrusted code.\r
1453      * @param key the key used to lookup the value\r
1454      * @return a value previously stored using putThreadLocal.\r
1455      */\r
1456     public Object getThreadLocal(Object key) {\r
1457         if (hashtable == null)\r
1458             return null;\r
1459         return hashtable.get(key);\r
1460     }\r
1461 \r
1462     /**\r
1463      * Put a value that can later be retrieved using a given key.\r
1464      * <p>\r
1465      * @param key the key used to index the value\r
1466      * @param value the value to save\r
1467      */\r
1468     public void putThreadLocal(Object key, Object value) {\r
1469         if (hashtable == null)\r
1470             hashtable = new Hashtable();\r
1471         hashtable.put(key, value);\r
1472     }\r
1473     \r
1474     /**\r
1475      * Remove values from thread-local storage.\r
1476      * @param key the key for the entry to remove.\r
1477      * @since 1.5 release 2\r
1478      */\r
1479     public void removeThreadLocal(Object key) {\r
1480         if (hashtable == null)\r
1481             return;\r
1482         hashtable.remove(key);\r
1483     }    \r
1484     \r
1485     /**\r
1486      * Return whether functions are compiled by this context using\r
1487      * dynamic scope.\r
1488      * <p>\r
1489      * If functions are compiled with dynamic scope, then they execute\r
1490      * in the scope of their caller, rather than in their parent scope.\r
1491      * This is useful for sharing functions across multiple scopes.\r
1492      * @since 1.5 Release 1\r
1493      */\r
1494     public boolean hasCompileFunctionsWithDynamicScope() {\r
1495         return compileFunctionsWithDynamicScopeFlag;\r
1496     }\r
1497     \r
1498     /**\r
1499      * Set whether functions compiled by this context should use\r
1500      * dynamic scope.\r
1501      * <p>\r
1502      * @param flag if true, compile functions with dynamic scope\r
1503      * @since 1.5 Release 1\r
1504      */\r
1505     public void setCompileFunctionsWithDynamicScope(boolean flag) {\r
1506         compileFunctionsWithDynamicScopeFlag = flag;\r
1507     }\r
1508     \r
1509     /**\r
1510      * Set whether to cache some values statically.\r
1511      * <p>\r
1512      * By default, the engine will cache some values statically \r
1513      * (reflected Java classes, for instance). This can speed\r
1514      * execution dramatically, but increases the memory footprint.\r
1515      * Also, with caching enabled, references may be held to \r
1516      * objects past the lifetime of any real usage. \r
1517      * <p>\r
1518      * If caching is enabled and this method is called with a \r
1519      * <code>false</code> argument, the caches will be emptied.\r
1520      * So one strategy could be to clear the caches at times\r
1521      * appropriate to the application.\r
1522      * <p>\r
1523      * Caching is enabled by default.\r
1524      * \r
1525      * @param cachingEnabled if true, caching is enabled\r
1526      * @since 1.5 Release 1 \r
1527      */\r
1528     public static void setCachingEnabled(boolean cachingEnabled) {\r
1529         if (isCachingEnabled && !cachingEnabled) {\r
1530             // Caching is being turned off. Empty caches.\r
1531             JavaMembers.classTable = new Hashtable();\r
1532             nameHelper.reset();\r
1533         }\r
1534         isCachingEnabled = cachingEnabled;\r
1535         FunctionObject.setCachingEnabled(cachingEnabled);\r
1536     }\r
1537     \r
1538     /**\r
1539      * Set a WrapHandler for this Context.\r
1540      * <p>\r
1541      * The WrapHandler allows custom object wrapping behavior for \r
1542      * Java object manipulated with JavaScript.\r
1543      * @see org.mozilla.javascript.WrapHandler\r
1544      * @since 1.5 Release 2 \r
1545      */\r
1546     public void setWrapHandler(WrapHandler wrapHandler) {\r
1547         this.wrapHandler = wrapHandler;\r
1548     }\r
1549     \r
1550     /**\r
1551      * Return the current WrapHandler, or null if none is defined.\r
1552      * @see org.mozilla.javascript.WrapHandler\r
1553      * @since 1.5 Release 2 \r
1554      */\r
1555     public WrapHandler getWrapHandler() {\r
1556         return wrapHandler;\r
1557     }\r
1558     \r
1559     public DebuggableEngine getDebuggableEngine() {\r
1560         if (debuggableEngine == null)\r
1561             debuggableEngine = new DebuggableEngineImpl(this);\r
1562         return debuggableEngine;\r
1563     }\r
1564     \r
1565     \r
1566     /**\r
1567      * if hasFeature(FEATURE_NON_ECMA_GET_YEAR) returns true,\r
1568      * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000\r
1569      * in deviation with Ecma B.2.4\r
1570      */\r
1571     public static final int FEATURE_NON_ECMA_GET_YEAR = 1;\r
1572     \r
1573     /**\r
1574      * Controls certain aspects of script semantics. \r
1575      * Should be overwritten to alter default behavior.\r
1576      * @param featureIndex feature index to check\r
1577      * @return true if the <code>featureIndex</code> feature is turned on\r
1578      * @see #FEATURE_NON_ECMA_GET_YEAR\r
1579      */\r
1580     public boolean hasFeature(int featureIndex) {\r
1581         if (featureIndex == FEATURE_NON_ECMA_GET_YEAR) {\r
1582            /*\r
1583             * During the great date rewrite of 1.3, we tried to track the\r
1584             * evolving ECMA standard, which then had a definition of\r
1585             * getYear which always subtracted 1900.  Which we\r
1586             * implemented, not realizing that it was incompatible with\r
1587             * the old behavior...  now, rather than thrash the behavior\r
1588             * yet again, we've decided to leave it with the - 1900\r
1589             * behavior and point people to the getFullYear method.  But\r
1590             * we try to protect existing scripts that have specified a\r
1591             * version...\r
1592             */\r
1593             return (version == Context.VERSION_1_0 \r
1594                     || version == Context.VERSION_1_1\r
1595                     || version == Context.VERSION_1_2);\r
1596         }\r
1597         throw new RuntimeException("Bad feature index: " + featureIndex);\r
1598     }\r
1599 \r
1600     /**\r
1601      * Get/Set threshold of executed instructions counter that triggers call to\r
1602      * <code>observeInstructionCount()</code>.\r
1603      * When the threshold is zero, instruction counting is disabled, \r
1604      * otherwise each time the run-time executes at least the threshold value\r
1605      * of script instructions, <code>observeInstructionCount()</code> will \r
1606      * be called.\r
1607      */\r
1608     public int getInstructionObserverThreshold() {\r
1609         return instructionThreshold;\r
1610     }\r
1611     \r
1612     public void setInstructionObserverThreshold(int threshold) {\r
1613         instructionThreshold = threshold;\r
1614     }\r
1615     \r
1616     /** \r
1617      * Allow application to monitor counter of executed script instructions\r
1618      * in Context subclasses.\r
1619      * Run-time calls this when instruction counting is enabled and the counter\r
1620      * reaches limit set by <code>setInstructionObserverThreshold()</code>.\r
1621      * The method is useful to observe long running scripts and if necessary\r
1622      * to terminate them.\r
1623      * @param instructionCount amount of script instruction executed since \r
1624      * last call to <code>observeInstructionCount</code> \r
1625      * @throws Error to terminate the script\r
1626      */\r
1627     protected void observeInstructionCount(int instructionCount) {}\r
1628     \r
1629     /********** end of API **********/\r
1630     \r
1631     void pushFrame(DebugFrame frame) {\r
1632         if (frameStack == null)\r
1633             frameStack = new java.util.Stack();\r
1634         frameStack.push(frame);\r
1635     }\r
1636     \r
1637     void popFrame() {\r
1638         frameStack.pop();\r
1639     }\r
1640     \r
1641 \r
1642 \r
1643     static String getMessage0(String messageId) {\r
1644         return getMessage(messageId, null);\r
1645     }\r
1646 \r
1647     static String getMessage1(String messageId, Object arg1) {\r
1648         Object[] arguments = {arg1};\r
1649         return getMessage(messageId, arguments);\r
1650     }\r
1651 \r
1652     static String getMessage2(String messageId, Object arg1, Object arg2) {\r
1653         Object[] arguments = {arg1, arg2};\r
1654         return getMessage(messageId, arguments);\r
1655     }\r
1656 \r
1657     static String getMessage3\r
1658         (String messageId, Object arg1, Object arg2, Object arg3) {\r
1659         Object[] arguments = {arg1, arg2, arg3};\r
1660         return getMessage(messageId, arguments);\r
1661     }\r
1662     /**\r
1663      * Internal method that reports an error for missing calls to\r
1664      * enter().\r
1665      */\r
1666     static Context getContext() {\r
1667         Thread t = Thread.currentThread();\r
1668         Context cx = (Context) threadContexts.get(t);\r
1669         if (cx == null) {\r
1670             throw new RuntimeException(\r
1671                 "No Context associated with current Thread");\r
1672         }\r
1673         return cx;\r
1674     }\r
1675 \r
1676     /** GCJ doesn't have an easy way to bundle up .properties files, so we do this */\r
1677     static class HardCodedResourceBundle extends ListResourceBundle {\r
1678         public Object[][] getContents() { return contents; }\r
1679         static final Object[][] contents = {\r
1680             { "msg.dup.parms", "Duplicate parameter name \"{0}\"." },\r
1681             { "msg.ctor.not.found", "Constructor for \"{0}\" not found." },\r
1682             { "msg.not.ctor", "\"{0}\" is not a constructor." },\r
1683             { "msg.varargs.ctor", "Method or constructor \"{0}\" must be static with the signature  \"(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)\"  to define a variable arguments constructor." },\r
1684             { "msg.varargs.fun", "Method \"{0}\" must be static with the signature  \"(Context cx, Scriptable thisObj, Object[] args, Function funObj)\"  to define a variable arguments function." },\r
1685             { "msg.incompat.call", "Method \"{0}\" called on incompatible object." },\r
1686             { "msg.bad.parms", "Bad method parameters for \"{0}\"." },\r
1687             { "msg.no.overload", "Method \"{0}\" occurs multiple times in class \"{1}\"." },\r
1688             { "msg.method.not.found", "Method \"{0}\" not found in \"{1}\"." },\r
1689             { "msg.bad.for.in.lhs", "Invalid left-hand side of for..in loop." },\r
1690             { "msg.bad.lhs.assign", "Invalid assignment left-hand side." },\r
1691             { "msg.mult.index", "Only one variable allowed in for..in loop." },\r
1692             { "msg.cant.convert", "Can''t convert to type \"{0}\"." },\r
1693             { "msg.cant.call.indirect", "Function \"{0}\" must be called directly, and not by way of a  function of another name." },\r
1694             { "msg.eval.nonstring", "Calling eval() with anything other than a primitive string value will  simply return the value. Is this what you intended?" },\r
1695             { "msg.only.from.new", "\"{0}\" may only be invoked from a \"new\" expression." },\r
1696             { "msg.deprec.ctor", "The \"{0}\" constructor is deprecated." },\r
1697             { "msg.no.function.ref.found.in", "no source found in {1} to decompile function reference {0}" },\r
1698             { "msg.no.function.ref.found", "no source found to decompile function reference {0}" },\r
1699             { "msg.arg.isnt.array", "second argument to Function.prototype.apply must be an array" },\r
1700             { "msg.bad.esc.mask", "invalid string escape mask" },\r
1701             { "msg.cant.instantiate", "error instantiating ({0}): class {1} is interface or abstract" },\r
1702             { "msg.bad.ctor.sig", "Found constructor with wrong signature:  {0} calling {1} with signature {2}" },\r
1703             { "msg.not.java.obj", "Expected argument to getClass() to be a Java object." },\r
1704             { "msg.no.java.ctor", "Java constructor for \"{0}\" with arguments \"{1}\" not found." },\r
1705             { "msg.method.ambiguous", "The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous;  candidate methods are: {3}" },\r
1706             { "msg.constructor.ambiguous", "The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous;  candidate constructors are: {2}" },\r
1707             { "msg.conversion.not.allowed", "Cannot convert {0} to {1}" },\r
1708             { "msg.bad.quant", "Invalid quantifier {0}" },\r
1709             { "msg.overlarge.max", "Overly large maximum {0}" },\r
1710             { "msg.zero.quant", "Zero quantifier {0}" },\r
1711             { "msg.max.lt.min", "Maximum {0} less than minimum" },\r
1712             { "msg.unterm.quant", "Unterminated quantifier {0}" },\r
1713             { "msg.unterm.paren", "Unterminated parenthetical {0}" },\r
1714             { "msg.unterm.class", "Unterminated character class {0}" },\r
1715             { "msg.bad.range", "Invalid range in character class." },\r
1716             { "msg.trail.backslash", "Trailing \\ in regular expression." },\r
1717             { "msg.no.regexp", "Regular expressions are not available." },\r
1718             { "msg.bad.backref", "back-reference exceeds number of capturing parentheses." },\r
1719             { "msg.dup.label", "Duplicate label {0}." },\r
1720             { "msg.undef.label", "Undefined label {0}." },\r
1721             { "msg.bad.break", "Unlabelled break must be inside loop or switch." },\r
1722             { "msg.continue.outside", "continue must be inside loop." },\r
1723             { "msg.continue.nonloop", "Can only continue to labeled iteration statement." },\r
1724             { "msg.fn.redecl", "Function \"{0}\" redeclared; prior definition will be ignored." },\r
1725             { "msg.no.paren.parms", "missing ( before function parameters" },\r
1726             { "msg.no.parm", "missing formal parameter" },\r
1727             { "msg.no.paren.after.parms", "missing ) after formal parameters" },\r
1728             { "msg.no.brace.body", "missing open brace before function body" },\r
1729             { "msg.no.brace.after.body", "missing close brace after function body" },\r
1730             { "msg.no.paren.cond", "missing ( before condition" },\r
1731             { "msg.no.paren.after.cond", "missing ) after condition" },\r
1732             { "msg.no.semi.stmt", "missing ; before statement" },\r
1733             { "msg.no.name.after.dot", "missing name after . operator" },\r
1734             { "msg.no.bracket.index", "missing ] in index expression" },\r
1735             { "msg.no.paren.switch", "missing ( before switch expression" },\r
1736             { "msg.no.paren.after.switch", "missing ) after switch expression" },\r
1737             { "msg.no.brace.switch", "missing open brace before switch body" },\r
1738             { "msg.bad.switch", "invalid switch statement" },\r
1739             { "msg.no.colon.case", "missing : after case expression" },\r
1740             { "msg.no.while.do", "missing while after do-loop body" },\r
1741             { "msg.no.paren.for", "missing ( after for" },\r
1742             { "msg.no.semi.for", "missing ; after for-loop initializer" },\r
1743             { "msg.no.semi.for.cond", "missing ; after for-loop condition" },\r
1744             { "msg.no.paren.for.ctrl", "missing ) after for-loop control" },\r
1745             { "msg.no.paren.with", "missing ( before with-statement object" },\r
1746             { "msg.no.paren.after.with", "missing ) after with-statement object" },\r
1747             { "msg.bad.return", "invalid return" },\r
1748             { "msg.no.brace.block", "missing close brace in compound statement" },\r
1749             { "msg.bad.label", "invalid label" },\r
1750             { "msg.bad.var", "missing variable name" },\r
1751             { "msg.bad.var.init", "invalid variable initialization" },\r
1752             { "msg.no.colon.cond", "missing : in conditional expression" },\r
1753             { "msg.no.paren.arg", "missing ) after argument list" },\r
1754             { "msg.no.bracket.arg", "missing ] after element list" },\r
1755             { "msg.bad.prop", "invalid property id" },\r
1756             { "msg.no.colon.prop", "missing : after property id" },\r
1757             { "msg.no.brace.prop", "missing close brace after property list" },\r
1758             { "msg.no.paren", "missing ) in parenthetical" },\r
1759             { "msg.reserved.id", "identifier is a reserved word" },\r
1760             { "msg.no.paren.catch", "missing ( before catch-block condition" },\r
1761             { "msg.bad.catchcond", "invalid catch block condition" },\r
1762             { "msg.catch.unreachable", "any catch clauses following an unqualified catch are unreachable" },\r
1763             { "msg.no.brace.catchblock", "missing open brace before catch-block body" },\r
1764             { "msg.try.no.catchfinally", "''try'' without ''catch'' or ''finally''" },\r
1765             { "msg.syntax", "syntax error" },\r
1766             { "msg.assn.create", "Assignment to undefined \"{0}\" will create a new variable.  Add a variable statement at the top level scope to remove this warning." },\r
1767             { "msg.prop.not.found", "Property not found." },\r
1768             { "msg.invalid.type", "Invalid JavaScript value of type {0}" },\r
1769             { "msg.primitive.expected", "Primitive type expected (had {0} instead)" },\r
1770             { "msg.null.to.object", "Cannot convert null to an object." },\r
1771             { "msg.undef.to.object", "Cannot convert undefined to an object." },\r
1772             { "msg.cyclic.value", "Cyclic {0} value not allowed." },\r
1773             { "msg.is.not.defined", "\"{0}\" is not defined." },\r
1774             { "msg.isnt.function", "{0} is not a function." },\r
1775             { "msg.bad.default.value", "Object''s getDefaultValue() method returned an object." },\r
1776             { "msg.instanceof.not.object", " Can''t use instanceof on a non-object." },\r
1777             { "msg.instanceof.bad.prototype", " ''prototype'' property of {0} is not an object." },\r
1778             { "msg.bad.radix", " illegal radix {0}." },\r
1779             { "msg.default.value", "Cannot find default value for object." },\r
1780             { "msg.zero.arg.ctor", "Cannot load class \"{0}\" which has no zero-parameter constructor." },\r
1781             { "msg.multiple.ctors", "Cannot have more than one constructor method, but found both {0} and {1}." },\r
1782             { "msg.ctor.multiple.parms", "Can''t define constructor or class {0} since more than one  constructor has multiple parameters." },\r
1783             { "msg.extend.scriptable", "{0} must extend ScriptableObject in order to define property {1}." },\r
1784             { "msg.bad.getter.parms", "In order to define a property, getter {0} must have zero parameters  or a single ScriptableObject parameter." },\r
1785             { "msg.obj.getter.parms", "Expected static or delegated getter {0} to take a ScriptableObject parameter." },\r
1786             { "msg.getter.static", "Getter and setter must both be static or neither be static." },\r
1787             { "msg.setter2.parms", "Two-parameter setter must take a ScriptableObject as its first parameter." },\r
1788             { "msg.setter1.parms", "Expected single parameter setter for {0}" },\r
1789             { "msg.setter2.expected", "Expected static or delegated setter {0} to take two parameters." },\r
1790             { "msg.setter.parms", "Expected either one or two parameters for setter." },\r
1791             { "msg.add.sealed", "Cannot add a property to a sealed object." },\r
1792             { "msg.remove.sealed", "Cannot remove a property from a sealed object." },\r
1793             { "msg.token.replaces.pushback", "ungot token {0} replaces pushback token {1}" },\r
1794             { "msg.missing.exponent", "missing exponent" },\r
1795             { "msg.caught.nfe", "number format error: {0}" },\r
1796             { "msg.unterminated.string.lit", "unterminated string literal" },\r
1797             { "msg.oct.esc.too.large", "octal escape too large" },\r
1798             { "msg.nested.comment", "nested comment" },\r
1799             { "msg.unterminated.comment", "unterminated comment" },\r
1800             { "msg.unterminated.re.lit", "unterminated regular expression literal" },\r
1801             { "msg.invalid.re.flag", "invalid flag after regular expression" },\r
1802             { "msg.no.re.input.for", "no input for {0}" },\r
1803             { "msg.illegal.character", "illegal character" },\r
1804             { "msg.invalid.escape", "invalid Unicode escape sequence" },\r
1805             { "msg.bad.octal.literal", "illegal octal literal digit {0}; interpreting it as a decimal digit" },\r
1806             { "msg.undefined", "The undefined value has no properties." },\r
1807             { "msg.java.internal.field.type", "Internal error: type conversion of {0} to assign to {1} on {2} failed." },\r
1808             { "msg.java.conversion.implicit_method", "Can''t find converter method \"{0}\" on class {1}." },\r
1809             { "msg.java.method.assign", "Java method \"{0}\" cannot be assigned to." },\r
1810             { "msg.java.internal.private", "Internal error: attempt to access private/protected field \"{0}\"." },\r
1811             { "msg.java.no_such_method", "Can''t find method {0}." },\r
1812             { "msg.script.is.not.constructor", "Script objects are not constructors." },\r
1813             { "msg.nonjava.method", "Java method \"{0}\" was invoked with a ''this'' value that was not a Java object." },\r
1814             { "msg.java.member.not.found", "Java class \"{0}\" has no public instance field or method named \"{1}\"." },\r
1815             { "msg.pkg.int", "Java package names may not be numbers." },\r
1816             { "msg.ambig.import", "Ambiguous import: \"{0}\" and and \"{1}\"." },\r
1817             { "msg.not.pkg", "Function importPackage must be called with a package; had \"{0}\" instead." },\r
1818             { "msg.not.class", "Function importClass must be called with a class; had \"{0}\" instead." },\r
1819             { "msg.prop.defined", "Cannot import \"{0}\" since a property by that name is already defined." },\r
1820             { "msg.arraylength.bad", "Inappropriate array length." },\r
1821             { "msg.bad.uri", "Malformed URI sequence." },\r
1822             { "msg.bad.precision",      "Precision {0} out of range." }\r
1823         };\r
1824     }\r
1825 \r
1826     static final ResourceBundle myresources = new HardCodedResourceBundle();\r
1827 \r
1828     /* OPT there's a noticable delay for the first error!  Maybe it'd\r
1829      * make sense to use a ListResourceBundle instead of a properties\r
1830      * file to avoid (synchronized) text parsing.\r
1831      */\r
1832     static String getMessage(String messageId, Object[] arguments) {\r
1833         Context cx = getCurrentContext();\r
1834         Locale locale = cx != null ? cx.getLocale() : Locale.getDefault();\r
1835 \r
1836         // ResourceBundle does cacheing.\r
1837         ResourceBundle rb = myresources;\r
1838 \r
1839         String formatString;\r
1840         try {\r
1841             formatString = rb.getString(messageId);\r
1842         } catch (java.util.MissingResourceException mre) {\r
1843             throw new RuntimeException\r
1844                 ("no message resource found for message property "+ messageId);\r
1845         }\r
1846 \r
1847         /*\r
1848          * It's OK to format the string, even if 'arguments' is null;\r
1849          * we need to format it anyway, to make double ''s collapse to\r
1850          * single 's.\r
1851          */\r
1852         // TODO: MessageFormat is not available on pJava\r
1853         MessageFormat formatter = new MessageFormat(formatString);\r
1854         return formatter.format(arguments);\r
1855     }\r
1856 \r
1857     // debug flags\r
1858     static final boolean printTrees = false;\r
1859     \r
1860     /**\r
1861      * Compile a script.\r
1862      *\r
1863      * Reads script source from the reader and compiles it, returning\r
1864      * a class for either the script or the function depending on the\r
1865      * value of <code>returnFunction</code>.\r
1866      *\r
1867      * @param scope the scope to compile relative to\r
1868      * @param in the Reader to read source from\r
1869      * @param sourceName the name of the origin of the source (usually\r
1870      *                   a file or URL)\r
1871      * @param lineno the line number of the start of the source\r
1872      * @param securityDomain an arbitrary object that specifies security \r
1873      *        information about the origin or owner of the script. For \r
1874      *        implementations that don't care about security, this value \r
1875      *        may be null.\r
1876      * @param returnFunction if true, will expect the source to contain\r
1877      *                        a function; return value is assumed to\r
1878      *                        then be a org.mozilla.javascript.Function\r
1879      * @return a class for the script or function\r
1880      * @see org.mozilla.javascript.Context#compileReader\r
1881      */\r
1882     private Object compile(Scriptable scope, Reader in, String sourceName, \r
1883                            int lineno, Object securityDomain, \r
1884                            boolean returnFunction)\r
1885         throws IOException\r
1886     {\r
1887         if (debugger != null && in != null) {\r
1888             in = new DebugReader(in);\r
1889         }\r
1890         TokenStream ts = new TokenStream(in, scope, sourceName, lineno);\r
1891         return compile(scope, ts, securityDomain, in, returnFunction);\r
1892     }\r
1893 \r
1894     private static Class codegenClass = null;\r
1895     private static ClassNameHelper nameHelper = null;\r
1896     static {\r
1897         /*\r
1898         try {\r
1899             codegenClass = Class.forName(\r
1900                 "org.mozilla.javascript.optimizer.Codegen");\r
1901             Class nameHelperClass = Class.forName(\r
1902                 "org.mozilla.javascript.optimizer.OptClassNameHelper");\r
1903             nameHelper = (ClassNameHelper)nameHelperClass.newInstance();\r
1904         } catch (ClassNotFoundException x) {\r
1905             // ...must be running lite, that's ok\r
1906             codegenClass = null;\r
1907         } catch (IllegalAccessException x) {\r
1908             codegenClass = null;\r
1909         } catch (InstantiationException x) {\r
1910             codegenClass = null;\r
1911         }\r
1912         */\r
1913     }\r
1914     \r
1915     private Interpreter getCompiler() {\r
1916         if (codegenClass != null) {\r
1917             try {\r
1918                 return (Interpreter) codegenClass.newInstance();\r
1919             }\r
1920             catch (SecurityException x) {   \r
1921             }\r
1922             catch (IllegalArgumentException x) {\r
1923             }\r
1924             catch (InstantiationException x) {\r
1925             }\r
1926             catch (IllegalAccessException x) {\r
1927             }\r
1928             // fall through\r
1929         }\r
1930         return new Interpreter();\r
1931     }\r
1932     \r
1933     private Object compile(Scriptable scope, TokenStream ts, \r
1934                            Object securityDomain, Reader in,\r
1935                            boolean returnFunction)\r
1936         throws IOException\r
1937     {\r
1938         Interpreter compiler = optimizationLevel == -1 \r
1939                                ? new Interpreter()\r
1940                                : getCompiler();\r
1941         \r
1942         errorCount = 0;\r
1943         IRFactory irf = compiler.createIRFactory(ts, nameHelper, scope);\r
1944         Parser p = new Parser(irf);\r
1945         Node tree = (Node) p.parse(ts);\r
1946         if (tree == null) \r
1947             return null;\r
1948 \r
1949         tree = compiler.transform(tree, ts, scope);\r
1950 \r
1951         if (printTrees)\r
1952             System.out.println(tree.toStringTree());\r
1953         \r
1954         if (returnFunction) {\r
1955             Node first = tree.getFirstChild();\r
1956             if (first == null)\r
1957                 return null;\r
1958             tree = (Node) first.getProp(Node.FUNCTION_PROP);\r
1959             if (tree == null)\r
1960                 return null;\r
1961         }\r
1962         \r
1963         if (in instanceof DebugReader) {\r
1964             DebugReader dr = (DebugReader) in;\r
1965             tree.putProp(Node.DEBUGSOURCE_PROP, dr.getSaved());\r
1966         }\r
1967 \r
1968         Object result = compiler.compile(this, scope, tree, securityDomain,\r
1969                                          securitySupport, nameHelper);\r
1970 \r
1971         return errorCount == 0 ? result : null;\r
1972     }\r
1973 \r
1974     static String getSourcePositionFromStack(int[] linep) {\r
1975         Context cx = getCurrentContext();\r
1976         if (cx == null)\r
1977             return null;\r
1978         if (cx.interpreterLine > 0 && cx.interpreterSourceFile != null) {\r
1979             linep[0] = cx.interpreterLine;\r
1980             return cx.interpreterSourceFile;\r
1981         }\r
1982         /**\r
1983          * A bit of a hack, but the only way to get filename and line\r
1984          * number from an enclosing frame.\r
1985          */\r
1986         CharArrayWriter writer = new CharArrayWriter();\r
1987         RuntimeException re = new RuntimeException();\r
1988         re.printStackTrace(new PrintWriter(writer));\r
1989         String s = writer.toString();\r
1990         int open = -1;\r
1991         int close = -1;\r
1992         int colon = -1;\r
1993         for (int i=0; i < s.length(); i++) {\r
1994             char c = s.charAt(i);\r
1995             if (c == ':')\r
1996                 colon = i;\r
1997             else if (c == '(')\r
1998                 open = i;\r
1999             else if (c == ')')\r
2000                 close = i;\r
2001             else if (c == '\n' && open != -1 && close != -1 && colon != -1 && \r
2002                      open < colon && colon < close) \r
2003             {\r
2004                 String fileStr = s.substring(open + 1, colon);\r
2005                 if (fileStr.endsWith(".js")) {\r
2006                     String lineStr = s.substring(colon + 1, close);\r
2007                     try {\r
2008                         linep[0] = Integer.parseInt(lineStr);\r
2009                         return fileStr;\r
2010                     }\r
2011                     catch (NumberFormatException e) {\r
2012                         // fall through\r
2013                     }\r
2014                 }\r
2015                 open = close = colon = -1;\r
2016             }\r
2017         }\r
2018 \r
2019         return null;\r
2020     }\r
2021 \r
2022     RegExpProxy getRegExpProxy() {\r
2023         if (regExpProxy == null) {\r
2024             try {\r
2025                 Class c = Class.forName(\r
2026                             "org.mozilla.javascript.regexp.RegExpImpl");\r
2027                 regExpProxy = (RegExpProxy) c.newInstance();\r
2028                 return regExpProxy;\r
2029             } catch (ClassNotFoundException e) {\r
2030             } catch (InstantiationException e) {\r
2031             } catch (IllegalAccessException e) {\r
2032             }\r
2033         }\r
2034         return regExpProxy;\r
2035     }\r
2036 \r
2037     private void newArrayHelper(Scriptable scope, Scriptable array) {\r
2038         array.setParentScope(scope);\r
2039         Object ctor = ScriptRuntime.getTopLevelProp(scope, "Array");\r
2040         if (ctor != null && ctor instanceof Scriptable) {\r
2041             Scriptable s = (Scriptable) ctor;\r
2042             array.setPrototype((Scriptable) s.get("prototype", s));\r
2043         }\r
2044     }\r
2045     \r
2046     final boolean isVersionECMA1() {\r
2047         return version == VERSION_DEFAULT || version >= VERSION_1_3;\r
2048     }\r
2049 \r
2050     /**\r
2051      * Get the security context from the given class.\r
2052      * <p>\r
2053      * When some form of security check needs to be done, the class context\r
2054      * must retrieved from the security manager to determine what class is\r
2055      * requesting some form of privileged access. \r
2056      * @since 1.4 release 2\r
2057      */\r
2058     Object getSecurityDomainFromClass(Class cl) {\r
2059         if (cl == Interpreter.class)\r
2060             return interpreterSecurityDomain;\r
2061         return securitySupport.getSecurityDomain(cl);\r
2062     }\r
2063     \r
2064     SecuritySupport getSecuritySupport() {\r
2065         return securitySupport;\r
2066     }\r
2067     \r
2068     Object getSecurityDomainForStackDepth(int depth) {\r
2069         Object result = null;\r
2070         if (securitySupport != null) {\r
2071             Class[] classes = securitySupport.getClassContext();\r
2072             if (classes != null) {\r
2073                 if (depth != -1) {\r
2074                     int depth1 = depth + 1;\r
2075                     result = getSecurityDomainFromClass(classes[depth1]);\r
2076                 } else {\r
2077                     for (int i=1; i < classes.length; i++) {\r
2078                         result = getSecurityDomainFromClass(classes[i]);\r
2079                         if (result != null)\r
2080                             break;\r
2081                     }\r
2082                 }\r
2083             }\r
2084         }\r
2085         if (result != null)\r
2086             return result;\r
2087         if (requireSecurityDomain) \r
2088             checkSecurityDomainRequired();\r
2089         return null;\r
2090     }\r
2091 \r
2092     private static boolean requireSecurityDomain = false;\r
2093     private static boolean resourceMissing = false;\r
2094 \r
2095     final static String securityResourceName = "org.mozilla.javascript.resources.Security";\r
2096     \r
2097     final public static void checkSecurityDomainRequired() { }\r
2098 \r
2099     public boolean isGeneratingDebugChanged() {\r
2100         return generatingDebugChanged;\r
2101     }\r
2102     \r
2103 \r
2104     /**\r
2105      * Add a name to the list of names forcing the creation of real\r
2106      * activation objects for functions.\r
2107      *\r
2108      * @param name the name of the object to add to the list\r
2109      */\r
2110     public void addActivationName(String name) {\r
2111         if (activationNames == null) \r
2112             activationNames = new Hashtable(5);\r
2113         activationNames.put(name, name);\r
2114     }\r
2115 \r
2116     /**\r
2117      * Check whether the name is in the list of names of objects\r
2118      * forcing the creation of activation objects.\r
2119      *\r
2120      * @param name the name of the object to test\r
2121      *\r
2122      * @return true if an function activation object is needed.\r
2123      */\r
2124     public boolean isActivationNeeded(String name) {\r
2125         if ("arguments".equals(name))\r
2126             return true;\r
2127         return activationNames != null && activationNames.containsKey(name);\r
2128     }\r
2129 \r
2130     /**\r
2131      * Remove a name from the list of names forcing the creation of real\r
2132      * activation objects for functions.\r
2133      *\r
2134      * @param name the name of the object to remove from the list\r
2135      */\r
2136     public void removeActivationName(String name) {\r
2137         if (activationNames != null)\r
2138             activationNames.remove(name);\r
2139     }\r
2140 \r
2141 \r
2142     static final boolean useJSObject = false;\r
2143 \r
2144     /** \r
2145      * The activation of the currently executing function or script. \r
2146      */\r
2147     NativeCall currentActivation;\r
2148 \r
2149     // for Objects, Arrays to tag themselves as being printed out,\r
2150     // so they don't print themselves out recursively.\r
2151     Hashtable iterating;\r
2152             \r
2153     Object interpreterSecurityDomain;\r
2154 \r
2155     int version;\r
2156     int errorCount;\r
2157     static boolean isCachingEnabled = true;\r
2158     \r
2159     private SecuritySupport securitySupport;\r
2160     private ErrorReporter errorReporter;\r
2161     private Thread currentThread;\r
2162     private static Hashtable threadContexts = new Hashtable(11);\r
2163     private RegExpProxy regExpProxy;\r
2164     private Locale locale;\r
2165     private boolean generatingDebug;\r
2166     private boolean generatingDebugChanged;\r
2167     private boolean generatingSource=true;\r
2168     private boolean compileFunctionsWithDynamicScopeFlag;\r
2169     private int optimizationLevel;\r
2170     WrapHandler wrapHandler;\r
2171     Debugger debugger;\r
2172     DebuggableEngine debuggableEngine;\r
2173     boolean inLineStepMode;\r
2174     java.util.Stack frameStack;    \r
2175     private int enterCount;\r
2176     private Object[] listeners;\r
2177     private Hashtable hashtable;\r
2178 \r
2179     /**\r
2180      * This is the list of names of objects forcing the creation of\r
2181      * function activation records.\r
2182      */\r
2183     private Hashtable activationNames;\r
2184 \r
2185     // Private lock for static fields to avoid a possibility of denial\r
2186     // of service via synchronized (Context.class) { while (true) {} }\r
2187     private static final Object staticDataLock = new Object();\r
2188     private static Object[] contextListeners;\r
2189     public Function currentFunction;\r
2190     Vector arrayCache = new Vector(10);\r
2191 \r
2192     // For the interpreter to indicate line/source for error reports.\r
2193     public int interpreterLine;\r
2194     public String interpreterSourceFile;\r
2195 \r
2196     public int stackDepth = 0;\r
2197 \r
2198     // For instruction counting (interpreter only)\r
2199     int instructionCount;\r
2200     int instructionThreshold;\r
2201 }\r