~statik/etherpad/trunk

« back to all changes in this revision

Viewing changes to infrastructure/rhino1_7R1/src/org/mozilla/javascript/Context.java

  • Committer: Elliot Murphy
  • Date: 2009-12-19 01:40:46 UTC
  • Revision ID: elliot@elliotmurphy.com-20091219014046-7icbb6oxc29ccdn3
Copied over from zero-history mercurial repo.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 * ***** BEGIN LICENSE BLOCK *****
 
4
 * Version: MPL 1.1/GPL 2.0
 
5
 *
 
6
 * The contents of this file are subject to the Mozilla Public License Version
 
7
 * 1.1 (the "License"); you may not use this file except in compliance with
 
8
 * the License. You may obtain a copy of the License at
 
9
 * http://www.mozilla.org/MPL/
 
10
 *
 
11
 * Software distributed under the License is distributed on an "AS IS" basis,
 
12
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
13
 * for the specific language governing rights and limitations under the
 
14
 * License.
 
15
 *
 
16
 * The Original Code is Rhino code, released
 
17
 * May 6, 1999.
 
18
 *
 
19
 * The Initial Developer of the Original Code is
 
20
 * Netscape Communications Corporation.
 
21
 * Portions created by the Initial Developer are Copyright (C) 1997-2000
 
22
 * the Initial Developer. All Rights Reserved.
 
23
 *
 
24
 * Contributor(s):
 
25
 *    Bob Jervis
 
26
 *
 
27
 * Alternatively, the contents of this file may be used under the terms of
 
28
 * the GNU General Public License Version 2 or later (the "GPL"), in which
 
29
 * case the provisions of the GPL are applicable instead of those above. If
 
30
 * you wish to allow use of your version of this file only under the terms of
 
31
 * the GPL and not to allow others to use your version of this file under the
 
32
 * MPL, indicate your decision by deleting the provisions above and replacing
 
33
 * them with the notice and other provisions required by the GPL. If you do
 
34
 * not delete the provisions above, a recipient may use your version of this
 
35
 * file under either the MPL or the GPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
// API class
 
40
 
 
41
package org.mozilla.javascript;
 
42
 
 
43
import java.beans.PropertyChangeEvent;
 
44
import java.beans.PropertyChangeListener;
 
45
import java.io.CharArrayWriter;
 
46
import java.io.IOException;
 
47
import java.io.PrintWriter;
 
48
import java.io.Reader;
 
49
import java.io.StringWriter;
 
50
import java.io.Writer;
 
51
import java.lang.reflect.InvocationTargetException;
 
52
import java.lang.reflect.Method;
 
53
import java.util.Hashtable;
 
54
import java.util.Locale;
 
55
 
 
56
import org.mozilla.javascript.debug.DebuggableScript;
 
57
import org.mozilla.javascript.debug.Debugger;
 
58
import org.mozilla.javascript.xml.XMLLib;
 
59
 
 
60
/**
 
61
 * This class represents the runtime context of an executing script.
 
62
 *
 
63
 * Before executing a script, an instance of Context must be created
 
64
 * and associated with the thread that will be executing the script.
 
65
 * The Context will be used to store information about the executing
 
66
 * of the script such as the call stack. Contexts are associated with
 
67
 * the current thread  using the {@link #call(ContextAction)}
 
68
 * or {@link #enter()} methods.<p>
 
69
 *
 
70
 * Different forms of script execution are supported. Scripts may be
 
71
 * evaluated from the source directly, or first compiled and then later
 
72
 * executed. Interactive execution is also supported.<p>
 
73
 *
 
74
 * Some aspects of script execution, such as type conversions and
 
75
 * object creation, may be accessed directly through methods of
 
76
 * Context.
 
77
 *
 
78
 * @see Scriptable
 
79
 * @author Norris Boyd
 
80
 * @author Brendan Eich
 
81
 */
 
82
 
 
83
public class Context
 
