1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 package org.mozilla.javascript;
8 
9 /**
10  * The JavaScript Script object.
11  *
12  * Note that the C version of the engine uses XDR as the format used
13  * by freeze and thaw. Since this depends on the internal format of
14  * structures in the C runtime, we cannot duplicate it.
15  *
16  * Since we cannot replace 'this' as a result of the compile method,
17  * will forward requests to execute to the nonnull 'script' field.
18  *
19  * @since 1.3
20  * @author Norris Boyd
21  */
22 
23 class NativeScript extends BaseFunction
24 {
25     static final long serialVersionUID = -6795101161980121700L;
26 
27     private static final Object SCRIPT_TAG = "Script";
28 
init(Scriptable scope, boolean sealed)29     static void init(Scriptable scope, boolean sealed)
30     {
31         NativeScript obj = new NativeScript(null);
32         obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
33     }
34 
NativeScript(Script script)35     private NativeScript(Script script)
36     {
37         this.script = script;
38     }
39 
40     /**
41      * Returns the name of this JavaScript class, "Script".
42      */
43     @Override
getClassName()44     public String getClassName()
45     {
46         return "Script";
47     }
48 
49     @Override
call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args)50     public Object call(Context cx, Scriptable scope, Scriptable thisObj,
51                        Object[] args)
52     {
53         if (script != null) {
54             return script.exec(cx, scope);
55         }
56         return Undefined.instance;
57     }
58 
59     @Override
construct(Context cx, Scriptable scope, Object[] args)60     public Scriptable construct(Context cx, Scriptable scope, Object[] args)
61     {
62         throw Context.reportRuntimeError0("msg.script.is.not.constructor");
63     }
64 
65     @Override
getLength()66     public int getLength()
67     {
68         return 0;
69     }
70 
71     @Override
getArity()72     public int getArity()
73     {
74         return 0;
75     }
76 
77     @Override
decompile(int indent, int flags)78     String decompile(int indent, int flags)
79     {
80         if (script instanceof NativeFunction) {
81             return ((NativeFunction)script).decompile(indent, flags);
82         }
83         return super.decompile(indent, flags);
84     }
85 
86     @Override
initPrototypeId(int id)87     protected void initPrototypeId(int id)
88     {
89         String s;
90         int arity;
91         switch (id) {
92           case Id_constructor: arity=1; s="constructor"; break;
93           case Id_toString:    arity=0; s="toString";    break;
94           case Id_exec:        arity=0; s="exec";        break;
95           case Id_compile:     arity=1; s="compile";     break;
96           default: throw new IllegalArgumentException(String.valueOf(id));
97         }
98         initPrototypeMethod(SCRIPT_TAG, id, s, arity);
99     }
100 
101     @Override
execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args)102     public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
103                              Scriptable thisObj, Object[] args)
104     {
105         if (!f.hasTag(SCRIPT_TAG)) {
106             return super.execIdCall(f, cx, scope, thisObj, args);
107         }
108         int id = f.methodId();
109         switch (id) {
110           case Id_constructor: {
111             String source = (args.length == 0)
112                             ? ""
113                             : ScriptRuntime.toString(args[0]);
114             Script script = compile(cx, source);
115             NativeScript nscript = new NativeScript(script);
116             ScriptRuntime.setObjectProtoAndParent(nscript, scope);
117             return nscript;
118           }
119 
120           case Id_toString: {
121             NativeScript real = realThis(thisObj, f);
122             Script realScript = real.script;
123             if (realScript == null) { return ""; }
124             return cx.decompileScript(realScript, 0);
125           }
126 
127           case Id_exec: {
128             throw Context.reportRuntimeError1(
129                 "msg.cant.call.indirect", "exec");
130           }
131 
132           case Id_compile: {
133             NativeScript real = realThis(thisObj, f);
134             String source = ScriptRuntime.toString(args, 0);
135             real.script = compile(cx, source);
136             return real;
137           }
138         }
139         throw new IllegalArgumentException(String.valueOf(id));
140     }
141 
realThis(Scriptable thisObj, IdFunctionObject f)142     private static NativeScript realThis(Scriptable thisObj, IdFunctionObject f)
143     {
144         if (!(thisObj instanceof NativeScript))
145             throw incompatibleCallError(f);
146         return (NativeScript)thisObj;
147     }
148 
compile(Context cx, String source)149     private static Script compile(Context cx, String source)
150     {
151         int[] linep = { 0 };
152         String filename = Context.getSourcePositionFromStack(linep);
153         if (filename == null) {
154             filename = "<Script object>";
155             linep[0] = 1;
156         }
157         ErrorReporter reporter;
158         reporter = DefaultErrorReporter.forEval(cx.getErrorReporter());
159         return cx.compileString(source, null, reporter, filename,
160                                 linep[0], null);
161     }
162 
163 // #string_id_map#
164 
165     @Override
findPrototypeId(String s)166     protected int findPrototypeId(String s)
167     {
168         int id;
169 // #generated# Last update: 2007-05-09 08:16:01 EDT
170         L0: { id = 0; String X = null;
171             L: switch (s.length()) {
172             case 4: X="exec";id=Id_exec; break L;
173             case 7: X="compile";id=Id_compile; break L;
174             case 8: X="toString";id=Id_toString; break L;
175             case 11: X="constructor";id=Id_constructor; break L;
176             }
177             if (X!=null && X!=s && !X.equals(s)) id = 0;
178             break L0;
179         }
180 // #/generated#
181         return id;
182     }
183 
184     private static final int
185         Id_constructor    = 1,
186         Id_toString       = 2,
187         Id_compile        = 3,
188         Id_exec           = 4,
189         MAX_PROTOTYPE_ID  = 4;
190 
191 // #/string_id_map#
192 
193     private Script script;
194 }
195 
196