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 import java.io.Serializable;
10 
11 /**
12  * This class implements the object lookup required for the
13  * <code>with</code> statement.
14  * It simply delegates every action to its prototype except
15  * for operations on its parent.
16  */
17 public class NativeWith implements Scriptable, IdFunctionCall, Serializable {
18 
19     private static final long serialVersionUID = 1L;
20 
init(Scriptable scope, boolean sealed)21     static void init(Scriptable scope, boolean sealed)
22     {
23         NativeWith obj = new NativeWith();
24 
25         obj.setParentScope(scope);
26         obj.setPrototype(ScriptableObject.getObjectPrototype(scope));
27 
28         IdFunctionObject ctor = new IdFunctionObject(obj, FTAG, Id_constructor,
29                                          "With", 0, scope);
30         ctor.markAsConstructor(obj);
31         if (sealed) {
32             ctor.sealObject();
33         }
34         ctor.exportAsScopeProperty();
35     }
36 
NativeWith()37     private NativeWith() {
38     }
39 
NativeWith(Scriptable parent, Scriptable prototype)40     protected NativeWith(Scriptable parent, Scriptable prototype) {
41         this.parent = parent;
42         this.prototype = prototype;
43     }
44 
getClassName()45     public String getClassName() {
46         return "With";
47     }
48 
has(String id, Scriptable start)49     public boolean has(String id, Scriptable start)
50     {
51         return prototype.has(id, prototype);
52     }
53 
has(int index, Scriptable start)54     public boolean has(int index, Scriptable start)
55     {
56         return prototype.has(index, prototype);
57     }
58 
get(String id, Scriptable start)59     public Object get(String id, Scriptable start)
60     {
61         if (start == this)
62             start = prototype;
63         return prototype.get(id, start);
64     }
65 
get(int index, Scriptable start)66     public Object get(int index, Scriptable start)
67     {
68         if (start == this)
69             start = prototype;
70         return prototype.get(index, start);
71     }
72 
put(String id, Scriptable start, Object value)73     public void put(String id, Scriptable start, Object value)
74     {
75         if (start == this)
76             start = prototype;
77         prototype.put(id, start, value);
78     }
79 
put(int index, Scriptable start, Object value)80     public void put(int index, Scriptable start, Object value)
81     {
82         if (start == this)
83             start = prototype;
84         prototype.put(index, start, value);
85     }
86 
delete(String id)87     public void delete(String id)
88     {
89         prototype.delete(id);
90     }
91 
delete(int index)92     public void delete(int index)
93     {
94         prototype.delete(index);
95     }
96 
getPrototype()97     public Scriptable getPrototype() {
98         return prototype;
99     }
100 
setPrototype(Scriptable prototype)101     public void setPrototype(Scriptable prototype) {
102         this.prototype = prototype;
103     }
104 
getParentScope()105     public Scriptable getParentScope() {
106         return parent;
107     }
108 
setParentScope(Scriptable parent)109     public void setParentScope(Scriptable parent) {
110         this.parent = parent;
111     }
112 
getIds()113     public Object[] getIds() {
114         return prototype.getIds();
115     }
116 
getDefaultValue(Class<?> typeHint)117     public Object getDefaultValue(Class<?> typeHint) {
118         return prototype.getDefaultValue(typeHint);
119     }
120 
hasInstance(Scriptable value)121     public boolean hasInstance(Scriptable value) {
122         return prototype.hasInstance(value);
123     }
124 
125     /**
126      * Must return null to continue looping or the final collection result.
127      */
updateDotQuery(boolean value)128     protected Object updateDotQuery(boolean value)
129     {
130         // NativeWith itself does not support it
131         throw new IllegalStateException();
132     }
133 
execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args)134     public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
135                              Scriptable thisObj, Object[] args)
136     {
137         if (f.hasTag(FTAG)) {
138             if (f.methodId() == Id_constructor) {
139                 throw Context.reportRuntimeError1("msg.cant.call.indirect", "With");
140             }
141         }
142         throw f.unknown();
143     }
144 
isWithFunction(Object functionObj)145     static boolean isWithFunction(Object functionObj)
146     {
147         if (functionObj instanceof IdFunctionObject) {
148             IdFunctionObject f = (IdFunctionObject)functionObj;
149             return f.hasTag(FTAG) && f.methodId() == Id_constructor;
150         }
151         return false;
152     }
153 
newWithSpecial(Context cx, Scriptable scope, Object[] args)154     static Object newWithSpecial(Context cx, Scriptable scope, Object[] args)
155     {
156         ScriptRuntime.checkDeprecated(cx, "With");
157         scope = ScriptableObject.getTopLevelScope(scope);
158         NativeWith thisObj = new NativeWith();
159         thisObj.setPrototype(args.length == 0
160                              ? ScriptableObject.getObjectPrototype(scope)
161                              : ScriptRuntime.toObject(cx, scope, args[0]));
162         thisObj.setParentScope(scope);
163         return thisObj;
164     }
165 
166     private static final Object FTAG = "With";
167 
168     private static final int
169         Id_constructor = 1;
170 
171     protected Scriptable prototype;
172     protected Scriptable parent;
173 }
174