84
{
 
85
    /**
 
86
     * Language versions.
 
87
     *
 
88
     * All integral values are reserved for future version numbers.
 
89
     */
 
90
 
 
91
    /**
 
92
     * The unknown version.
 
93
     */
 
94
    public static final int VERSION_UNKNOWN =   -1;
 
95
 
 
96
    /**
 
97
     * The default version.
 
98
     */
 
99
    public static final int VERSION_DEFAULT =    0;
 
100
 
 
101
    /**
 
102
     * JavaScript 1.0
 
103
     */
 
104
    public static final int VERSION_1_0 =      100;
 
105
 
 
106
    /**
 
107
     * JavaScript 1.1
 
108
     */
 
109
    public static final int VERSION_1_1 =      110;
 
110
 
 
111
    /**
 
112
     * JavaScript 1.2
 
113
     */
 
114
    public static final int VERSION_1_2 =      120;
 
115
 
 
116
    /**
 
117
     * JavaScript 1.3
 
118
     */
 
119
    public static final int VERSION_1_3 =      130;
 
120
 
 
121
    /**
 
122
     * JavaScript 1.4
 
123
     */
 
124
    public static final int VERSION_1_4 =      140;
 
125
 
 
126
    /**
 
127
     * JavaScript 1.5
 
128
     */
 
129
    public static final int VERSION_1_5 =      150;
 
130
 
 
131
    /**
 
132
     * JavaScript 1.6
 
133
     */
 
134
    public static final int VERSION_1_6 =      160;
 
135
 
 
136
    /**
 
137
     * JavaScript 1.7
 
138
     */
 
139
    public static final int VERSION_1_7 =      170;
 
140
 
 
141
    /**
 
142
     * Controls behaviour of <tt>Date.prototype.getYear()</tt>.
 
143
     * If <tt>hasFeature(FEATURE_NON_ECMA_GET_YEAR)</tt> returns true,
 
144
     * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000.
 
145
     * The default behavior of {@link #hasFeature(int)} is always to subtruct
 
146
     * 1900 as rquired by ECMAScript B.2.4.
 
147
     */
 
148
    public static final int FEATURE_NON_ECMA_GET_YEAR = 1;
 
149
 
 
150
    /**
 
151
     * Control if member expression as function name extension is available.
 
152
     * If <tt>hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME)</tt> returns
 
153
     * true, allow <tt>function memberExpression(args) { body }</tt> to be
 
154
     * syntax sugar for <tt>memberExpression = function(args) { body }</tt>,
 
155
     * when memberExpression is not a simple identifier.
 
156
     * See ECMAScript-262, section 11.2 for definition of memberExpression.
 
157
     * By default {@link #hasFeature(int)} returns false.
 
158
     */
 
159
    public static final int FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME = 2;
 
160
 
 
161
    /**
 
162
     * Control if reserved keywords are treated as identifiers.
 
163
     * If <tt>hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER)</tt> returns true,
 
164
     * treat future reserved keyword (see  Ecma-262, section 7.5.3) as ordinary
 
165
     * identifiers but warn about this usage.
 
166
     *
 
167
     * By default {@link #hasFeature(int)} returns false.
 
168
     */
 
169
    public static final int FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER = 3;
 
170
 
 
171
    /**
 
172
     * Control if <tt>toString()</tt> should returns the same result
 
173
     * as  <tt>toSource()</tt> when applied to objects and arrays.
 
174
     * If <tt>hasFeature(FEATURE_TO_STRING_AS_SOURCE)</tt> returns true,
 
175
     * calling <tt>toString()</tt> on JS objects gives the same result as
 
176
     * calling <tt>toSource()</tt>. That is it returns JS source with code
 
177
     * to create an object with all enumeratable fields of the original object
 
178
     * instead of printing <tt>[object <i>result of
 
179
     * {@link Scriptable#getClassName()}</i>]</tt>.
 
180
     * <p>
 
181
     * By default {@link #hasFeature(int)} returns true only if
 
182
     * the current JS version is set to {@link #VERSION_1_2}.
 
183
     */
 
184
    public static final int FEATURE_TO_STRING_AS_SOURCE = 4;
 
185
 
 
186
    /**
 
187
     * Control if properties <tt>__proto__</tt> and <tt>__parent__</tt>
 
188
     * are treated specially.
 
189
     * If <tt>hasFeature(FEATURE_PARENT_PROTO_PROPERTIES)</tt> returns true,
 
190
     * treat <tt>__parent__</tt> and <tt>__proto__</tt> as special properties.
 
191
     * <p>
 
192
     * The properties allow to query and set scope and prototype chains for the
 
193
     * objects. The special meaning of the properties is available
 
194
     * only when they are used as the right hand side of the dot operator.
 
195
     * For example, while <tt>x.__proto__ = y</tt> changes the prototype
 
196
     * chain of the object <tt>x</tt> to point to <tt>y</tt>,
 
197
     * <tt>x["__proto__"] = y</tt> simply assigns a new value to the property
 
198
     * <tt>__proto__</tt> in <tt>x</tt> even when the feature is on.
 
199
     *
 
200
     * By default {@link #hasFeature(int)} returns true.
 
201
     */
 
202
    public static final int FEATURE_PARENT_PROTO_PROPERTIES = 5;
 
203
 
 
204
        /**
 
205
         * @deprecated In previous releases, this name was given to
 
206
         * FEATURE_PARENT_PROTO_PROPERTIES.
 
207
         */
 
208
    public static final int FEATURE_PARENT_PROTO_PROPRTIES = 5;
 
209
        
 
210
    /**
 
211
     * Control if support for E4X(ECMAScript for XML) extension is available.
 
212
     * If hasFeature(FEATURE_E4X) returns true, the XML syntax is available.
 
213
     * <p>
 
214
     * By default {@link #hasFeature(int)} returns true if
 
215
     * the current JS version is set to {@link #VERSION_DEFAULT}
 
216
     * or is at least {@link #VERSION_1_6}.
 
217
     * @since 1.6 Release 1
 
218
     */
 
219
    public static final int FEATURE_E4X = 6;
 
220
 
 
221
    /**
 
222
     * Control if dynamic scope should be used for name access.
 
223
     * If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup
 
224
     * during name resolution will use the top scope of the script or function
 
225
     * which is at the top of JS execution stack instead of the top scope of the
 
226
     * script or function from the current stack frame if the top scope of
 
227
     * the top stack frame contains the top scope of the current stack frame
 
228
     * on its prototype chain.
 
229
     * <p>
 
230
     * This is useful to define shared scope containing functions that can
 
231
     * be called from scripts and functions using private scopes.
 
232
     * <p>
 
233
     * By default {@link #hasFeature(int)} returns false.
 
234
     * @since 1.6 Release 1
 
235
     */
 
236
    public static final int FEATURE_DYNAMIC_SCOPE = 7;
 
237
 
 
238
    /**
 
239
     * Control if strict variable mode is enabled.
 
240
     * When the feature is on Rhino reports runtime errors if assignment
 
241
     * to a global variable that does not exist is executed. When the feature
 
242
     * is off such assignments creates new variable in the global scope  as
 
243
     * required by ECMA 262.
 
244
     * <p>
 
245
     * By default {@link #hasFeature(int)} returns false.
 
246
     * @since 1.6 Release 1
 
247
     */
 
248
    public static final int FEATURE_STRICT_VARS = 8;
 
249
 
 
250
    /**
 
251
     * Control if strict eval mode is enabled.
 
252
     * When the feature is on Rhino reports runtime errors if non-string
 
253
     * argument is passed to the eval function. When the feature is off
 
254
     * eval simply return non-string argument as is without performing any
 
255
     * evaluation as required by ECMA 262.
 
256
     * <p>
 
257
     * By default {@link #hasFeature(int)} returns false.
 
258
     * @since 1.6 Release 1
 
259
     */
 
260
    public static final int FEATURE_STRICT_EVAL = 9;
 
261
 
 
262
    /**
 
263
     * When the feature is on Rhino will add a "fileName" and "lineNumber"
 
264
     * properties to Error objects automatically. When the feature is off, you
 
265
     * have to explicitly pass them as the second and third argument to the
 
266
     * Error constructor. Note that neither behaviour is fully ECMA 262 
 
267
     * compliant (as 262 doesn't specify a three-arg constructor), but keeping 
 
268
     * the feature off results in Error objects that don't have
 
269
     * additional non-ECMA properties when constructed using the ECMA-defined
 
270
     * single-arg constructor and is thus desirable if a stricter ECMA 
 
271
     * compliance is desired, specifically adherence to the point 15.11.5. of
 
272
     * the standard.
 
273
     * <p>
 
274
     * By default {@link #hasFeature(int)} returns false.
 
275
     * @since 1.6 Release 6
 
276
     */
 
277
    public static final int FEATURE_LOCATION_INFORMATION_IN_ERROR = 10;
 
278
 
 
279
    /**
 
280
     * Controls whether JS 1.5 'strict mode' is enabled.
 
281
     * When the feature is on, Rhino reports more than a dozen different
 
282
     * warnings.  When the feature is off, these warnings are not generated.
 
283
     * FEATURE_STRICT_MODE implies FEATURE_STRICT_VARS and FEATURE_STRICT_EVAL.
 
284
     * <p>
 
285
     * By default {@link #hasFeature(int)} returns false.
 
286
     * @since 1.6 Release 6
 
287
     */
 
288
    public static final int FEATURE_STRICT_MODE = 11;
 
289
 
 
290
    /**
 
291
     * Controls whether a warning should be treated as an error.
 
292
     * @since 1.6 Release 6
 
293
     */
 
294
    public static final int FEATURE_WARNING_AS_ERROR = 12;
 
295
 
 
296
    /**
 
297
     * Enables enhanced access to Java. 
 
298
     * Specifically, controls whether private and protected members can be
 
299
     * accessed, and whether scripts can catch all Java exceptions.
 
300
     * <p>
 
301
     * Note that this feature should only be enabled for trusted scripts.
 
302
     * <p>
 
303
     * By default {@link #hasFeature(int)} returns false.
 
304
     * @since 1.7 Release 1
 
305
     */
 
306
    public static final int FEATURE_ENHANCED_JAVA_ACCESS = 13;
 
307
 
 
308
 
 
309
    public static final String languageVersionProperty = "language version";
 
310
    public static final String errorReporterProperty   = "error reporter";
 
311
 
 
312
    /**
 
313
     * Convenient value to use as zero-length array of objects.
 
314
     */
 
315
    public static final Object[] emptyArgs = ScriptRuntime.emptyArgs;
 
316
 
 
317
    /**
 
318
     * Create a new Context.
 
319
     *
 
320
     * Note that the Context must be associated with a thread before
 
321
     * it can be used to execute a script.
 
322
     * @deprecated use {@link ContextFactory#enter()} or 
 
323
     * {@link ContextFactory#call(ContextAction)} instead.
 
324
     */
 
325
    public Context()
 
326
    {
 
327
        this(ContextFactory.getGlobal());
 
328
    }
 
329
    
 
330
    Context(ContextFactory factory)
 
331
    {
 
332
        assert factory != null;
 
333
        this.factory = factory;
 
334
        setLanguageVersion(VERSION_DEFAULT);
 
335
        optimizationLevel = codegenClass != null ? 0 : -1;
 
336
        maximumInterpreterStackDepth = Integer.MAX_VALUE;
 
337
    }
 
338
 
 
339
    /**
 
340
     * Get the current Context.
 
341
     *
 
342
     * The current Context is per-thread; this method looks up
 
343
     * the Context associated with the current thread. <p>
 
344
     *
 
345
     * @return the Context associated with the current thread, or
 
346
     *         null if no context is associated with the current
 
347
     *         thread.
 
348
     * @see ContextFactory#enterContext()
 
349
     * @see ContextFactory#call(ContextAction)
 
350
     */
 
351
    public static Context getCurrentContext()
 
352
    {
 
353
        Object helper = VMBridge.instance.getThreadContextHelper();
 
354
        return VMBridge.instance.getContext(helper);
 
355
    }
 
356
 
 
357
    /**
 
358
     * Same as calling {@link ContextFactory#enterContext()} on the global
 
359
     * ContextFactory instance.
 
360
     * @deprecated use {@link ContextFactory#enter()} or 
 
361
     * {@link ContextFactory#call(ContextAction)} instead as this method relies
 
362
     * on usage of a static singleton "global" ContextFactory.
 
363
     * @return a Context associated with the current thread
 
364
     * @see #getCurrentContext()
 
365
     * @see #exit()
 
366
     * @see #call(ContextAction)
 
367
     */
 
368
    public static Context enter()
 
369
    {
 
370
        return enter(null);
 
371
    }
 
372
 
 
373
    /**
 
374
     * Get a Context associated with the current thread, using
 
375
     * the given Context if need be.
 
376
     * <p>
 
377
     * The same as <code>enter()</code> except that <code>cx</code>
 
378
     * is associated with the current thread and returned if
 
379
     * the current thread has no associated context and <code>cx</code>
 
380
     * is not associated with any other thread.
 
381
     * @param cx a Context to associate with the thread if possible
 
382
     * @return a Context associated with the current thread
 
383
     * @deprecated use {@link ContextFactory#enterContext(Context)} instead as 
 
384
     * this method relies on usage of a static singleton "global" ContextFactory.
 
385
     * @see ContextFactory#enterContext(Context)
 
386
     * @see ContextFactory#call(ContextAction)
 
387
     */
 
388
    public static Context enter(Context cx)
 
389
    {
 
390
        return enter(cx, ContextFactory.getGlobal());
 
391
    }
 
392
    
 
393
    static final Context enter(Context cx, ContextFactory factory)
 
394
    {
 
395
        Object helper = VMBridge.instance.getThreadContextHelper();
 
396
        Context old = VMBridge.instance.getContext(helper);
 
397
        if (old != null) {
 
398
            cx = old;
 
399
        } else {
 
400
            if (cx == null) {
 
401
                cx = factory.makeContext();
 
402
                if (cx.enterCount != 0) {
 
403
                    throw new IllegalStateException("factory.makeContext() returned Context instance already associated with some thread");
 
404
                }
 
405
                factory.onContextCreated(cx);
 
406
                if (factory.isSealed() && !cx.isSealed()) {
 
407
                    cx.seal(null);
 
408
                }
 
409
            } else {
 
410
                if (cx.enterCount != 0) {
 
411
                    throw new IllegalStateException("can not use Context instance already associated with some thread");
 
412
                }
 
413
            }
 
414
            VMBridge.instance.setContext(helper, cx);
 
415
        }
 
416
        ++cx.enterCount;
 
417
        return cx;
 
418
     }
 
419
 
 
420
    /**
 
421
     * Exit a block of code requiring a Context.
 
422
     *
 
423
     * Calling <code>exit()</code> will remove the association between
 
424
     * the current thread and a Context if the prior call to
 
425
     * {@link ContextFactory#enterContext()} on this thread newly associated a 
 
426
     * Context with this thread. Once the current thread no longer has an 
 
427
     * associated Context, it cannot be used to execute JavaScript until it is 
 
428
     * again associated with a Context.
 
429
     * @see ContextFactory#enterContext()
 
430
     */
 
431
    public static void exit()
 
432
    {
 
433
        Object helper = VMBridge.instance.getThreadContextHelper();
 
434
        Context cx = VMBridge.instance.getContext(helper);
 
435
        if (cx == null) {
 
436
            throw new IllegalStateException(
 
437
                "Calling Context.exit without previous Context.enter");
 
438
        }
 
439
        if (cx.enterCount < 1) Kit.codeBug();
 
440
        if (--cx.enterCount == 0) {
 
441
            VMBridge.instance.setContext(helper, null);
 
442
            cx.factory.onContextReleased(cx);
 
443
        }
 
444
    }
 
445
    
 
446
    /**
 
447
     * Call {@link ContextAction#run(Context cx)}
 
448
     * using the Context instance associated with the current thread.
 
449
     * If no Context is associated with the thread, then
 
450
     * <tt>ContextFactory.getGlobal().makeContext()</tt> will be called to
 
451
     * construct new Context instance. The instance will be temporary
 
452
     * associated with the thread during call to
 
453
     * {@link ContextAction#run(Context)}.
 
454
     * @deprecated use {@link ContextFactory#call(ContextAction)} instead as 
 
455
     * this method relies on usage of a static singleton "global" 
 
456
     * ContextFactory.
 
457
     * @return The result of {@link ContextAction#run(Context)}.
 
458
     */
 
459
    public static Object call(ContextAction action)
 
460
    {
 
461
        return call(ContextFactory.getGlobal(), action);
 
462
    }
 
463
 
 
464
    /**
 
465
     * Call {@link
 
466
     * Callable#call(Context cx, Scriptable scope, Scriptable thisObj,
 
467
     *               Object[] args)}
 
468
     * using the Context instance associated with the current thread.
 
469
     * If no Context is associated with the thread, then
 
470
     * {@link ContextFactory#makeContext()} will be called to construct
 
471
     * new Context instance. The instance will be temporary associated
 
472
     * with the thread during call to {@link ContextAction#run(Context)}.
 
473
     * <p>
 
474
     * It is allowed but not advisable to use null for <tt>factory</tt> 
 
475
     * argument in which case the global static singleton ContextFactory 
 
476
     * instance will be used to create new context instances.
 
477
     * @see ContextFactory#call(ContextAction)
 
478
     */
 
479
    public static Object call(ContextFactory factory, final Callable callable,
 
480
                              final Scriptable scope, final Scriptable thisObj,
 
481
                              final Object[] args)
 
482
    {
 
483
        if(factory == null) {
 
484
            factory = ContextFactory.getGlobal();
 
485
        }
 
486
        return call(factory, new ContextAction() {
 
487
            public Object run(Context cx) {
 
488
                return callable.call(cx, scope, thisObj, args);
 
489
            }
 
490
        });
 
491
    }
 
492
    
 
493
    /**
 
494
     * The method implements {@links ContextFactory#call(ContextAction)} logic.
 
495
     */
 
496
    static Object call(ContextFactory factory, ContextAction action) {
 
497
        Context cx = enter(null, factory);
 
498
        try {
 
499
            return action.run(cx);
 
500
        }
 
501
        finally {
 
502
            exit();
 
503
        }
 
504
    }
 
505
 
 
506
    /**
 
507
     * @deprecated
 
508
     * @see ContextFactory#addListener(ContextFactory.Listener)
 
509
     * @see ContextFactory#getGlobal()
 
510
     */
 
511
    public static void addContextListener(ContextListener listener)
 
512
    {
 
513
        // Special workaround for the debugger
 
514
        String DBG = "org.mozilla.javascript.tools.debugger.Main";
 
515
        if (DBG.equals(listener.getClass().getName())) {
 
516
            Class cl = listener.getClass();
 
517
            Class factoryClass = Kit.classOrNull(
 
518
                "org.mozilla.javascript.ContextFactory");
 
519
            Class[] sig = { factoryClass };
 
520
            Object[] args = { ContextFactory.getGlobal() };
 
521
            try {
 
522
                Method m = cl.getMethod("attachTo", sig);
 
523
                m.invoke(listener, args);
 
524
            } catch (Exception ex) {
 
525
                RuntimeException rex = new RuntimeException();
 
526
                Kit.initCause(rex, ex);
 
527
                throw rex;
 
528
            }
 
529
            return;
 
530
        }
 
531
 
 
532
        ContextFactory.getGlobal().addListener(listener);
 
533
    }
 
534
 
 
535
    /**
 
536
     * @deprecated
 
537
     * @see ContextFactory#removeListener(ContextFactory.Listener)
 
538
     * @see ContextFactory#getGlobal()
 
539
     */
 
540
    public static void removeContextListener(ContextListener listener)
 
541
    {
 
542
        ContextFactory.getGlobal().addListener(listener);
 
543
    }
 
544
 
 
545
    /**
 
546
     * Return {@link ContextFactory} instance used to create this Context.
 
547
     */
 
548
    public final ContextFactory getFactory()
 
549
    {
 
550
        return factory;
 
551
    }
 
552
 
 
553
    /**
 
554
     * Checks if this is a sealed Context. A sealed Context instance does not
 
555
     * allow to modify any of its properties and will throw an exception
 
556
     * on any such attempt.
 
557
     * @see #seal(Object sealKey)
 
558
     */
 
559
    public final boolean isSealed()
 
560
    {
 
561
        return sealed;
 
562
    }
 
563
 
 
564
    /**
 
565
     * Seal this Context object so any attempt to modify any of its properties
 
566
     * including calling {@link #enter()} and {@link #exit()} methods will
 
567
     * throw an exception.
 
568
     * <p>
 
569
     * If <tt>sealKey</tt> is not null, calling
 
570
     * {@link #unseal(Object sealKey)} with the same key unseals
 
571
     * the object. If <tt>sealKey</tt> is null, unsealing is no longer possible.
 
572
     *
 
573
     * @see #isSealed()
 
574
     * @see #unseal(Object)
 
575
     */
 
576
    public final void seal(Object sealKey)
 
577
    {
 
578
        if (sealed) onSealedMutation();
 
579
        sealed = true;
 
580
        this.sealKey = sealKey;
 
581
    }
 
582
 
 
583
    /**
 
584
     * Unseal previously sealed Context object.
 
585
     * The <tt>sealKey</tt> argument should not be null and should match
 
586
     * <tt>sealKey</tt> suplied with the last call to
 
587
     * {@link #seal(Object)} or an exception will be thrown.
 
588
     *
 
589
     * @see #isSealed()
 
590
     * @see #seal(Object sealKey)
 
591
     */
 
592
    public final void unseal(Object sealKey)
 
593
    {
 
594
        if (sealKey == null) throw new IllegalArgumentException();
 
595
        if (this.sealKey != sealKey) throw new IllegalArgumentException();
 
596
        if (!sealed) throw new IllegalStateException();
 
597
        sealed = false;
 
598
        this.sealKey = null;
 
599
    }
 
600
 
 
601
    static void onSealedMutation()
 
602
    {
 
603
        throw new IllegalStateException();
 
604
    }
 
605
 
 
606
    /**
 
607
     * Get the current language version.
 
608
     * <p>
 
609
     * The language version number affects JavaScript semantics as detailed
 
610
     * in the overview documentation.
 
611
     *
 
612
     * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
 
613
     */
 
614
    public final int getLanguageVersion()
 
615
    {
 
616
       return version;
 
617
    }
 
618
 
 
619
    /**
 
620
     * Set the language version.
 
621
     *
 
622
     * <p>
 
623
     * Setting the language version will affect functions and scripts compiled
 
624
     * subsequently. See the overview documentation for version-specific
 
625
     * behavior.
 
626
     *
 
627
     * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
 
628
     */
 
629
    public void setLanguageVersion(int version)
 
630
    {
 
631
        if (sealed) onSealedMutation();
 
632
        checkLanguageVersion(version);
 
633
        Object listeners = propertyListeners;
 
634
        if (listeners != null && version != this.version) {
 
635
            firePropertyChangeImpl(listeners, languageVersionProperty,
 
636
                               new Integer(this.version),
 
637
                               new Integer(version));
 
638
        }
 
639
        this.version = version;
 
640
    }
 
641
 
 
642
    public static boolean isValidLanguageVersion(int version)
 
643
    {
 
644
        switch (version) {
 
645
            case VERSION_DEFAULT:
 
646
            case VERSION_1_0:
 
647
            case VERSION_1_1:
 
648
            case VERSION_1_2:
 
649
            case VERSION_1_3:
 
650
            case VERSION_1_4:
 
651
            case VERSION_1_5:
 
652
            case VERSION_1_6:
 
653
            case VERSION_1_7:
 
654
                return true;
 
655
        }
 
656
        return false;
 
657
    }
 
658
 
 
659
    public static void checkLanguageVersion(int version)
 
660
    {
 
661
        if (isValidLanguageVersion(version)) {
 
662
            return;
 
663
        }
 
664
        throw new IllegalArgumentException("Bad language version: "+version);
 
665
    }
 
666
 
 
667
    /**
 
668
     * Get the implementation version.
 
669
     *
 
670
     * <p>
 
671
     * The implementation version is of the form
 
672
     * <pre>
 
673
     *    "<i>name langVer</i> <code>release</code> <i>relNum date</i>"
 
674
     * </pre>
 
675
     * where <i>name</i> is the name of the product, <i>langVer</i> is
 
676
     * the language version, <i>relNum</i> is the release number, and
 
677
     * <i>date</i> is the release date for that specific
 
678
     * release in the form "yyyy mm dd".
 
679
     *
 
680
     * @return a string that encodes the product, language version, release
 
681
     *         number, and date.
 
682
     */
 
683
    public final String getImplementationVersion()
 
684
    {
 
685
        // XXX Probably it would be better to embed this directly into source
 
686
        // with special build preprocessing but that would require some ant
 
687
        // tweaking and then replacing token in resource files was simpler
 
688
        if (implementationVersion == null) {
 
689
            implementationVersion
 
690
                = ScriptRuntime.getMessage0("implementation.version");
 
691
        }
 
692
        return implementationVersion;
 
693
    }
 
694
 
 
695
    /**
 
696
     * Get the current error reporter.
 
697
     *
 
698
     * @see org.mozilla.javascript.ErrorReporter
 
699
     */
 
700
    public final ErrorReporter getErrorReporter()
 
701
    {
 
702
        if (errorReporter == null) {
 
703
            return DefaultErrorReporter.instance;
 
704
        }
 
705
        return errorReporter;
 
706
    }
 
707
 
 
708
    /**
 
709
     * Change the current error reporter.
 
710
     *
 
711
     * @return the previous error reporter
 
712
     * @see org.mozilla.javascript.ErrorReporter
 
713
     */
 
714
    public final ErrorReporter setErrorReporter(ErrorReporter reporter)
 
715
    {
 
716
        if (sealed) onSealedMutation();
 
717
        if (reporter == null) throw new IllegalArgumentException();
 
718
        ErrorReporter old = getErrorReporter();
 
719
        if (reporter == old) {
 
720
            return old;
 
721
        }
 
722
        Object listeners = propertyListeners;
 
723
        if (listeners != null) {
 
724
            firePropertyChangeImpl(listeners, errorReporterProperty,
 
725
                                   old, reporter);
 
726
        }
 
727
        this.errorReporter = reporter;
 
728
        return old;
 
729
    }
 
730
 
 
731
    /**
 
732
     * Get the current locale.  Returns the default locale if none has
 
733
     * been set.
 
734
     *
 
735
     * @see java.util.Locale
 
736
     */
 
737
 
 
738
    public final Locale getLocale()
 
739
    {
 
740
        if (locale == null)
 
741
            locale = Locale.getDefault();
 
742
        return locale;
 
743
    }
 
744
 
 
745
    /**
 
746
     * Set the current locale.
 
747
     *
 
748
     * @see java.util.Locale
 
749
     */
 
750
    public final Locale setLocale(Locale loc)
 
751
    {
 
752
        if (sealed) onSealedMutation();
 
753
        Locale result = locale;
 
754
        locale = loc;
 
755
        return result;
 
756
    }
 
757
 
 
758
    /**
 
759
     * Register an object to receive notifications when a bound property
 
760
     * has changed
 
761
     * @see java.beans.PropertyChangeEvent
 
762
     * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
 
763
     * @param l the listener
 
764
     */
 
765
    public final void addPropertyChangeListener(PropertyChangeListener l)
 
766
    {
 
767
        if (sealed) onSealedMutation();
 
768
        propertyListeners = Kit.addListener(propertyListeners, l);
 
769
    }
 
770
 
 
771
    /**
 
772
     * Remove an object from the list of objects registered to receive
 
773
     * notification of changes to a bounded property
 
774
     * @see java.beans.PropertyChangeEvent
 
775
     * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
 
776
     * @param l the listener
 
777
     */
 
778
    public final void removePropertyChangeListener(PropertyChangeListener l)
 
779
    {
 
780
        if (sealed) onSealedMutation();
 
781
        propertyListeners = Kit.removeListener(propertyListeners, l);
 
782
    }
 
783
 
 
784
    /**
 
785
     * Notify any registered listeners that a bounded property has changed
 
786
     * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
 
787
     * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
 
788
     * @see java.beans.PropertyChangeListener
 
789
     * @see java.beans.PropertyChangeEvent
 
790
     * @param  property  the bound property
 
791
     * @param  oldValue  the old value
 
792
     * @param  newValue   the new value
 
793
     */
 
794
    final void firePropertyChange(String property, Object oldValue,
 
795
                                  Object newValue)
 
796
    {
 
797
        Object listeners = propertyListeners;
 
798
        if (listeners != null) {
 
799
            firePropertyChangeImpl(listeners, property, oldValue, newValue);
 
800
        }
 
801
    }
 
802
 
 
803
    private void firePropertyChangeImpl(Object listeners, String property,
 
804
                                        Object oldValue, Object newValue)
 
805
    {
 
806
        for (int i = 0; ; ++i) {
 
807
            Object l = Kit.getListener(listeners, i);
 
808
            if (l == null)
 
809
                break;
 
810
            if (l instanceof PropertyChangeListener) {
 
811
                PropertyChangeListener pcl = (PropertyChangeListener)l;
 
812
                pcl.propertyChange(new PropertyChangeEvent(
 
813
                    this, property, oldValue, newValue));
 
814
            }
 
815
        }
 
816
    }
 
817
 
 
818
    /**
 
819
     * Report a warning using the error reporter for the current thread.
 
820
     *
 
821
     * @param message the warning message to report
 
822
     * @param sourceName a string describing the source, such as a filename
 
823
     * @param lineno the starting line number
 
824
     * @param lineSource the text of the line (may be null)
 
825
     * @param lineOffset the offset into lineSource where problem was detected
 
826
     * @see org.mozilla.javascript.ErrorReporter
 
827
     */
 
828
    public static void reportWarning(String message, String sourceName,
 
829
                                     int lineno, String lineSource,
 
830
                                     int lineOffset)
 
831
    {
 
832
        Context cx = Context.getContext();
 
833
        if (cx.hasFeature(FEATURE_WARNING_AS_ERROR))
 
834
            reportError(message, sourceName, lineno, lineSource, lineOffset);
 
835
        else
 
836
            cx.getErrorReporter().warning(message, sourceName, lineno,
 
837
                                          lineSource, lineOffset);
 
838
    }
 
839
 
 
840
    /**
 
841
     * Report a warning using the error reporter for the current thread.
 
842
     *
 
843
     * @param message the warning message to report
 
844
     * @see org.mozilla.javascript.ErrorReporter
 
845
     */
 
846
    public static void reportWarning(String message)
 
847
    {
 
848
        int[] linep = { 0 };
 
849
        String filename = getSourcePositionFromStack(linep);
 
850
        Context.reportWarning(message, filename, linep[0], null, 0);
 
851
    }
 
852
 
 
853
    public static void reportWarning(String message, Throwable t)
 
854
    {
 
855
        int[] linep = { 0 };
 
856
        String filename = getSourcePositionFromStack(linep);
 
857
        Writer sw = new StringWriter();
 
858
        PrintWriter pw = new PrintWriter(sw);
 
859
        pw.println(message);
 
860
        t.printStackTrace(pw);
 
861
        pw.flush();
 
862
        Context.reportWarning(sw.toString(), filename, linep[0], null, 0);
 
863
    }
 
864
 
 
865
    /**
 
866
     * Report an error using the error reporter for the current thread.
 
867
     *
 
868
     * @param message the error message to report
 
869
     * @param sourceName a string describing the source, such as a filename
 
870
     * @param lineno the starting line number
 
871
     * @param lineSource the text of the line (may be null)
 
872
     * @param lineOffset the offset into lineSource where problem was detected
 
873
     * @see org.mozilla.javascript.ErrorReporter
 
874
     */
 
875
    public static void reportError(String message, String sourceName,
 
876
                                   int lineno, String lineSource,
 
877
                                   int lineOffset)
 
878
    {
 
879
        Context cx = getCurrentContext();
 
880
        if (cx != null) {
 
881
            cx.getErrorReporter().error(message, sourceName, lineno,
 
882
                                        lineSource, lineOffset);
 
883
        } else {
 
884
            throw new EvaluatorException(message, sourceName, lineno,
 
885
                                         lineSource, lineOffset);
 
886
        }
 
887
    }
 
888
 
 
889
    /**
 
890
     * Report an error using the error reporter for the current thread.
 
891
     *
 
892
     * @param message the error message to report
 
893
     * @see org.mozilla.javascript.ErrorReporter
 
894
     */
 
895
    public static void reportError(String message)
 
896
    {
 
897
        int[] linep = { 0 };
 
898
        String filename = getSourcePositionFromStack(linep);
 
899
        Context.reportError(message, filename, linep[0], null, 0);
 
900
    }
 
901
 
 
902
    /**
 
903
     * Report a runtime error using the error reporter for the current thread.
 
904
     *
 
905
     * @param message the error message to report
 
906
     * @param sourceName a string describing the source, such as a filename
 
907
     * @param lineno the starting line number
 
908
     * @param lineSource the text of the line (may be null)
 
909
     * @param lineOffset the offset into lineSource where problem was detected
 
910
     * @return a runtime exception that will be thrown to terminate the
 
911
     *         execution of the script
 
912
     * @see org.mozilla.javascript.ErrorReporter
 
913
     */
 
914
    public static EvaluatorException reportRuntimeError(String message,
 
915
                                                        String sourceName,
 
916
                                                        int lineno,
 
917
                                                        String lineSource,
 
918
                                                        int lineOffset)
 
919
    {
 
920
        Context cx = getCurrentContext();
 
921
        if (cx != null) {
 
922
            return cx.getErrorReporter().
 
923
                            runtimeError(message, sourceName, lineno,
 
924
                                         lineSource, lineOffset);
 
925
        } else {
 
926
            throw new EvaluatorException(message, sourceName, lineno,
 
927
                                         lineSource, lineOffset);
 
928
        }
 
929
    }
 
930
 
 
931
    static EvaluatorException reportRuntimeError0(String messageId)
 
932
    {
 
933
        String msg = ScriptRuntime.getMessage0(messageId);
 
934
        return reportRuntimeError(msg);
 
935
    }
 
936
 
 
937
    static EvaluatorException reportRuntimeError1(String messageId,
 
938
                                                  Object arg1)
 
939
    {
 
940
        String msg = ScriptRuntime.getMessage1(messageId, arg1);
 
941
        return reportRuntimeError(msg);
 
942
    }
 
943
 
 
944
    static EvaluatorException reportRuntimeError2(String messageId,
 
945
                                                  Object arg1, Object arg2)
 
946
    {
 
947
        String msg = ScriptRuntime.getMessage2(messageId, arg1, arg2);
 
948
        return reportRuntimeError(msg);
 
949
    }
 
950
 
 
951
    static EvaluatorException reportRuntimeError3(String messageId,
 
952
                                                  Object arg1, Object arg2,
 
953
                                                  Object arg3)
 
954
    {
 
955
        String msg = ScriptRuntime.getMessage3(messageId, arg1, arg2, arg3);
 
956
        return reportRuntimeError(msg);
 
957
    }
 
958
 
 
959
    static EvaluatorException reportRuntimeError4(String messageId,
 
960
                                                  Object arg1, Object arg2,
 
961
                                                  Object arg3, Object arg4)
 
962
    {
 
963
        String msg
 
964
            = ScriptRuntime.getMessage4(messageId, arg1, arg2, arg3, arg4);
 
965
        return reportRuntimeError(msg);
 
966
    }
 
967
 
 
968
    /**
 
969
     * Report a runtime error using the error reporter for the current thread.
 
970
     *
 
971
     * @param message the error message to report
 
972
     * @see org.mozilla.javascript.ErrorReporter
 
973
     */
 
974
    public static EvaluatorException reportRuntimeError(String message)
 
975
    {
 
976
        int[] linep = { 0 };
 
977
        String filename = getSourcePositionFromStack(linep);
 
978
        return Context.reportRuntimeError(message, filename, linep[0], null, 0);
 
979
    }
 
980
 
 
981
    /**
 
982
     * Initialize the standard objects.
 
983
     *
 
984
     * Creates instances of the standard objects and their constructors
 
985
     * (Object, String, Number, Date, etc.), setting up 'scope' to act
 
986
     * as a global object as in ECMA 15.1.<p>
 
987
     *
 
988
     * This method must be called to initialize a scope before scripts
 
989
     * can be evaluated in that scope.<p>
 
990
     *
 
991
     * This method does not affect the Context it is called upon.
 
992
     *
 
993
     * @return the initialized scope
 
994
     */
 
995
    public final ScriptableObject initStandardObjects()
 
996
    {
 
997
        return initStandardObjects(null, false);
 
998
    }
 
999
 
 
1000
    /**
 
1001
     * Initialize the standard objects.
 
1002
     *
 
1003
     * Creates instances of the standard objects and their constructors
 
1004
     * (Object, String, Number, Date, etc.), setting up 'scope' to act
 
1005
     * as a global object as in ECMA 15.1.<p>
 
1006
     *
 
1007
     * This method must be called to initialize a scope before scripts
 
1008
     * can be evaluated in that scope.<p>
 
1009
     *
 
1010
     * This method does not affect the Context it is called upon.
 
1011
     *
 
1012
     * @param scope the scope to initialize, or null, in which case a new
 
1013
     *        object will be created to serve as the scope
 
1014
     * @return the initialized scope. The method returns the value of the scope
 
1015
     *         argument if it is not null or newly allocated scope object which
 
1016
     *         is an instance {@link ScriptableObject}.
 
1017
     */
 
1018
    public final Scriptable initStandardObjects(ScriptableObject scope)
 
1019
    {
 
1020
        return initStandardObjects(scope, false);
 
1021
    }
 
1022
 
 
1023
    /**
 
1024
     * Initialize the standard objects.
 
1025
     *
 
1026
     * Creates instances of the standard objects and their constructors
 
1027
     * (Object, String, Number, Date, etc.), setting up 'scope' to act
 
1028
     * as a global object as in ECMA 15.1.<p>
 
1029
     *
 
1030
     * This method must be called to initialize a scope before scripts
 
1031
     * can be evaluated in that scope.<p>
 
1032
     *
 
1033
     * This method does not affect the Context it is called upon.<p>
 
1034
     *
 
1035
     * This form of the method also allows for creating "sealed" standard
 
1036
     * objects. An object that is sealed cannot have properties added, changed,
 
1037
     * or removed. This is useful to create a "superglobal" that can be shared
 
1038
     * among several top-level objects. Note that sealing is not allowed in
 
1039
     * the current ECMA/ISO language specification, but is likely for
 
1040
     * the next version.
 
1041
     *
 
1042
     * @param scope the scope to initialize, or null, in which case a new
 
1043
     *        object will be created to serve as the scope
 
1044
     * @param sealed whether or not to create sealed standard objects that
 
1045
     *        cannot be modified.
 
1046
     * @return the initialized scope. The method returns the value of the scope
 
1047
     *         argument if it is not null or newly allocated scope object.
 
1048
     * @since 1.4R3
 
1049
     */
 
1050
    public ScriptableObject initStandardObjects(ScriptableObject scope,
 
1051
                                                boolean sealed)
 
1052
    {
 
1053
        return ScriptRuntime.initStandardObjects(this, scope, sealed);
 
1054
    }
 
1055
 
 
1056
    /**
 
1057
     * Get the singleton object that represents the JavaScript Undefined value.
 
1058
     */
 
1059
    public static Object getUndefinedValue()
 
1060
    {
 
1061
        return Undefined.instance;
 
1062
    }
 
1063
 
 
1064
    /**
 
1065
     * Evaluate a JavaScript source string.
 
1066
     *
 
1067
     * The provided source name and line number are used for error messages
 
1068
     * and for producing debug information.
 
1069
     *
 
1070
     * @param scope the scope to execute in
 
1071
     * @param source the JavaScript source
 
1072
     * @param sourceName a string describing the source, such as a filename
 
1073
     * @param lineno the starting line number
 
1074
     * @param securityDomain an arbitrary object that specifies security
 
1075
     *        information about the origin or owner of the script. For
 
1076
     *        implementations that don't care about security, this value
 
1077
     *        may be null.
 
1078
     * @return the result of evaluating the string
 
1079
     * @see org.mozilla.javascript.SecurityController
 
1080
     */
 
1081
    public final Object evaluateString(Scriptable scope, String source,
 
1082
                                       String sourceName, int lineno,
 
1083
                                       Object securityDomain)
 
1084
    {
 
1085
        Script script = compileString(source, sourceName, lineno,
 
1086
                                      securityDomain);
 
1087
        if (script != null) {
 
1088
            return script.exec(this, scope);
 
1089
        } else {
 
1090
            return null;
 
1091
        }
 
1092
    }
 
1093
 
 
1094
    /**
 
1095
     * Evaluate a reader as JavaScript source.
 
1096
     *
 
1097
     * All characters of the reader are consumed.
 
1098
     *
 
1099
     * @param scope the scope to execute in
 
1100
     * @param in the Reader to get JavaScript source from
 
1101
     * @param sourceName a string describing the source, such as a filename
 
1102
     * @param lineno the starting line number
 
1103
     * @param securityDomain an arbitrary object that specifies security
 
1104
     *        information about the origin or owner of the script. For
 
1105
     *        implementations that don't care about security, this value
 
1106
     *        may be null.
 
1107
     * @return the result of evaluating the source
 
1108
     *
 
1109
     * @exception IOException if an IOException was generated by the Reader
 
1110
     */
 
1111
    public final Object evaluateReader(Scriptable scope, Reader in,
 
1112
                                       String sourceName, int lineno,
 
1113
                                       Object securityDomain)
 
1114
        throws IOException
 
1115
    {
 
1116
        Script script = compileReader(scope, in, sourceName, lineno,
 
1117
                                      securityDomain);
 
1118
        if (script != null) {
 
1119
            return script.exec(this, scope);
 
1120
        } else {
 
1121
            return null;
 
1122
        }
 
1123
    }
 
1124
 
 
1125
    /**
 
1126
     * Check whether a string is ready to be compiled.
 
1127
     * <p>
 
1128
     * stringIsCompilableUnit is intended to support interactive compilation of
 
1129
     * javascript.  If compiling the string would result in an error
 
1130
     * that might be fixed by appending more source, this method
 
1131
     * returns false.  In every other case, it returns true.
 
1132
     * <p>
 
1133
     * Interactive shells may accumulate source lines, using this
 
1134
     * method after each new line is appended to check whether the
 
1135
     * statement being entered is complete.
 
1136
     *
 
1137
     * @param source the source buffer to check
 
1138
     * @return whether the source is ready for compilation
 
1139
     * @since 1.4 Release 2
 
1140
     */
 
1141
    public final boolean stringIsCompilableUnit(String source)
 
1142
    {
 
1143
        boolean errorseen = false;
 
1144
        CompilerEnvirons compilerEnv = new CompilerEnvirons();
 
1145
        compilerEnv.initFromContext(this);
 
1146
        // no source name or source text manager, because we're just
 
1147
        // going to throw away the result.
 
1148
        compilerEnv.setGeneratingSource(false);
 
1149
        /*APPJET*/
 
1150
        Parser p = InformativeParser.makeParser(compilerEnv,
 
1151
                                                DefaultErrorReporter.instance);
 
1152
        try {
 
1153
            p.parse(source, null, 1);
 
1154
        } catch (EvaluatorException ee) {
 
1155
            errorseen = true;
 
1156
        }
 
1157
        // Return false only if an error occurred as a result of reading past
 
1158
        // the end of the file, i.e. if the source could be fixed by
 
1159
        // appending more source.
 
1160
        if (errorseen && p.eof())
 
1161
            return false;
 
1162
        else
 
1163
            return true;
 
1164
    }
 
1165
 
 
1166
    /**
 
1167
     * @deprecated
 
1168
     * @see #compileReader(Reader in, String sourceName, int lineno,
 
1169
     *                     Object securityDomain)
 
1170
     */
 
1171
    public final Script compileReader(Scriptable scope, Reader in,
 
1172
                                      String sourceName, int lineno,
 
1173
                                      Object securityDomain)
 
1174
        throws IOException
 
1175
    {
 
1176
        return compileReader(in, sourceName, lineno, securityDomain);
 
1177
    }
 
1178
 
 
1179
    /**
 
1180
     * Compiles the source in the given reader.
 
1181
     * <p>
 
1182
     * Returns a script that may later be executed.
 
1183
     * Will consume all the source in the reader.
 
1184
     *
 
1185
     * @param in the input reader
 
1186
     * @param sourceName a string describing the source, such as a filename
 
1187
     * @param lineno the starting line number for reporting errors
 
1188
     * @param securityDomain an arbitrary object that specifies security
 
1189
     *        information about the origin or owner of the script. For
 
1190
     *        implementations that don't care about security, this value
 
1191
     *        may be null.
 
1192
     * @return a script that may later be executed
 
1193
     * @exception IOException if an IOException was generated by the Reader
 
1194
     * @see org.mozilla.javascript.Script
 
1195
     */
 
1196
    public final Script compileReader(Reader in, String sourceName,
 
1197
                                      int lineno, Object securityDomain)
 
1198
        throws IOException
 
1199
    {
 
1200
        if (lineno < 0) {
 
1201
            // For compatibility IllegalArgumentException can not be thrown here
 
1202
            lineno = 0;
 
1203
        }
 
1204
        return (Script) compileImpl(null, in, null, sourceName, lineno,
 
1205
                                    securityDomain, false, null, null);
 
1206
    }
 
1207
 
 
1208
    /**
 
1209
     * Compiles the source in the given string.
 
1210
     * <p>
 
1211
     * Returns a script that may later be executed.
 
1212
     *
 
1213
     * @param source the source string
 
1214
     * @param sourceName a string describing the source, such as a filename
 
1215
     * @param lineno the starting line number for reporting errors
 
1216
     * @param securityDomain an arbitrary object that specifies security
 
1217
     *        information about the origin or owner of the script. For
 
1218
     *        implementations that don't care about security, this value
 
1219
     *        may be null.
 
1220
     * @return a script that may later be executed
 
1221
     * @see org.mozilla.javascript.Script
 
1222
     */
 
1223
    public final Script compileString(String source,
 
1224
                                      String sourceName, int lineno,
 
1225
                                      Object securityDomain)
 
1226
    {
 
1227
        if (lineno < 0) {
 
1228
            // For compatibility IllegalArgumentException can not be thrown here
 
1229
            lineno = 0;
 
1230
        }
 
1231
        return compileString(source, null, null, sourceName, lineno,
 
1232
                             securityDomain);
 
1233
    }
 
1234
 
 
1235
    final Script compileString(String source,
 
1236
                               Evaluator compiler,
 
1237
                               ErrorReporter compilationErrorReporter,
 
1238
                               String sourceName, int lineno,
 
1239
                               Object securityDomain)
 
1240
    {
 
1241
        try {
 
1242
            return (Script) compileImpl(null, null, source, sourceName, lineno,
 
1243
                                        securityDomain, false,
 
1244
                                        compiler, compilationErrorReporter);
 
1245
        } catch (IOException ex) {
 
1246
            // Should not happen when dealing with source as string
 
1247
            throw new RuntimeException();
 
1248
        }
 
1249
    }
 
1250
 
 
1251
    /**
 
1252
     * Compile a JavaScript function.
 
1253
     * <p>
 
1254
     * The function source must be a function definition as defined by
 
1255
     * ECMA (e.g., "function f(a) { return a; }").
 
1256
     *
 
1257
     * @param scope the scope to compile relative to
 
1258
     * @param source the function definition source
 
1259
     * @param sourceName a string describing the source, such as a filename
 
1260
     * @param lineno the starting line number
 
1261
     * @param securityDomain an arbitrary object that specifies security
 
1262
     *        information about the origin or owner of the script. For
 
1263
     *        implementations that don't care about security, this value
 
1264
     *        may be null.
 
1265
     * @return a Function that may later be called
 
1266
     * @see org.mozilla.javascript.Function
 
1267
     */
 
1268
    public final Function compileFunction(Scriptable scope, String source,
 
1269
                                          String sourceName, int lineno,
 
1270
                                          Object securityDomain)
 
1271
    {
 
1272
        return compileFunction(scope, source, null, null, sourceName, lineno,
 
1273
                               securityDomain);
 
1274
    }
 
1275
 
 
1276
    final Function compileFunction(Scriptable scope, String source,
 
1277
                                   Evaluator compiler,
 
1278
                                   ErrorReporter compilationErrorReporter,
 
1279
                                   String sourceName, int lineno,
 
1280
                                   Object securityDomain)
 
1281
    {
 
1282
        try {
 
1283
            return (Function) compileImpl(scope, null, source, sourceName,
 
1284
                                          lineno, securityDomain, true,
 
1285
                                          compiler, compilationErrorReporter);
 
1286
        }
 
1287
        catch (IOException ioe) {
 
1288
            // Should never happen because we just made the reader
 
1289
            // from a String
 
1290
            throw new RuntimeException();
 
1291
        }
 
1292
    }
 
1293
 
 
1294
    /**
 
1295
     * Decompile the script.
 
1296
     * <p>
 
1297
     * The canonical source of the script is returned.
 
1298
     *
 
1299
     * @param script the script to decompile
 
1300
     * @param indent the number of spaces to indent the result
 
1301
     * @return a string representing the script source
 
1302
     */
 
1303
    public final String decompileScript(Script script, int indent)
 
1304
    {
 
1305
        NativeFunction scriptImpl = (NativeFunction) script;
 
1306
        return scriptImpl.decompile(indent, 0);
 
1307
    }
 
1308
 
 
1309
    /**
 
1310
     * Decompile a JavaScript Function.
 
1311
     * <p>
 
1312
     * Decompiles a previously compiled JavaScript function object to
 
1313
     * canonical source.
 
1314
     * <p>
 
1315
     * Returns function body of '[native code]' if no decompilation
 
1316
     * information is available.
 
1317
     *
 
1318
     * @param fun the JavaScript function to decompile
 
1319
     * @param indent the number of spaces to indent the result
 
1320
     * @return a string representing the function source
 
1321
     */
 
1322
    public final String decompileFunction(Function fun, int indent)
 
1323
    {
 
1324
        if (fun instanceof BaseFunction)
 
1325
            return ((BaseFunction)fun).decompile(indent, 0);
 
1326
        else
 
1327
            return "function " + fun.getClassName() +
 
1328
                   "() {\n\t[native code]\n}\n";
 
1329
    }
 
1330
 
 
1331
    /**
 
1332
     * Decompile the body of a JavaScript Function.
 
1333
     * <p>
 
1334
     * Decompiles the body a previously compiled JavaScript Function
 
1335
     * object to canonical source, omitting the function header and
 
1336
     * trailing brace.
 
1337
     *
 
1338
     * Returns '[native code]' if no decompilation information is available.
 
1339
     *
 
1340
     * @param fun the JavaScript function to decompile
 
1341
     * @param indent the number of spaces to indent the result
 
1342
     * @return a string representing the function body source.
 
1343
     */
 
1344
    public final String decompileFunctionBody(Function fun, int indent)
 
1345
    {
 
1346
        if (fun instanceof BaseFunction) {
 
1347
            BaseFunction bf = (BaseFunction)fun;
 
1348
            return bf.decompile(indent, Decompiler.ONLY_BODY_FLAG);
 
1349
        }
 
1350
        // ALERT: not sure what the right response here is.
 
1351
        return "[native code]\n";
 
1352
    }
 
1353
 
 
1354
    /**
 
1355
     * Create a new JavaScript object.
 
1356
     *
 
1357
     * Equivalent to evaluating "new Object()".
 
1358
     * @param scope the scope to search for the constructor and to evaluate
 
1359
     *              against
 
1360
     * @return the new object
 
1361
     */
 
1362
    public final Scriptable newObject(Scriptable scope)
 
1363
    {
 
1364
        return newObject(scope, "Object", ScriptRuntime.emptyArgs);
 
1365
    }
 
1366
 
 
1367
    /**
 
1368
     * Create a new JavaScript object by executing the named constructor.
 
1369
     *
 
1370
     * The call <code>newObject(scope, "Foo")</code> is equivalent to
 
1371
     * evaluating "new Foo()".
 
1372
     *
 
1373
     * @param scope the scope to search for the constructor and to evaluate against
 
1374
     * @param constructorName the name of the constructor to call
 
1375
     * @return the new object
 
1376
     */
 
1377
    public final Scriptable newObject(Scriptable scope, String constructorName)
 
1378
    {
 
1379
        return newObject(scope, constructorName, ScriptRuntime.emptyArgs);
 
1380
    }
 
1381
 
 
1382
    /**
 
1383
     * Creates a new JavaScript object by executing the named constructor.
 
1384
     *
 
1385
     * Searches <code>scope</code> for the named constructor, calls it with
 
1386
     * the given arguments, and returns the result.<p>
 
1387
     *
 
1388
     * The code
 
1389
     * <pre>
 
1390
     * Object[] args = { "a", "b" };
 
1391
     * newObject(scope, "Foo", args)</pre>
 
1392
     * is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo
 
1393
     * constructor has been defined in <code>scope</code>.
 
1394
     *
 
1395
     * @param scope The scope to search for the constructor and to evaluate
 
1396
     *              against
 
1397
     * @param constructorName the name of the constructor to call
 
1398
     * @param args the array of arguments for the constructor
 
1399
     * @return the new object
 
1400
     */
 
1401
    public final Scriptable newObject(Scriptable scope, String constructorName,
 
1402
                                      Object[] args)
 
1403
    {
 
1404
        scope = ScriptableObject.getTopLevelScope(scope);
 
1405
        Function ctor = ScriptRuntime.getExistingCtor(this, scope,
 
1406
                                                      constructorName);
 
1407
        if (args == null) { args = ScriptRuntime.emptyArgs; }
 
1408
        return ctor.construct(this, scope, args);
 
1409
    }
 
1410
 
 
1411
    /**
 
1412
     * Create an array with a specified initial length.
 
1413
     * <p>
 
1414
     * @param scope the scope to create the object in
 
1415
     * @param length the initial length (JavaScript arrays may have
 
1416
     *               additional properties added dynamically).
 
1417
     * @return the new array object
 
1418
     */
 
1419
    public final Scriptable newArray(Scriptable scope, int length)
 
1420
    {
 
1421
        NativeArray result = new NativeArray(length);
 
1422
        ScriptRuntime.setObjectProtoAndParent(result, scope);
 
1423
        return result;
 
1424
    }
 
1425
 
 
1426
    /**
 
1427
     * Create an array with a set of initial elements.
 
1428
     *
 
1429
     * @param scope the scope to create the object in.
 
1430
     * @param elements the initial elements. Each object in this array
 
1431
     *                 must be an acceptable JavaScript type and type
 
1432
     *                 of array should be exactly Object[], not
 
1433
     *                 SomeObjectSubclass[].
 
1434
     * @return the new array object.
 
1435
     */
 
1436
    public final Scriptable newArray(Scriptable scope, Object[] elements)
 
1437
    {
 
1438
        if (elements.getClass().getComponentType() != ScriptRuntime.ObjectClass)
 
1439
            throw new IllegalArgumentException();
 
1440
        NativeArray result = new NativeArray(elements);
 
1441
        ScriptRuntime.setObjectProtoAndParent(result, scope);
 
1442
        return result;
 
1443
    }
 
1444
 
 
1445
    /**
 
1446
     * Get the elements of a JavaScript array.
 
1447
     * <p>
 
1448
     * If the object defines a length property convertible to double number,
 
1449
     * then the number is converted Uint32 value as defined in Ecma 9.6
 
1450
     * and Java array of that size is allocated.
 
1451
     * The array is initialized with the values obtained by
 
1452
     * calling get() on object for each value of i in [0,length-1]. If
 
1453
     * there is not a defined value for a property the Undefined value
 
1454
     * is used to initialize the corresponding element in the array. The
 
1455
     * Java array is then returned.
 
1456
     * If the object doesn't define a length property or it is not a number,
 
1457
     * empty array is returned.
 
1458
     * @param object the JavaScript array or array-like object
 
1459
     * @return a Java array of objects
 
1460
     * @since 1.4 release 2
 
1461
     */
 
1462
    public final Object[] getElements(Scriptable object)
 
1463
    {
 
1464
        return ScriptRuntime.getArrayElements(object);
 
1465
    }
 
1466
 
 
1467
    /**
 
1468
     * Convert the value to a JavaScript boolean value.
 
1469
     * <p>
 
1470
     * See ECMA 9.2.
 
1471
     *
 
1472
     * @param value a JavaScript value
 
1473
     * @return the corresponding boolean value converted using
 
1474
     *         the ECMA rules
 
1475
     */
 
1476
    public static boolean toBoolean(Object value)
 
1477
    {
 
1478
        return ScriptRuntime.toBoolean(value);
 
1479
    }
 
1480
 
 
1481
    /**
 
1482
     * Convert the value to a JavaScript Number value.
 
1483
     * <p>
 
1484
     * Returns a Java double for the JavaScript Number.
 
1485
     * <p>
 
1486
     * See ECMA 9.3.
 
1487
     *
 
1488
     * @param value a JavaScript value
 
1489
     * @return the corresponding double value converted using
 
1490
     *         the ECMA rules
 
1491
     */
 
1492
    public static double toNumber(Object value)
 
1493
    {
 
1494
        return ScriptRuntime.toNumber(value);
 
1495
    }
 
1496
 
 
1497
    /**
 
1498
     * Convert the value to a JavaScript String value.
 
1499
     * <p>
 
1500
     * See ECMA 9.8.
 
1501
     * <p>
 
1502
     * @param value a JavaScript value
 
1503
     * @return the corresponding String value converted using
 
1504
     *         the ECMA rules
 
1505
     */
 
1506
    public static String toString(Object value)
 
1507
    {
 
1508
        return ScriptRuntime.toString(value);
 
1509
    }
 
1510
 
 
1511
    /**
 
1512
     * Convert the value to an JavaScript object value.
 
1513
     * <p>
 
1514
     * Note that a scope must be provided to look up the constructors
 
1515
     * for Number, Boolean, and String.
 
1516
     * <p>
 
1517
     * See ECMA 9.9.
 
1518
     * <p>
 
1519
     * Additionally, arbitrary Java objects and classes will be
 
1520
     * wrapped in a Scriptable object with its Java fields and methods
 
1521
     * reflected as JavaScript properties of the object.
 
1522
     *
 
1523
     * @param value any Java object
 
1524
     * @param scope global scope containing constructors for Number,
 
1525
     *              Boolean, and String
 
1526
     * @return new JavaScript object
 
1527
     */
 
1528
    public static Scriptable toObject(Object value, Scriptable scope)
 
1529
    {
 
1530
        return ScriptRuntime.toObject(scope, value);
 
1531
    }
 
1532
 
 
1533
    /**
 
1534
     * @deprecated
 
1535
     * @see #toObject(Object, Scriptable)
 
1536
     */
 
1537
    public static Scriptable toObject(Object value, Scriptable scope,
 
1538
                                      Class staticType)
 
1539
    {
 
1540
        return ScriptRuntime.toObject(scope, value);
 
1541
    }
 
1542
 
 
1543
    /**
 
1544
     * Convenient method to convert java value to its closest representation
 
1545
     * in JavaScript.
 
1546
     * <p>
 
1547
     * If value is an instance of String, Number, Boolean, Function or
 
1548
     * Scriptable, it is returned as it and will be treated as the corresponding
 
1549
     * JavaScript type of string, number, boolean, function and object.
 
1550
     * <p>
 
1551
     * Note that for Number instances during any arithmetic operation in
 
1552
     * JavaScript the engine will always use the result of
 
1553
     * <tt>Number.doubleValue()</tt> resulting in a precision loss if
 
1554
     * the number can not fit into double.
 
1555
     * <p>
 
1556
     * If value is an instance of Character, it will be converted to string of
 
1557
     * length 1 and its JavaScript type will be string.
 
1558
     * <p>
 
1559
     * The rest of values will be wrapped as LiveConnect objects
 
1560
     * by calling {@link WrapFactory#wrap(Context cx, Scriptable scope,
 
1561
     * Object obj, Class staticType)} as in:
 
1562
     * <pre>
 
1563
     *    Context cx = Context.getCurrentContext();
 
1564
     *    return cx.getWrapFactory().wrap(cx, scope, value, null);
 
1565
     * </pre>
 
1566
     *
 
1567
     * @param value any Java object
 
1568
     * @param scope top scope object
 
1569
     * @return value suitable to pass to any API that takes JavaScript values.
 
1570
     */
 
1571
    public static Object javaToJS(Object value, Scriptable scope)
 
1572
    {
 
1573
        if (value instanceof String || value instanceof Number
 
1574
            || value instanceof Boolean || value instanceof Scriptable)
 
1575
        {
 
1576
            return value;
 
1577
        } else if (value instanceof Character) {
 
1578
            return String.valueOf(((Character)value).charValue());
 
1579
        } else {
 
1580
            Context cx = Context.getContext();
 
1581
            return cx.getWrapFactory().wrap(cx, scope, value, null);
 
1582
        }
 
1583
    }
 
1584
 
 
1585
    /**
 
1586
     * Convert a JavaScript value into the desired type.
 
1587
     * Uses the semantics defined with LiveConnect3 and throws an
 
1588
     * Illegal argument exception if the conversion cannot be performed.
 
1589
     * @param value the JavaScript value to convert
 
1590
     * @param desiredType the Java type to convert to. Primitive Java
 
1591
     *        types are represented using the TYPE fields in the corresponding
 
1592
     *        wrapper class in java.lang.
 
1593
     * @return the converted value
 
1594
     * @throws EvaluatorException if the conversion cannot be performed
 
1595
     */
 
1596
    public static Object jsToJava(Object value, Class desiredType)
 
1597
        throws EvaluatorException
 
1598
    {
 
1599
        return NativeJavaObject.coerceTypeImpl(desiredType, value);
 
1600
    }
 
1601
 
 
1602
    /**
 
1603
     * @deprecated
 
1604
     * @see #jsToJava(Object, Class)
 
1605
     * @throws IllegalArgumentException if the conversion cannot be performed.
 
1606
     *         Note that {@link #jsToJava(Object, Class)} throws
 
1607
     *         {@link EvaluatorException} instead.
 
1608
     */
 
1609
    public static Object toType(Object value, Class desiredType)
 
1610
        throws IllegalArgumentException
 
1611
    {
 
1612
        try {
 
1613
            return jsToJava(value, desiredType);
 
1614
        } catch (EvaluatorException ex) {
 
1615
            IllegalArgumentException
 
1616
                ex2 = new IllegalArgumentException(ex.getMessage());
 
1617
            Kit.initCause(ex2, ex);
 
1618
            throw ex2;
 
1619
        }
 
1620
    }
 
1621
 
 
1622
    /**
 
1623
     * Rethrow the exception wrapping it as the script runtime exception.
 
1624
     * Unless the exception is instance of {@link EcmaError} or
 
1625
     * {@link EvaluatorException} it will be wrapped as
 
1626
     * {@link WrappedException}, a subclass of {@link EvaluatorException}.
 
1627
     * The resulting exception object always contains
 
1628
     * source name and line number of script that triggered exception.
 
1629
     * <p>
 
1630
     * This method always throws an exception, its return value is provided
 
1631
     * only for convenience to allow a usage like:
 
1632
     * <pre>
 
1633
     * throw Context.throwAsScriptRuntimeEx(ex);
 
1634
     * </pre>
 
1635
     * to indicate that code after the method is unreachable.
 
1636
     * @throws EvaluatorException
 
1637
     * @throws EcmaError
 
1638
     */
 
1639
    public static RuntimeException throwAsScriptRuntimeEx(Throwable e)
 
1640
    {
 
1641
        while ((e instanceof InvocationTargetException)) {
 
1642
            e = ((InvocationTargetException) e).getTargetException();
 
1643
        }
 
1644
        // special handling of Error so scripts would not catch them
 
1645
        if (e instanceof Error) {
 
1646
            Context cx = getContext();
 
1647
            if (cx == null ||
 
1648
                !cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS))
 
1649
            {
 
1650
                throw (Error)e;
 
1651
            }
 
1652
        }
 
1653
        if (e instanceof RhinoException) {
 
1654
            throw (RhinoException)e;
 
1655
        }
 
1656
        throw new WrappedException(e);
 
1657
    }
 
