KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > expr > SetExp


1 // Copyright (c) 1999, 2001, 2004, 2005 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.expr;
5 import gnu.mapping.*;
6 import gnu.mapping.Location; // As opposed to gnu.bytecode.Location
7
import gnu.bytecode.*;
8
9 /** An Expression to set (bind) or define a new value to a named variable.
10  * @author Per Bothner
11  */

12
13 public class SetExp extends AccessExp
14 {
15   /** The new value to assign to the variable. */
16   Expression new_value;
17
18   public SetExp (Object JavaDoc symbol, Expression val)
19   { this.symbol = symbol; new_value = val; }
20
21   public SetExp (Declaration decl, Expression val)
22   {
23     this.binding = decl;
24     symbol = decl.getSymbol();
25     new_value = val;
26   }
27
28   public static SetExp makeDefinition (Object JavaDoc symbol, Expression val)
29   {
30     SetExp sexp = new SetExp(symbol, val);
31     sexp.setDefining(true);
32     return sexp;
33   }
34
35   public static SetExp makeDefinition (Declaration decl, Expression val)
36   {
37     SetExp sexp = new SetExp(decl, val);
38     sexp.setDefining(true);
39     return sexp;
40   }
41
42   /** Get the Expression for calculating the new ("right-hand") value. */
43   public final Expression getNewValue() { return new_value; }
44
45   public static final int DEFINING_FLAG = NEXT_AVAIL_FLAG;
46   public static final int GLOBAL_FLAG = NEXT_AVAIL_FLAG << 1;
47   public static final int PREFER_BINDING2 = NEXT_AVAIL_FLAG << 2;
48   public static final int PROCEDURE = NEXT_AVAIL_FLAG << 3;
49   public static final int SET_IF_UNBOUND = NEXT_AVAIL_FLAG << 4;
50   public static final int HAS_VALUE = NEXT_AVAIL_FLAG << 5;
51
52   public final boolean isDefining ()
53   {
54     return (flags & DEFINING_FLAG) != 0;
55   }
56
57   public final void setDefining (boolean value)
58   {
59     if (value) flags |= DEFINING_FLAG; else flags &= ~DEFINING_FLAG;
60   }
61
62   /** True if evaluating the SetExp yields the value of the RHS. */
63   public final boolean getHasValue()
64   { return (flags & HAS_VALUE) != 0; }
65
66   public final void setHasValue (boolean value)
67   { if (value) flags |= HAS_VALUE; else flags &= ~HAS_VALUE; }
68
69   /** True if this is a functon definition ("defun"). */
70   public final boolean isFuncDef()
71   { return (flags & PROCEDURE) != 0; }
72
73   public final void setFuncDef (boolean value)
74   { if (value) flags |= PROCEDURE; else flags &= ~PROCEDURE; }
75
76   public final boolean isSetIfUnbound()
77   { return (flags & SET_IF_UNBOUND) != 0; }
78
79   public final void setSetIfUnbound (boolean value)
80   { if (value) flags |= SET_IF_UNBOUND; else flags &= ~SET_IF_UNBOUND; }
81
82   protected boolean mustCompile () { return false; }
83
84   public void apply (CallContext ctx) throws Throwable JavaDoc
85   {
86     Environment env = ctx.getEnvironment();
87     Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
88       : env.getSymbol(symbol.toString());
89     Object JavaDoc property = null;
90     Language language = Language.getDefaultLanguage();
91     if (isFuncDef() && language.hasSeparateFunctionNamespace())
92       property = EnvironmentKey.FUNCTION;
93     if (isSetIfUnbound())
94       {
95     Location loc = env.getLocation(sym, property);
96     if (! loc.isBound())
97       loc.set(new_value.eval (env));
98     if (getHasValue())
99        ctx.writeValue(loc);
100         return;
101       }
102
103     Object JavaDoc new_val = new_value.eval (env);
104     if (binding != null && ! (binding.context instanceof ModuleExp))
105       {
106         Object JavaDoc[] evalFrame = ctx.evalFrames[ScopeExp.nesting(binding.context)];
107         if (binding.isIndirectBinding())
108           {
109             Location loc;
110             if (isDefining())
111               evalFrame[binding.evalIndex] = Location.make(sym);
112             loc = (Location) evalFrame[binding.evalIndex];
113             loc.set(new_value);
114           }
115         else
116           evalFrame[binding.evalIndex] = new_val;
117       }
118     else if (isDefining ())
119       {
120     /*
121     if (binding != null && binding.isAlias())
122       env.addLocation(sym, null, (gnu.mapping.Location) new_val);
123     else
124     */

125     env.define(sym, property, new_val);
126       }
127     else
128       {
129     env.put(sym, property, new_val);
130       }
131     if (getHasValue())
132       ctx.writeValue(new_val);
133   }
134
135   public void compile (Compilation comp, Target target)
136   {
137     if (new_value instanceof LambdaExp
138     && target instanceof IgnoreTarget
139     && ((LambdaExp) new_value).getInlineOnly())
140       return;
141     Type type;
142     gnu.bytecode.CodeAttr code = comp.getCode();
143     // FIXME - handle isSetIfUnbound
144
boolean needValue = getHasValue() && ! (target instanceof IgnoreTarget);
145
146     // set the following to true if the value has been pushed.
147
// this is used to detect not implemented cases.
148
// when all cases are implemented, remove this.
149
boolean valuePushed = false;
150
151     // This code is kind of kludgy, because it handles a number of
152
// different cases: assignments and definitions to both local and
153
// global variables. Some of the complication is because we want
154
// to generate fields for module-level definitions; this is how
155
// bindings are exported from modules.
156

157     Declaration decl = binding;
158     Expression declValue = decl.getValue();
159     if (decl.getFlag(Declaration.EARLY_INIT)
160     && isDefining() && ! decl.ignorable())
161       {
162     BindingInitializer.create(decl, new_value, comp);
163       }
164     else if (declValue instanceof LambdaExp
165     && decl.context instanceof ModuleExp
166     && (! decl.isPrivate() || declValue instanceof ClassExp)
167     && ((LambdaExp) declValue).getName() != null // FIXME
168
&& declValue == new_value)
169       {
170     ((LambdaExp) new_value).compileSetField(comp);
171       }
172     else if (decl.context instanceof ModuleExp
173          && (decl.getFlag(Declaration.IS_CONSTANT) || decl.isAlias())
174              && isDefining()
175              && declValue != null)
176       { // This is handled in ModuleExp's allocFields method. But:
177
if (needValue)
178           {
179             decl.load(this, 0, comp, Target.pushObject);
180         valuePushed = true;
181       }
182       }
183     else
184       {
185         AccessExp access = this;
186         Declaration owner = contextDecl();
187     if (! isDefining())
188           {
189             while (decl != null && decl.isAlias())
190               {
191                 declValue = decl.getValue();
192                 if (! (declValue instanceof ReferenceExp))
193                   break;
194                 ReferenceExp rexp = (ReferenceExp) declValue;
195                 Declaration orig = rexp.binding;
196                 if (orig == null)
197                   break;
198                 if (owner != null && orig.needsContext())
199                   break;
200                 owner = rexp.contextDecl();
201                 access = rexp;
202                 decl = orig;
203               }
204       }
205     if (decl.ignorable())
206       new_value.compile (comp, Target.Ignore);
207     else if (decl.isAlias() && isDefining())
208       {
209             decl.load(this, ReferenceExp.DONT_DEREFERENCE,
210                       comp, Target.pushObject);
211         ClassType locType
212           = ClassType.make("gnu.mapping.IndirectableLocation");
213         code.emitCheckcast(locType);
214         new_value.compile(comp, Target.pushObject);
215         Method meth = locType.getDeclaredMethod("setAlias", 1);
216         code.emitInvokeVirtual(meth);
217       }
218     else if (decl.isIndirectBinding())
219       {
220             decl.load(access, ReferenceExp.DONT_DEREFERENCE,
221                       comp, Target.pushObject);
222         if (isSetIfUnbound())
223           {
224         if (needValue)
225           {
226             code.emitDup();
227             valuePushed = true;
228           }
229         code.pushScope();
230         code.emitDup();
231         Variable symLoc = code.addLocal(Compilation.typeLocation);
232         code.emitStore(symLoc);
233         code.emitInvokeVirtual(Compilation.typeLocation
234                        .getDeclaredMethod("isBound", 0));
235         code.emitIfIntEqZero();
236         code.emitLoad(symLoc);
237           }
238         new_value.compile (comp, Target.pushObject);
239         if (needValue && ! isSetIfUnbound())
240           {
241         code.emitDupX();
242         valuePushed = true;
243           }
244         String JavaDoc setterName = "set";
245         code.emitInvokeVirtual(Compilation.typeLocation
246                    .getDeclaredMethod(setterName, 1));
247         if (isSetIfUnbound())
248           {
249         code.emitFi();
250         code.popScope();
251           }
252       }
253     else if (decl.isSimple ())
254       {
255             type = decl.getType();
256         new_value.compile(comp, decl);
257         if (needValue)
258               {
259                 code.emitDup(type); // dup or dup2
260
valuePushed = true;
261               }
262         Variable var = decl.getVariable();
263         if (var == null)
264           var = decl.allocateVariable(code);
265         code.emitStore(var);
266       }
267     else if (decl.context instanceof ClassExp && decl.field == null
268          && ! getFlag(PROCEDURE)
269          && ((ClassExp) decl.context).isMakingClassPair())
270       {
271         String JavaDoc setName = ClassExp.slotToMethodName("set", decl.getName());
272         ClassExp cl = (ClassExp) decl.context;
273         Method setter = cl.type.getDeclaredMethod(setName, 1);
274         cl.loadHeapFrame(comp);
275         new_value.compile(comp, decl);
276         if (needValue)
277           {
278         code.emitDupX();
279         valuePushed = true;
280           }
281         code.emitInvoke(setter);
282       }
283     else
284       {
285         Field field = decl.field;
286             if (! field.getStaticFlag())
287               decl.loadOwningObject(owner, comp);
288             type = field.getType();
289         new_value.compile(comp, decl);
290             if (field.getStaticFlag())
291               {
292                 if (needValue)
293                   {
294                     code.emitDup(type);
295                     valuePushed = true;
296                   }
297                 code.emitPutStatic(field);
298               }
299             else
300               {
301                 if (needValue)
302                   {
303                     code.emitDupX();
304                     valuePushed = true;
305                   }
306                 code.emitPutField(field);
307               }
308       }
309       }
310
311     if (needValue && ! valuePushed)
312       throw new Error JavaDoc("SetExp.compile: not implemented - return value");
313
314     if (needValue)
315       target.compileFromStack(comp, getType());
316     else
317       comp.compileConstant(Values.empty, target);
318   }
319
320   public final gnu.bytecode.Type getType()
321   {
322     return ! getHasValue() ? Type.void_type
323       : binding == null ? Type.pointer_type : binding.getType();
324   }
325
326   protected Expression walk (ExpWalker walker)
327   {
328     return walker.walkSetExp(this);
329   }
330
331   protected void walkChildren (ExpWalker walker)
332   {
333     new_value = (Expression) walker.walk(new_value);
334   }
335
336   public void print (OutPort out)
337   {
338     out.startLogicalBlock(isDefining () ? "(Define" : "(Set", ")", 2);
339     out.writeSpaceFill();
340     printLineColumn(out);
341     if (binding == null || symbol.toString() != binding.getName())
342       {
343     out.print('/');
344     out.print(symbol);
345       }
346     if (binding != null)
347       {
348     out.print('/');
349     out.print(binding);
350       }
351     out.writeSpaceLinear();
352     new_value.print(out);
353     out.endLogicalBlock(")");
354   }
355
356   public String JavaDoc toString()
357   {
358     return "SetExp["+symbol+":="+new_value+']';
359   }
360 }
361
Popular Tags