1658
 
 
1659
    /**
 
1660
     * Tell whether debug information is being generated.
 
1661
     * @since 1.3
 
1662
     */
 
1663
    public final boolean isGeneratingDebug()
 
1664
    {
 
1665
        return generatingDebug;
 
1666
    }
 
1667
 
 
1668
    /**
 
1669
     * Specify whether or not debug information should be generated.
 
1670
     * <p>
 
1671
     * Setting the generation of debug information on will set the
 
1672
     * optimization level to zero.
 
1673
     * @since 1.3
 
1674
     */
 
1675
    public final void setGeneratingDebug(boolean generatingDebug)
 
1676
    {
 
1677
        if (sealed) onSealedMutation();
 
1678
        generatingDebugChanged = true;
 
1679
        if (generatingDebug && getOptimizationLevel() > 0)
 
1680
            setOptimizationLevel(0);
 
1681
        this.generatingDebug = generatingDebug;
 
1682
    }
 
1683
 
 
1684
    /**
 
1685
     * Tell whether source information is being generated.
 
1686
     * @since 1.3
 
1687
     */
 
1688
    public final boolean isGeneratingSource()
 
1689
    {
 
1690
        return generatingSource;
 
1691
    }
 
1692
 
 
1693
    /**
 
1694
     * Specify whether or not source information should be generated.
 
1695
     * <p>
 
1696
     * Without source information, evaluating the "toString" method
 
1697
     * on JavaScript functions produces only "[native code]" for
 
1698
     * the body of the function.
 
1699
     * Note that code generated without source is not fully ECMA
 
1700
     * conformant.
 
1701
     * @since 1.3
 
1702
     */
 
1703
    public final void setGeneratingSource(boolean generatingSource)
 
1704
    {
 
1705
        if (sealed) onSealedMutation();
 
1706
        this.generatingSource = generatingSource;
 
1707
    }
 
1708
 
 
1709
    /**
 
1710
     * Get the current optimization level.
 
1711
     * <p>
 
1712
     * The optimization level is expressed as an integer between -1 and
 
1713
     * 9.
 
1714
     * @since 1.3
 
1715
     *
 
1716
     */
 
1717
    public final int getOptimizationLevel()
 
1718
    {
 
1719
        return optimizationLevel;
 
1720
    }
 
1721
    
 
1722
    /**
 
1723
     * Set the current optimization level.
 
1724
     * <p>
 
1725
     * The optimization level is expected to be an integer between -1 and
 
1726
     * 9. Any negative values will be interpreted as -1, and any values
 
1727
     * greater than 9 will be interpreted as 9.
 
1728
     * An optimization level of -1 indicates that interpretive mode will
 
1729
     * always be used. Levels 0 through 9 indicate that class files may
 
1730
     * be generated. Higher optimization levels trade off compile time
 
1731
     * performance for runtime performance.
 
1732
     * The optimizer level can't be set greater than -1 if the optimizer
 
1733
     * package doesn't exist at run time.
 
1734
     * @param optimizationLevel an integer indicating the level of
 
1735
     *        optimization to perform
 
1736
     * @since 1.3
 
1737
     *
 
1738
     */
 
1739
    public final void setOptimizationLevel(int optimizationLevel)
 
1740
    {
 
1741
        if (sealed) onSealedMutation();
 
1742
        if (optimizationLevel == -2) {
 
1743
            // To be compatible with Cocoon fork
 
1744
            optimizationLevel = -1;
 
1745
        }
 
1746
        checkOptimizationLevel(optimizationLevel);
 
1747
        if (codegenClass == null)
 
1748
            optimizationLevel = -1;
 
1749
        this.optimizationLevel = optimizationLevel;
 
1750
    }
 
1751
 
 
1752
    public static boolean isValidOptimizationLevel(int optimizationLevel)
 
1753
    {
 
1754
        return -1 <= optimizationLevel && optimizationLevel <= 9;
 
1755
    }
 
1756
 
 
1757
    public static void checkOptimizationLevel(int optimizationLevel)
 
1758
    {
 
1759
        if (isValidOptimizationLevel(optimizationLevel)) {
 
1760
            return;
 
1761
        }
 
1762
        throw new IllegalArgumentException(
 
1763
            "Optimization level outside [-1..9]: "+optimizationLevel);
 
1764
    }
 
1765
 
 
1766
    /**
 
1767
     * Returns the maximum stack depth (in terms of number of call frames) 
 
1768
     * allowed in a single invocation of interpreter. If the set depth would be
 
1769
     * exceeded, the interpreter will throw an EvaluatorException in the script.
 
1770
     * Defaults to Integer.MAX_VALUE. The setting only has effect for 
 
1771
     * interpreted functions (those compiled with optimization level set to -1).
 
1772
     * As the interpreter doesn't use the Java stack but rather manages its own
 
1773
     * stack in the heap memory, a runaway recursion in interpreted code would 
 
1774
     * eventually consume all available memory and cause OutOfMemoryError 
 
1775
     * instead of a StackOverflowError limited to only a single thread. This
 
1776
     * setting helps prevent such situations.
 
1777
     *  
 
1778
     * @return The current maximum interpreter stack depth.
 
1779
     */
 
1780
    public final int getMaximumInterpreterStackDepth()
 
1781
    {
 
1782
        return maximumInterpreterStackDepth;
 
1783
    }
 
1784
 
 
1785
    /**
 
1786
     * Sets the maximum stack depth (in terms of number of call frames) 
 
1787
     * allowed in a single invocation of interpreter. If the set depth would be
 
1788
     * exceeded, the interpreter will throw an EvaluatorException in the script.
 
1789
     * Defaults to Integer.MAX_VALUE. The setting only has effect for 
 
1790
     * interpreted functions (those compiled with optimization level set to -1).
 
1791
     * As the interpreter doesn't use the Java stack but rather manages its own
 
1792
     * stack in the heap memory, a runaway recursion in interpreted code would 
 
1793
     * eventually consume all available memory and cause OutOfMemoryError 
 
1794
     * instead of a StackOverflowError limited to only a single thread. This
 
1795
     * setting helps prevent such situations.
 
1796
     * 
 
1797
     * @param max the new maximum interpreter stack depth
 
1798
     * @throws IllegalStateException if this context's optimization level is not
 
1799
     * -1
 
1800
     * @throws IllegalArgumentException if the new depth is not at least 1 
 
1801
     */
 
1802
    public final void setMaximumInterpreterStackDepth(int max)
 
1803
    {
 
1804
        if(sealed) onSealedMutation();
 
1805
        if(optimizationLevel != -1) {
 
1806
            throw new IllegalStateException("Cannot set maximumInterpreterStackDepth when optimizationLevel != -1");
 
1807
        }
 
1808
        if(max < 1) {
 
1809
            throw new IllegalArgumentException("Cannot set maximumInterpreterStackDepth to less than 1");
 
1810
        }
 
1811
        maximumInterpreterStackDepth = max;
 
1812
    }
 
1813
    
 
1814
    /**
 
1815
     * Set the security controller for this context.
 
1816
     * <p> SecurityController may only be set if it is currently null
 
1817
     * and {@link SecurityController#hasGlobal()} is <tt>false</tt>.
 
1818
     * Otherwise a SecurityException is thrown.
 
1819
     * @param controller a SecurityController object
 
1820
     * @throws SecurityException if there is already a SecurityController
 
1821
     *         object for this Context or globally installed.
 
1822
     * @see SecurityController#initGlobal(SecurityController controller)
 
1823
     * @see SecurityController#hasGlobal()
 
1824
     */
 
1825
    public final void setSecurityController(SecurityController controller)
 
1826
    {
 
1827
        if (sealed) onSealedMutation();
 
1828
        if (controller == null) throw new IllegalArgumentException();
 
1829
        if (securityController != null) {
 
1830
            throw new SecurityException("Can not overwrite existing SecurityController object");
 
1831
        }
 
1832
        if (SecurityController.hasGlobal()) {
 
1833
            throw new SecurityException("Can not overwrite existing global SecurityController object");
 
1834
        }
 
1835
        securityController = controller;
 
1836
    }
 
1837
 
 
1838
    /**
 
1839
     * Set the LiveConnect access filter for this context.
 
1840
     * <p> {@link ClassShutter} may only be set if it is currently null.
 
1841
     * Otherwise a SecurityException is thrown.
 
1842
     * @param shutter a ClassShutter object
 
1843
     * @throws SecurityException if there is already a ClassShutter
 
1844
     *         object for this Context
 
1845
     */
 
1846
    public final void setClassShutter(ClassShutter shutter)
 
1847
    {
 
1848
        if (sealed) onSealedMutation();
 
1849
        if (shutter == null) throw new IllegalArgumentException();
 
1850
        if (classShutter != null) {
 
1851
            throw new SecurityException("Cannot overwrite existing " +
 
1852
                                        "ClassShutter object");
 
1853
        }
 
1854
        classShutter = shutter;
 
1855
    }
 
1856
 
 
1857
    final ClassShutter getClassShutter()
 
1858
    {
 
1859
        return classShutter;
 
1860
    }
 
1861
 
 
1862
    /**
 
1863
     * Get a value corresponding to a key.
 
1864
     * <p>
 
1865
     * Since the Context is associated with a thread it can be
 
1866
     * used to maintain values that can be later retrieved using
 
1867
     * the current thread.
 
1868
     * <p>
 
1869
     * Note that the values are maintained with the Context, so
 
1870
     * if the Context is disassociated from the thread the values
 
1871
     * cannot be retrieved. Also, if private data is to be maintained
 
1872
     * in this manner the key should be a java.lang.Object
 
1873
     * whose reference is not divulged to untrusted code.
 
1874
     * @param key the key used to lookup the value
 
1875
     * @return a value previously stored using putThreadLocal.
 
1876
     */
 
1877
    public final Object getThreadLocal(Object key)
 
1878
    {
 
1879
        if (hashtable == null)
 
1880
            return null;
 
1881
        return hashtable.get(key);
 
1882
    }
 
1883
 
 
1884
    /**
 
1885
     * Put a value that can later be retrieved using a given key.
 
1886
     * <p>
 
1887
     * @param key the key used to index the value
 
1888
     * @param value the value to save
 
1889
     */
 
1890
    public final void putThreadLocal(Object key, Object value)
 
1891
    {
 
1892
        if (sealed) onSealedMutation();
 
1893
        if (hashtable == null)
 
1894
            hashtable = new Hashtable();
 
1895
        hashtable.put(key, value);
 
1896
    }
 
1897
 
 
1898
    /**
 
1899
     * Remove values from thread-local storage.
 
1900
     * @param key the key for the entry to remove.
 
1901
     * @since 1.5 release 2
 
1902
     */
 
1903
    public final void removeThreadLocal(Object key)
 
1904
    {
 
1905
        if (sealed) onSealedMutation();
 
1906
        if (hashtable == null)
 
1907
            return;
 
1908
        hashtable.remove(key);
 
1909
    }
 
1910
 
 
1911
    /**
 
1912
     * @deprecated
 
1913
     * @see #FEATURE_DYNAMIC_SCOPE
 
1914
     * @see #hasFeature(int)
 
1915
     */
 
1916
    public final boolean hasCompileFunctionsWithDynamicScope()
 
1917
    {
 
1918
        return compileFunctionsWithDynamicScopeFlag;
 
1919
    }
 
1920
 
 
1921
    /**
 
1922
     * @deprecated
 
1923
     * @see #FEATURE_DYNAMIC_SCOPE
 
1924
     * @see #hasFeature(int)
 
1925
     */
 
1926
    public final void setCompileFunctionsWithDynamicScope(boolean flag)
 
1927
    {
 
1928
        if (sealed) onSealedMutation();
 
1929
        compileFunctionsWithDynamicScopeFlag = flag;
 
1930
    }
 
1931
 
 
1932
    /**
 
1933
     * @deprecated
 
1934
     * @see ClassCache#get(Scriptable)
 
1935
     * @see ClassCache#setCachingEnabled(boolean)
 
1936
     */
 
1937
    public static void setCachingEnabled(boolean cachingEnabled)
 
1938
    {
 
1939
    }
 
1940
 
 
1941
    /**
 
1942
     * Set a WrapFactory for this Context.
 
1943
     * <p>
 
1944
     * The WrapFactory allows custom object wrapping behavior for
 
1945
     * Java object manipulated with JavaScript.
 
1946
     * @see WrapFactory
 
1947
     * @since 1.5 Release 4
 
1948
     */
 
1949
    public final void setWrapFactory(WrapFactory wrapFactory)
 
1950
    {
 
1951
        if (sealed) onSealedMutation();
 
1952
        if (wrapFactory == null) throw new IllegalArgumentException();
 
1953
        this.wrapFactory = wrapFactory;
 
1954
    }
 
1955
 
 
1956
    /**
 
1957
     * Return the current WrapFactory, or null if none is defined.
 
1958
     * @see WrapFactory
 
1959
     * @since 1.5 Release 4
 
1960
     */
 
1961
    public final WrapFactory getWrapFactory()
 
1962
    {
 
1963
        if (wrapFactory == null) {
 
1964
            wrapFactory = new WrapFactory();
 
1965
        }
 
1966
        return wrapFactory;
 
1967
    }
 
1968
 
 
1969
    /**
 
1970
     * Return the current debugger.
 
1971
     * @return the debugger, or null if none is attached.
 
1972
     */
 
1973
    public final Debugger getDebugger()
 
1974
    {
 
1975
        return debugger;
 
1976
    }
 
1977
 
 
1978
    /**
 
1979
     * Return the debugger context data associated with current context.
 
1980
     * @return the debugger data, or null if debugger is not attached
 
1981
     */
 
1982
    public final Object getDebuggerContextData()
 
1983
    {
 
1984
        return debuggerData;
 
1985
    }
 
1986
 
 
1987
    /**
 
1988
     * Set the associated debugger.
 
1989
     * @param debugger the debugger to be used on callbacks from
 
1990
     * the engine.
 
1991
     * @param contextData arbitrary object that debugger can use to store
 
1992
     *        per Context data.
 
1993
     */
 
1994
    public final void setDebugger(Debugger debugger, Object contextData)
 
1995
    {
 
1996
        if (sealed) onSealedMutation();
 
1997
        this.debugger = debugger;
 
1998
        debuggerData = contextData;
 
1999
    }
 
2000
 
 
2001
    /**
 
2002
     * Return DebuggableScript instance if any associated with the script.
 
2003
     * If callable supports DebuggableScript implementation, the method
 
2004
     * returns it. Otherwise null is returned.
 
2005
     */
 
2006
    public static DebuggableScript getDebuggableView(Script script)
 
2007
    {
 
2008
        if (script instanceof NativeFunction) {
 
2009
            return ((NativeFunction)script).getDebuggableView();
 
2010
        }
 
2011
        return null;
 
2012
    }
 
2013
 
 
2014
    /**
 
2015
     * Controls certain aspects of script semantics.
 
2016
     * Should be overwritten to alter default behavior.
 
2017
     * <p>
 
2018
     * The default implementation calls
 
2019
     * {@link ContextFactory#hasFeature(Context cx, int featureIndex)}
 
2020
     * that allows to customize Context behavior without introducing
 
2021
     * Context subclasses.  {@link ContextFactory} documentation gives
 
2022
     * an example of hasFeature implementation.
 
2023
     *
 
2024
     * @param featureIndex feature index to check
 
2025
     * @return true if the <code>featureIndex</code> feature is turned on
 
2026
     * @see #FEATURE_NON_ECMA_GET_YEAR
 
2027
     * @see #FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME
 
2028
     * @see #FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER
 
2029
     * @see #FEATURE_TO_STRING_AS_SOURCE
 
2030
     * @see #FEATURE_PARENT_PROTO_PROPRTIES
 
2031
     * @see #FEATURE_E4X
 
2032
     * @see #FEATURE_DYNAMIC_SCOPE
 
2033
     * @see #FEATURE_STRICT_VARS
 
2034
     * @see #FEATURE_STRICT_EVAL
 
2035
     * @see #FEATURE_LOCATION_INFORMATION_IN_ERROR
 
2036
     * @see #FEATURE_STRICT_MODE
 
2037
     * @see #FEATURE_WARNING_AS_ERROR
 
2038
     * @see #FEATURE_ENHANCED_JAVA_ACCESS
 
2039
     */
 
2040
    public boolean hasFeature(int featureIndex)
 
2041
    {
 
2042
        ContextFactory f = getFactory();
 
2043
        return f.hasFeature(this, featureIndex);
 
2044
    }
 
2045
        
 
2046
        /**
 
2047
                Returns an object which specifies an E4X implementation to use within
 
2048
                this <code>Context</code>.  Note
 
2049
                that the XMLLib.Factory interface should be considered experimental.
 
2050
         
 
2051
                The default implementation uses the implementation provided by this
 
2052
                <code>Context</code>'s {@link ContextFactory}.
 
2053
         
 
2054
                @return An XMLLib.Factory.  Should not return <code>null</code> if
 
2055
                        {@link #FEATURE_E4X} is enabled.  See {@link #hasFeature}.
 
2056
         */
 
2057
        public XMLLib.Factory getE4xImplementationFactory() {
 
2058
                return getFactory().getE4xImplementationFactory();
 
2059
        }
 
2060
 
 
2061
    /**
 
2062
     * Get threshold of executed instructions counter that triggers call to
 
2063
     * <code>observeInstructionCount()</code>.
 
2064
     * When the threshold is zero, instruction counting is disabled,
 
2065
     * otherwise each time the run-time executes at least the threshold value
 
2066
     * of script instructions, <code>observeInstructionCount()</code> will
 
2067
     * be called.
 
2068
     */
 
2069
    public final int getInstructionObserverThreshold()
 
2070
    {
 
2071
        return instructionThreshold;
 
2072
    }
 
2073
 
 
2074
    /**
 
2075
     * Set threshold of executed instructions counter that triggers call to
 
2076
     * <code>observeInstructionCount()</code>.
 
2077
     * When the threshold is zero, instruction counting is disabled,
 
2078
     * otherwise each time the run-time executes at least the threshold value
 
2079
     * of script instructions, <code>observeInstructionCount()</code> will
 
2080
     * be called.<p/>
 
2081
     * Note that the meaning of "instruction" is not guaranteed to be
 
2082
     * consistent between compiled and interpretive modes: executing a given
 
2083
     * script or function in the different modes will result in different
 
2084
     * instruction counts against the threshold.
 
2085
     * {@link #setGenerateObserverCount} is called with true if
 
2086
     * <code>threshold</code> is greater than zero, false otherwise.
 
2087
     * @param threshold The instruction threshold
 
2088
     */
 
2089
    public final void setInstructionObserverThreshold(int threshold)
 
2090
    {
 
2091
        if (sealed) onSealedMutation();
 
2092
        if (threshold < 0) throw new IllegalArgumentException();
 
2093
        instructionThreshold = threshold;
 
2094
        setGenerateObserverCount(threshold > 0);
 
2095
    }
 
2096
 
 
2097
    /**
 
2098
     * Turn on or off generation of code with callbacks to
 
2099
     * track the count of executed instructions.
 
2100
     * Currently only affects JVM byte code generation: this slows down the
 
2101
     * generated code, but code generated without the callbacks will not
 
2102
     * be counted toward instruction thresholds. Rhino's interpretive
 
2103
     * mode does instruction counting without inserting callbacks, so
 
2104
     * there is no requirement to compile code differently.
 
2105
     * @param generateObserverCount if true, generated code will contain
 
2106
     * calls to accumulate an estimate of the instructions executed.
 
2107
     */
 
2108
    public void setGenerateObserverCount(boolean generateObserverCount) {
 
2109
        this.generateObserverCount = generateObserverCount;
 
2110
    }
 
2111
 
 
2112
    /**
 
2113
     * Allow application to monitor counter of executed script instructions
 
2114
     * in Context subclasses.
 
2115
     * Run-time calls this when instruction counting is enabled and the counter
 
2116
     * reaches limit set by <code>setInstructionObserverThreshold()</code>.
 
2117
     * The method is useful to observe long running scripts and if necessary
 
2118
     * to terminate them.
 
2119
     * <p>
 
2120
     * The instruction counting support is available only for interpreted
 
2121
     * scripts generated when the optimization level is set to -1.
 
2122
     * <p>
 
2123
     * The default implementation calls
 
2124
     * {@link ContextFactory#observeInstructionCount(Context cx,
 
2125
     *                                               int instructionCount)}
 
2126
     * that allows to customize Context behavior without introducing
 
2127
     * Context subclasses.
 
2128
     *
 
2129
     * @param instructionCount amount of script instruction executed since
 
2130
     * last call to <code>observeInstructionCount</code>
 
2131
     * @throws Error to terminate the script
 
2132
     * @see #setOptimizationLevel(int)
 
2133
     */
 
2134
    protected void observeInstructionCount(int instructionCount)
 
2135
    {
 
2136
        ContextFactory f = getFactory();
 
2137
        f.observeInstructionCount(this, instructionCount);
 
2138
    }
 
2139
 
 
2140
    /**
 
2141
     * Create class loader for generated classes.
 
2142
     * The method calls {@link ContextFactory#createClassLoader(ClassLoader)}
 
2143
     * using the result of {@link #getFactory()}.
 
2144
     */
 
2145
    public GeneratedClassLoader createClassLoader(ClassLoader parent)
 
2146
    {
 
2147
        ContextFactory f = getFactory();
 
2148
        return f.createClassLoader(parent);
 
2149
    }
 
2150
 
 
2151
    public final ClassLoader getApplicationClassLoader()
 
2152
    {
 
2153
        if (applicationClassLoader == null) {
 
2154
            ContextFactory f = getFactory();
 
2155
            ClassLoader loader = f.getApplicationClassLoader();
 
2156
            if (loader == null) {
 
2157
                ClassLoader threadLoader
 
2158
                    = VMBridge.instance.getCurrentThreadClassLoader();
 
2159
                if (threadLoader != null
 
2160
                    && Kit.testIfCanLoadRhinoClasses(threadLoader))
 
2161
                {
 
2162
                    // Thread.getContextClassLoader is not cached since
 
2163
                    // its caching prevents it from GC which may lead to
 
2164
                    // a memory leak and hides updates to
 
2165
                    // Thread.getContextClassLoader
 
2166
                    return threadLoader;
 
2167
                }
 
2168
                // Thread.getContextClassLoader can not load Rhino classes,
 
2169
                // try to use the loader of ContextFactory or Context
 
2170
                // subclasses.
 
2171
                Class fClass = f.getClass();
 
2172
                if (fClass != ScriptRuntime.ContextFactoryClass) {
 
2173
                    loader = fClass.getClassLoader();
 
2174
                } else {
 
2175
                    loader = getClass().getClassLoader();
 
2176
                }
 
2177
            }
 
2178
            applicationClassLoader = loader;
 
2179
        }
 
2180
        return applicationClassLoader;
 
2181
    }
 
2182
 
 
2183
    public final void setApplicationClassLoader(ClassLoader loader)
 
2184
    {
 
2185
        if (sealed) onSealedMutation();
 
2186
        if (loader == null) {
 
2187
            // restore default behaviour
 
2188
            applicationClassLoader = null;
 
2189
            return;
 
2190
        }
 
2191
        if (!Kit.testIfCanLoadRhinoClasses(loader)) {
 
2192
            throw new IllegalArgumentException(
 
2193
                "Loader can not resolve Rhino classes");
 
2194
        }
 
2195
        applicationClassLoader = loader;
 
2196
    }
 
2197
 
 
2198
    /********** end of API **********/
 
2199
 
 
2200
    /**
 
2201
     * Internal method that reports an error for missing calls to
 
2202
     * enter().
 
2203
     */
 
2204
    static Context getContext()
 
2205
    {
 
2206
        Context cx = getCurrentContext();
 
2207
        if (cx == null) {
 
2208
            throw new RuntimeException(
 
2209
                "No Context associated with current Thread");
 
2210
        }
 
2211
        return cx;
 
2212
    }
 
2213
 
 
2214
    private Object compileImpl(Scriptable scope,
 
2215
                               Reader sourceReader, String sourceString,
 
2216
                               String sourceName, int lineno,
 
2217
                               Object securityDomain, boolean returnFunction,
 
2218
                               Evaluator compiler,
 
2219
                               ErrorReporter compilationErrorReporter)
 
2220
        throws IOException
 
2221
    {
 
2222
        if(sourceName == null) {
 
2223
            sourceName = "unnamed script";
 
2224
        }
 
2225
        if (securityDomain != null && getSecurityController() == null) {
 
2226
            throw new IllegalArgumentException(
 
2227
                "securityDomain should be null if setSecurityController() was never called");
 
2228
        }
 
2229
 
 
2230
        // One of sourceReader or sourceString has to be null
 
2231
        if (!(sourceReader == null ^ sourceString == null)) Kit.codeBug();
 
2232
        // scope should be given if and only if compiling function
 
2233
        if (!(scope == null ^ returnFunction)) Kit.codeBug();
 
2234
 
 
2235
        CompilerEnvirons compilerEnv = new CompilerEnvirons();
 
2236
        compilerEnv.initFromContext(this);
 
2237
        if (compilationErrorReporter == null) {
 
2238
            compilationErrorReporter = compilerEnv.getErrorReporter();
 
2239
        }
 
2240
 
 
2241
        if (debugger != null) {
 
2242
            if (sourceReader != null) {
 
2243
                sourceString = Kit.readReader(sourceReader);
 
2244
                sourceReader = null;
 
2245
            }
 
2246
        }
 
2247
 
 
2248
        /*APPJET*/
 
2249
        Parser p = InformativeParser.makeParser(compilerEnv,
 
2250
                                                    compilationErrorReporter);
 
2251
        if (returnFunction) {
 
2252
            p.calledByCompileFunction = true;
 
2253
        }
 
2254
        ScriptOrFnNode tree;
 
2255
        if (sourceString != null) {
 
2256
            tree = p.parse(sourceString, sourceName, lineno);
 
2257
        } else {
 
2258
            tree = p.parse(sourceReader, sourceName, lineno);
 
2259
        }
 
2260
        if (returnFunction) {
 
2261
            if (!(tree.getFunctionCount() == 1
 
2262
                  && tree.getFirstChild() != null
 
2263
                  && tree.getFirstChild().getType() == Token.FUNCTION))
 
2264
            {
 
2265
                // XXX: the check just look for the first child
 
2266
                // and allows for more nodes after it for compatibility
 
2267
                // with sources like function() {};;;
 
2268
                throw new IllegalArgumentException(
 
2269
                    "compileFunction only accepts source with single JS function: "+sourceString);
 
2270
            }
 
2271
        }
 
2272
 
 
2273
        if (compiler == null) {
 
2274
            compiler = createCompiler();
 
2275
        }
 
2276
 
 
2277
        String encodedSource = p.getEncodedSource();
 
2278
 
 
2279
        Object bytecode = compiler.compile(compilerEnv,
 
2280
                                           tree, encodedSource,
 
2281
                                           returnFunction);
 
2282
 
 
2283
        if (debugger != null) {
 
2284
            if (sourceString == null) Kit.codeBug();
 
2285
            if (bytecode instanceof DebuggableScript) {
 
2286
                DebuggableScript dscript = (DebuggableScript)bytecode;
 
2287
                notifyDebugger_r(this, dscript, sourceString);
 
2288
            } else {
 
2289
                throw new RuntimeException("NOT SUPPORTED");
 
2290
            }
 
2291
        }
 
2292
 
 
2293
        Object result;
 
2294
        if (returnFunction) {
 
2295
            result = compiler.createFunctionObject(this, scope, bytecode, securityDomain);
 
2296
        } else {
 
2297
            result = compiler.createScriptObject(bytecode, securityDomain);
 
2298
        }
 
2299
 
 
2300
        return result;
 
2301
    }
 
2302
 
 
2303
    private static void notifyDebugger_r(Context cx, DebuggableScript dscript,
 
2304
                                         String debugSource)
 
2305
    {
 
2306
        cx.debugger.handleCompilationDone(cx, dscript, debugSource);
 
2307
        for (int i = 0; i != dscript.getFunctionCount(); ++i) {
 
2308
            notifyDebugger_r(cx, dscript.getFunction(i), debugSource);
 
2309
        }
 
2310
    }
 
2311
 
 
2312
    private static Class codegenClass = Kit.classOrNull(
 
2313
                             "org.mozilla.javascript.optimizer.Codegen");
 
2314
    private static Class interpreterClass = Kit.classOrNull(
 
2315
                             "org.mozilla.javascript.Interpreter");
 
2316
 
 
2317
    private Evaluator createCompiler()
 
2318
    {
 
2319
        Evaluator result = null;
 
2320
        if (optimizationLevel >= 0 && codegenClass != null) {
 
2321
            result = (Evaluator)Kit.newInstanceOrNull(codegenClass);
 
2322
        }
 
2323
        if (result == null) {
 
2324
            result = createInterpreter();
 
2325
        }
 
2326
        return result;
 
2327
    }
 
2328
 
 
2329
    static Evaluator createInterpreter()
 
2330
    {
 
2331
        return (Evaluator)Kit.newInstanceOrNull(interpreterClass);
 
2332
    }
 
2333
 
 
2334
    static String getSourcePositionFromStack(int[] linep)
 
2335
    {
 
2336
        Context cx = getCurrentContext();
 
2337
        if (cx == null)
 
2338
            return null;
 
2339
        if (cx.lastInterpreterFrame != null) {
 
2340
            Evaluator evaluator = createInterpreter();
 
2341
            if (evaluator != null)
 
2342
                return evaluator.getSourcePositionFromStack(cx, linep);
 
2343
        }
 
2344
        /**
 
2345
         * A bit of a hack, but the only way to get filename and line
 
2346
         * number from an enclosing frame.
 
2347
         */
 
2348
        CharArrayWriter writer = new CharArrayWriter();
 
2349
        RuntimeException re = new RuntimeException();
 
2350
        re.printStackTrace(new PrintWriter(writer));
 
2351
        String s = writer.toString();
 
2352
        int open = -1;
 
2353
        int close = -1;
 
2354
        int colon = -1;
 
2355
        for (int i=0; i < s.length(); i++) {
 
2356
            char c = s.charAt(i);
 
2357
            if (c == ':')
 
2358
                colon = i;
 
2359
            else if (c == '(')
 
2360
                open = i;
 
2361
            else if (c == ')')
 
2362
                close = i;
 
2363
            else if (c == '\n' && open != -1 && close != -1 && colon != -1 &&
 
2364
                     open < colon && colon < close)
 
2365
            {
 
2366
                String fileStr = s.substring(open + 1, colon);
 
2367
                if (!fileStr.endsWith(".java")) {
 
2368
                    String lineStr = s.substring(colon + 1, close);
 
2369
                    try {
 
2370
                        linep[0] = Integer.parseInt(lineStr);
 
2371
                        if (linep[0] < 0) {
 
2372
                            linep[0] = 0;
 
2373
                        }
 
2374
                        return fileStr;
 
2375
                    }
 
2376
                    catch (NumberFormatException e) {
 
2377
                        // fall through
 
2378
                    }
 
2379
                }
 
2380
                open = close = colon = -1;
 
2381
            }
 
2382
        }
 
2383
 
 
2384
        return null;
 
2385
    }
 
2386
 
 
2387
    RegExpProxy getRegExpProxy()
 
2388
    {
 
2389
        if (regExpProxy == null) {
 
2390
            Class cl = Kit.classOrNull(
 
2391
                          "org.mozilla.javascript.regexp.RegExpImpl");
 
2392
            if (cl != null) {
 
2393
                regExpProxy = (RegExpProxy)Kit.newInstanceOrNull(cl);
 
2394
            }
 
2395
        }
 
2396
        return regExpProxy;
 
2397
    }
 
2398
 
 
2399
    final boolean isVersionECMA1()
 
2400
    {
 
2401
        return version == VERSION_DEFAULT || version >= VERSION_1_3;
 
2402
    }
 
2403
 
 
2404
// The method must NOT be public or protected
 
2405
    SecurityController getSecurityController()
 
2406
    {
 
2407
        SecurityController global = SecurityController.global();
 
2408
        if (global != null) {
 
2409
            return global;
 
2410
        }
 
2411
        return securityController;
 
2412
    }
 
2413
 
 
2414
    public final boolean isGeneratingDebugChanged()
 
2415
    {
 
2416
        return generatingDebugChanged;
 
2417
    }
 
2418
 
 
2419
    /**
 
2420
     * Add a name to the list of names forcing the creation of real
 
2421
     * activation objects for functions.
 
2422
     *
 
2423
     * @param name the name of the object to add to the list
 
2424
     */
 
2425
    public void addActivationName(String name)
 
2426
    {
 
2427
        if (sealed) onSealedMutation();
 
2428
        if (activationNames == null)
 
2429
            activationNames = new Hashtable(5);
 
2430
        activationNames.put(name, name);
 
2431
    }
 
2432
 
 
2433
    /**
 
2434
     * Check whether the name is in the list of names of objects
 
2435
     * forcing the creation of activation objects.
 
2436
     *
 
2437
     * @param name the name of the object to test
 
2438
     *
 
2439
     * @return true if an function activation object is needed.
 
2440
     */
 
2441
    public final boolean isActivationNeeded(String name)
 
2442
    {
 
2443
        return activationNames != null && activationNames.containsKey(name);
 
2444
    }
 
2445
 
 
2446
    /**
 
2447
     * Remove a name from the list of names forcing the creation of real
 
2448
     * activation objects for functions.
 
2449
     *
 
2450
     * @param name the name of the object to remove from the list
 
2451
     */
 
2452
    public void removeActivationName(String name)
 
2453
    {
 
2454
        if (sealed) onSealedMutation();
 
2455
        if (activationNames != null)
 
2456
            activationNames.remove(name);
 
2457
    }
 
2458
 
 
2459
    private static String implementationVersion;
 
2460
 
 
2461
    private final ContextFactory factory;
 
2462
    private boolean sealed;
 
2463
    private Object sealKey;
 
2464
 
 
2465
    Scriptable topCallScope;
 
2466
    NativeCall currentActivationCall;
 
2467
    XMLLib cachedXMLLib;
 
2468
 
 
2469
    // for Objects, Arrays to tag themselves as being printed out,
 
2470
    // so they don't print themselves out recursively.
 
2471
    // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility
 
2472
    ObjToIntMap iterating;
 
2473
 
 
2474
    Object interpreterSecurityDomain;
 
2475
 
 
2476
    int version;
 
2477
 
 
2478
    private SecurityController securityController;
 
2479
    private ClassShutter classShutter;
 
2480
    private ErrorReporter errorReporter;
 
2481
    RegExpProxy regExpProxy;
 
2482
    private Locale locale;
 
2483
    private boolean generatingDebug;
 
2484
    private boolean generatingDebugChanged;
 
2485
    private boolean generatingSource=true;
 
2486
    boolean compileFunctionsWithDynamicScopeFlag;
 
2487
    boolean useDynamicScope;
 
2488
    private int optimizationLevel;
 
2489
    private int maximumInterpreterStackDepth;
 
2490
    private WrapFactory wrapFactory;
 
2491
    Debugger debugger;
 
2492
    private Object debuggerData;
 
2493
    private int enterCount;
 
2494
    private Object propertyListeners;
 
2495
    private Hashtable hashtable;
 
2496
    private ClassLoader applicationClassLoader;
 
2497
 
 
2498
    /**
 
2499
     * This is the list of names of objects forcing the creation of
 
2500
     * function activation records.
 
2501
     */
 
2502
    Hashtable activationNames;
 
2503
 
 
2504
    // For the interpreter to store the last frame for error reports etc.
 
2505
    Object lastInterpreterFrame;
 
2506
 
 
2507
    // For the interpreter to store information about previous invocations
 
2508
    // interpreter invocations
 
2509
    ObjArray previousInterpreterInvocations;
 
2510
 
 
2511
    // For instruction counting (interpreter only)
 
2512
    int instructionCount;
 
2513
    int instructionThreshold;
 
2514
 
 
2515
    // It can be used to return the second index-like result from function
 
2516
    int scratchIndex;
 
2517
 
 
2518
    // It can be used to return the second uint32 result from function
 
2519
    long scratchUint32;
 
2520
 
 
2521
    // It can be used to return the second Scriptable result from function
 
2522
    Scriptable scratchScriptable;
 
2523
 
 
2524
    // Generate an observer count on compiled code
 
2525
        public boolean generateObserverCount = false;
 
2526
}