1 // Copyright (c) 2003, 2009, 2010, 2011  Per M.A. Bothner.
2 // This is free software;  for terms and warranty disclaimer see ./COPYING.
3 
4 package gnu.expr;
5 import gnu.bytecode.*;
6 import gnu.kawa.functions.*;
7 import gnu.kawa.io.OutPort;
8 import gnu.mapping.*;
9 import gnu.kawa.reflect.MappedArrayType;
10 import gnu.text.SourceLocator;
11 import gnu.text.SourceLocator;
12 import gnu.math.*;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.lang.reflect.Proxy;
16 import java.lang.annotation.ElementType;
17 
18 /**
19  * The static information associated with a local variable binding.
20  * @author	Per Bothner
21  *
22  * These are the kinds of Declaration we use:
23  *
24  * A local variable that is not captured by an inner lambda is stored
25  * in a Java local variables slot (register).  The predicate isSimple ()
26  * is true, and offset is the number of the local variable slot.
27  *
28  * If a local variable is captured by an inner lambda, the
29  * variable is stored in a field of the LambdaExp's heapFrame variable.
30  * (The latter declaration has isSimple and isArtificial true.)
31  * The Declaration's field specifies the Field used.
32  *
33  * If a function takes a fixed number of parameters, at most four,
34  * then the arguments are passed in Java registers 1..4.
35  * If a parameter is not captured by an inner lambda, the parameter
36  * has the flags isSimple and isParameter true.
37  *
38  * If a function takes more than 4 or a variable number of parameters,
39  * the arguments are passed in an array (using the applyN virtual method).
40  * This array is referenced by the argsArray declaration, which has
41  * isSimple(), isParameter(), and isArtificial() true, and its offset is 1.
42  * The parameters are copied into the program-named variables by the
43  * procedure prologue, so the parameters henceforth act like local variables.
44  */
45 
46 public class Declaration extends SourceLocator.Simple
47 {
48   static int counter;
49   /** Unique id number, to ease print-outs and debugging.
50    * If negative, a code to specify a builtin function. */
51   protected int id = ++counter;
52 
53   /** The name of the new variable, either an interned String or a Symbol.
54    * This is the source-level (non-mangled) name. */
55   Object symbol;
56 
setCode(int code)57   public void setCode (int code)
58   {
59     if (code >= 0) throw new Error("code must be negative");
60     this.id = code;
61   }
62 
getCode()63   public int getCode () { return id; }
64 
65   public ScopeExp context;
66 
67   /** The type of the value of this Declaration.
68    * It is null if the type is un-specified and not yet inferred.
69    * Will get set implicitly by getType, to avoid inconsistencies.
70    */
71     public/*protected*/ Type type;
72     public/*protected*/ Expression typeExp;
getTypeExp()73   public final Expression getTypeExp()
74   {
75     if (typeExp == null)
76       setType(Type.objectType);
77     return typeExp;
78   }
getType()79   public final Type getType()
80   {
81     if (type == null)
82       {
83         Type t = Type.objectType;
84         type = t;  // To protect against possible cycles.
85         if (! hasUnknownValue() && nvalues > 0)
86           {
87             int arithCount = 0;
88             for (int i = 0;  i < nvalues;  i++)
89               {
90                 Expression vi = values[i].getValue(this);
91                 boolean arithOp = false;
92                 if (vi != null && ! (vi.getFlag(Expression.VALIDATED)))
93                   {
94                     // Special handling of arithmetic assignments like
95                     // '(set! D (+ D V))', where D is this Declaration.
96                     // We can then use the type of V, instead of the unknown
97                     // type of (+ D V), to inductively determine the type of D.
98                     Expression oparg = checkArithStepOp(vi);
99                     if (oparg != null)
100                       {
101                         // oparg is the expression D above.
102                         arithOp = true;
103                         arithCount++;
104                         vi = oparg;
105                       }
106                   }
107                 Declaration d;
108                 if ((vi != null && vi.getFlag(Expression.VALIDATED))
109                     || vi instanceof LambdaExp
110                     || vi instanceof QuoteExp
111                     || (vi instanceof ReferenceExp
112                         && (d = ((ReferenceExp) vi).getBinding()) != null
113                         && d.type != null))
114                   {
115                     Type vt = vi.getType();
116                     if (i == 0)
117                       t = vt;
118                     else if (arithOp)
119                       t = CompileArith.combineType(t, vt);
120                     else
121                       t = Language.unionType(t, vt);
122                   }
123                 else
124                   {
125                     t = Type.objectType;
126                     break;
127                   }
128               }
129           }
130         setType(t);
131       }
132     return type;
133   }
134 
checkArithStepOp(Expression exp)135   private Expression checkArithStepOp (Expression exp)
136   {
137     if (! (exp instanceof ApplyExp))
138       return null;
139     ApplyExp aexp = (ApplyExp) exp;
140     Expression func = aexp.getFunction();
141     Compilation comp = Compilation.getCurrent();
142     boolean isApplyFunc = comp.isSimpleApplyFunction(func);
143     if (aexp.getArgCount() == (isApplyFunc ? 3 : 2))
144       {
145         if (isApplyFunc)
146           func = aexp.getArg(0);
147         Declaration fdecl;
148         if (func instanceof ReferenceExp
149             && (fdecl = ((ReferenceExp) func).getBinding()) != null
150             && fdecl.getValue() != null)
151           {
152             Object proc = fdecl.getValue().valueIfConstant();
153             if (proc instanceof AddOp || proc instanceof MultiplyOp)
154               {
155                 Expression arg1 = aexp.getArg(isApplyFunc ? 1 : 0);
156                 Expression arg2 = aexp.getArg(isApplyFunc ? 2 : 1);
157                 if (arg1 instanceof ReferenceExp
158                     && ((ReferenceExp) arg1).getBinding() == this)
159                   return arg2;
160                 if (arg2 instanceof ReferenceExp
161                     && ((ReferenceExp) arg2).getBinding() == this)
162                   return arg1;
163               }
164           }
165       }
166     return null;
167   }
168 
getTypeExpRaw()169   public Expression getTypeExpRaw () { return typeExp; }
170 
setType(Type type)171   public final void setType(Type type)
172   {
173     if (type.isVoid())
174       type = Type.objectType;
175     this.type = type;
176     typeExp = QuoteExp.getInstance(type);
177   }
178 
setTypeExp(Expression typeExp)179   public final void setTypeExp (Expression typeExp)
180   {
181     this.typeExp = typeExp;
182     Type t = null;
183     if (typeExp instanceof TypeValue)
184       t = ((TypeValue) typeExp).getImplementationType();
185     else
186       t = Language.getDefaultLanguage().getTypeFor(typeExp, false);
187     if (t == null)
188       t = Type.pointer_type;
189     this.type = t;
190     if (var != null) var.setType(t);
191   }
192 
setType(Expression typeExp, Type type)193   public final void setType (Expression typeExp, Type type)
194   {
195     this.typeExp = typeExp;
196     this.type = type;
197   }
198 
getName()199   public final String getName()
200   {
201     return symbol == null ? null : symbol instanceof Symbol ? ((Symbol) symbol).getName()
202       : symbol.toString();
203   }
setName(Object symbol)204   public final void setName(Object symbol)
205   {
206     this.symbol = symbol;
207   }
208 
getSymbol()209   public final Object getSymbol() { return symbol; }
setSymbol(Object symbol)210   public final void setSymbol(Object symbol) { this.symbol = symbol; }
211 
212   /* Declarations in a ScopeExp are linked together in a linked list. */
213   private Declaration next;
214 
nextDecl()215   public final Declaration nextDecl() { return next; }
setNext(Declaration next)216   public final void setNext(Declaration next) { this.next = next; }
217 
218   /** Index in evalFrame for this scope, if interpreting. */
219   int evalIndex;
220 
221   Variable var;
getVariable()222   public Variable getVariable() { return var; }
223 
224     /** If non-zero, indicates this names a 'scan' of a sequence.
225      * The value property is a sequence; the declaration names
226      * "each" of the elements.
227      * This field is the amount of nesting within scan ('...') contexts.
228      */
getScanNesting()229     public int getScanNesting() { return scanNesting; }
setScanNesting(int value)230     public void setScanNesting(int value) { scanNesting = value; }
231     int scanNesting;
232 
isSimple()233   public final boolean isSimple()
234   { return (flags & IS_SIMPLE) != 0; }
235 
setSimple(boolean b)236   public final void setSimple(boolean b)
237   {
238     setFlag(b, IS_SIMPLE);
239     if (var != null && ! var.isParameter()) var.setSimple(b);
240   }
241 
setSyntax()242   public final void setSyntax ()
243   {
244     setSimple(false);
245     setFlag(IS_CONSTANT|IS_SYNTAX|EARLY_INIT);
246   }
247 
248   /** Return the ScopeExp that contains (declares) this Declaration. */
getContext()249   public final ScopeExp getContext() { return context; }
250 
251   /** Used to link Declarations in a LambdaExp's capturedVars list. */
252   Declaration nextCapturedVar;
253 
254   /** If non-null, field is relative to base.
255    * If IS_FLUID, base points to IS_UNKNOWN Symbol. */
256   public Declaration base;
257 
258     private Field field;
259     public Method getterMethod;
260     public Method setterMethod;
261 
262   /** If this is a field in some object, load a reference to that object. */
loadOwningObject(Declaration owner, Compilation comp)263   void loadOwningObject (Declaration owner, Compilation comp)
264   {
265     if (owner == null)
266       owner = base;
267     if (owner != null)
268       owner.load(null, 0, comp, Target.pushObject);
269     else
270       getContext().currentLambda().loadHeapFrame(comp);
271   }
272 
loadFieldLocation(Declaration owner, Compilation comp)273     public Type loadFieldLocation(Declaration owner, Compilation comp) {
274         Field fld = getField();
275         if (fld == null)
276           throw new Error("internal error: cannot take location of "+this);
277         Method meth;
278         ClassType ltype;
279         boolean immediate = comp.immediate;
280         if (! fld.getStaticFlag())
281             loadOwningObject(owner, comp);
282         if (fld.getStaticFlag()) {
283             ltype = Compilation.typeStaticFieldLocation;
284             meth = ltype.getDeclaredMethod("make", immediate ? 1 : 2);
285         } else {
286             ltype = Compilation.typeFieldLocation;
287             meth = ltype.getDeclaredMethod("make", immediate ? 2 : 3);
288         }
289         if (immediate)
290             comp.compileConstant(this);
291         else {
292             comp.compileConstant(fld.getDeclaringClass().getName());
293             comp.compileConstant(fld.getName());
294         }
295         comp.getCode().emitInvokeStatic(meth);
296         return ltype;
297     }
298 
load(AccessExp access, int flags, Compilation comp, Target target)299   public void load (AccessExp access, int flags,
300                     Compilation comp, Target target)
301   {
302     if (target instanceof IgnoreTarget)
303       {
304         if (access.getFlag(ReferenceExp.ALLOCATE_ON_STACK_LAST))
305           comp.getCode().emitPop(1);
306         return;
307       }
308     Declaration owner = access == null ? null : access.contextDecl();
309     Expression dvalue = getValueRaw();
310     if (isAlias() && dvalue instanceof ReferenceExp)
311       {
312         ReferenceExp rexp = (ReferenceExp) dvalue;
313         Declaration orig = rexp.binding;
314         if (orig != null
315             && ((flags & ReferenceExp.DONT_DEREFERENCE) == 0
316                 || orig.isIndirectBinding())
317             && (owner == null || ! orig.needsContext()))
318           {
319             orig.load(rexp, flags, comp, target);
320             return;
321           }
322       }
323     if (isFluid())
324       {
325         if (context instanceof FluidLetExp)
326           {
327             base.load(access, flags, comp, target);
328             return;
329           }
330       }
331     CodeAttr code = comp.getCode();
332     boolean dontDeref = (flags & ReferenceExp.DONT_DEREFERENCE) != 0;
333     Type rtype = dontDeref ? Compilation.typeLocation : getType();
334     if (! isIndirectBinding() && dontDeref)
335       {
336         rtype = loadFieldLocation(owner, comp);
337       }
338     else if (getFlag(ALLOCATE_ON_STACK))
339       {
340         int SP = code.getSP();
341         if (access.getFlag(ReferenceExp.ALLOCATE_ON_STACK_LAST))
342           ;
343         else if (SP == evalIndex)
344           code.emitDup();
345         else if (SP == evalIndex+1)
346           {
347             code.emitSwap();
348             code.emitDupX();
349           }
350         else
351           throw new InternalError("allocate-on-stack mismatch");
352       }
353     else
354       {
355         Object val;
356         Expression value = getValueRaw();
357         if (type == Type.javalangClassType
358             && (value instanceof ClassExp || value instanceof ModuleExp))
359           {
360             comp.loadClassRef(((LambdaExp) value).getCompiledClassType(comp));
361           }
362         else if (getField() != null)
363           {
364             comp.usedClass(getField().getDeclaringClass());
365             comp.usedClass(getField().getType());
366             if (! field.getStaticFlag())
367               {
368                 loadOwningObject(owner, comp);
369                 code.emitGetField(getField());
370               }
371             else
372               code.emitGetStatic(getField());
373             code.fixUnsigned(getType());
374           }
375         else if (isClassField())
376           {
377             String getName = ClassExp.slotToMethodName("get", getName());
378             Method getter = ((ClassExp) context).compiledType
379                 .getDeclaredMethod(getName, 0);
380             comp.usedClass(getter.getDeclaringClass());
381             comp.usedClass(getter.getReturnType());
382             loadOwningObject(owner, comp);
383             code.emitInvoke(getter);
384           }
385         else if (isIndirectBinding() && comp.immediate && getVariable() == null)
386           {
387             // This is a bit of a kludge.  See comment in ModuleExp.evalModule.
388             Environment env = Environment.getCurrent();
389             Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
390               : env.getSymbol(symbol.toString());
391             Object property = null;
392             if (isProcedureDecl()
393                 && comp.getLanguage().hasSeparateFunctionNamespace())
394               property = EnvironmentKey.FUNCTION;
395             gnu.mapping.Location loc = env.getLocation(sym, property);
396             comp.compileConstant(loc, Target.pushValue(Compilation.typeLocation));
397           }
398         else if (comp.immediate && (val = getConstantValue()) != null)
399           {
400             comp.compileConstant(val, target);
401             return;
402           }
403         else if (value != QuoteExp.undefined_exp && value != null
404                  && ignorable()
405                  && ! (value instanceof LambdaExp))
406           {
407             value.compile(comp, target);
408             return;
409           }
410         else
411           {
412             Variable var = getVariable();
413             if (var == null)
414               var = allocateVariable(code, true);
415             code.emitLoad(var);
416           }
417         if (isIndirectBinding() && ! dontDeref)
418           {
419             String filename;
420             int line;
421             if (access != null
422                 && (filename = access.getFileName()) != null
423                 && (line = access.getLineNumber()) > 0)
424               {
425                 // Wrap call to Location.get by a catch handler that
426                 // calls setLine on the UnboundLocationException.
427                 ClassType typeUnboundLocationException
428                   = ClassType.make("gnu.mapping.UnboundLocationException");
429                 // See comment in CheckedTarget.emitCheckedCoerce.
430                 boolean isInTry = code.isInTry();
431                 int column = access.getColumnNumber();
432                 Label startTry = new Label(code);
433                 startTry.define(code);
434                 code.emitInvokeVirtual(getLocationMethod);
435                 Label endTry = new Label(code);
436                 endTry.define(code);
437                 Label endLabel = new Label(code);
438                 endLabel.setTypes(code);
439                 if (isInTry)
440                   code.emitGoto(endLabel);
441                 else
442                   code.setUnreachable();
443                 int fragment_cookie = 0;
444                 if (! isInTry)
445                   fragment_cookie = code.beginFragment(endLabel);
446                 code.addHandler(startTry, endTry, typeUnboundLocationException);
447 
448                 code.emitDup(typeUnboundLocationException);
449                 code.emitPushString(filename);
450                 code.emitPushInt(line);
451                 code.emitPushInt(column);
452                 code.emitInvokeVirtual(typeUnboundLocationException
453                                        .getDeclaredMethod("setLine", 3));
454                 code.emitThrow();
455                 if (isInTry)
456                   endLabel.define(code);
457                 else
458                   code.endFragment(fragment_cookie);
459               }
460             else
461               code.emitInvokeVirtual(getLocationMethod);
462             if (isAlias()
463                 || target.getType().getRawType() == Type.objectType)
464                 rtype = Type.objectType;
465             else {
466                 getType().emitCoerceFromObject(code);
467                 rtype = getType();
468             }
469           }
470       }
471     target.compileFromStack(comp, rtype);
472   }
473 
474     static final Method getLocationMethod
475         = Compilation.typeLocation.addMethod("get", Type.typeArray0,
476                                              Type.objectType, Access.PUBLIC);
477 
478   /* Compile code to store a value (which must already be on the
479      stack) into this variable. */
compileStore(Compilation comp)480   public void compileStore (Compilation comp)
481   {
482     gnu.bytecode.CodeAttr code = comp.getCode();
483     if (isSimple ())
484       code.emitStore(getVariable());
485     else
486       {
487         if (! field.getStaticFlag())
488           {
489             loadOwningObject(null, comp);
490             code.emitSwap();
491 	    code.emitPutField(getField());
492           }
493 	else
494 	  code.emitPutStatic(getField());
495       }
496   }
497 
shouldEarlyInit()498   boolean shouldEarlyInit ()
499   {
500     return getFlag(EARLY_INIT) || isCompiletimeConstant ();
501   }
502 
isCompiletimeConstant()503   public boolean isCompiletimeConstant ()
504   {
505     return getFlag(IS_CONSTANT) && hasConstantValue();
506   }
507 
508   /** This prefix is prepended to field names for unknown names. */
509   static final String UNKNOWN_PREFIX = "loc$";
510 
511   /** This prefix is used in field names for a declaration that has
512    * both EXTERNAL_ACCESS and IS_PRIVATE set. */
513   public static final String PRIVATE_PREFIX = "$Prvt$";
514 
515   /** If this flag is set then to get the actual value you have to dereference
516    * a <code>gnu.mapping.Location</code>.  I.e. this <code>Declaration</code>'s
517    * <code>var</code> or <code>field</code> does not contain the
518    * <code>Declaration</code>'s value directly, but rather yields a
519    * <code>Location</code> that contains the <code>Declaration</code>'s value.
520    * Note that this flag indicates the <em>representation</em>:
521    * The result of <code>getValue()</code> is not the location, but the
522    * semantic value. after dereferencing.  Likewise <code>getType</code> is
523    * the value after de-referencing, not a <code>Location</code> sub-class. */
524   static final int INDIRECT_BINDING = 1;
525 
526   static final int CAN_READ = 2;
527   static final int CAN_CALL = 4;
528   static final int CAN_WRITE = 8;
529   static final int IS_FLUID = 0x10;
530   static final int PRIVATE = 0x20;
531   static final int IS_SIMPLE = 0x40;
532 
533   /** True if in the function namespace, for languages that distinguishes them.
534    * I.e. a function definition or macro definition. */
535   public static final int PROCEDURE = 0x80;
536 
537   public static final int IS_ALIAS = 0x100;
538 
539   /** Set if this is just a declaration, not a definition. */
540   public static final int NOT_DEFINING = 0x200;
541 
542   public static final int EXPORT_SPECIFIED = 0x400;
543   public static final int STATIC_SPECIFIED = 0x800;
544   public static final int NONSTATIC_SPECIFIED = 0x1000;
545   public static final int TYPE_SPECIFIED = 0x2000;
546   public static final int IS_CONSTANT = 0x4000;
547   public static final int IS_SYNTAX = 0x8000;
548   public static final int IS_UNKNOWN = 0x10000;
549   public static final int IS_IMPORTED = 0x20000;
550     public static final int IS_CAPTURED = IS_IMPORTED; // Re-use bit.
551 
552   // This should be a type property, not a variable property, at some point!
553   public static final int IS_SINGLE_VALUE = 0x40000;
554 
555   /** This flag bit is set if this can be be accessed from other modules.
556    * Ignored unless PRIVATE.
557    * Used when an exported macro references a non-exported name. */
558   public static final int EXTERNAL_ACCESS = 0x80000;
559 
needsExternalAccess()560   public final boolean needsExternalAccess ()
561   {
562     return (flags & EXTERNAL_ACCESS+PRIVATE) == EXTERNAL_ACCESS+PRIVATE
563       // Kludge - needed for macros - see Savannah bug #13601.
564       || (flags & IS_NAMESPACE_PREFIX+PRIVATE) == IS_NAMESPACE_PREFIX+PRIVATE;
565   }
566 
567   /** If we need a 'context' supplied from a ReferenceExp or 'this. */
needsContext()568   public final boolean needsContext ()
569   {
570     return base == null
571         && ((isClassField() && ! isStatic())
572             || (getField() != null && ! field.getStaticFlag()));
573   }
574 
575   /** True if this is a field or method in a class definition. */
576   public static final int FIELD_OR_METHOD = 0x100000;
577 
578   /** Set if this declares a namespace prefix (as in XML namespaces). */
579   public static final int IS_NAMESPACE_PREFIX = 0x200000;
580 
581   public static final int PRIVATE_ACCESS = 0x1000000;
582   public static final int PRIVATE_SPECIFIED = PRIVATE_ACCESS; /* deprecated*/
583   public static final int PROTECTED_ACCESS = 0x2000000;
584   public static final int PUBLIC_ACCESS = 0x4000000;
585   public static final int PACKAGE_ACCESS = 0x8000000;
586 
587   public static final int IS_DYNAMIC = 0x10000000;
588 
589   /** Initialize in {@code <init>}/{@code <clinit>}
590    * rather than in {@code run}/{@code $run$}. */
591   public static final int EARLY_INIT = 0x20000000;
592   /** A reference to a module instance. */
593   public static final int MODULE_REFERENCE = 0x40000000;
594 
595   public static final long VOLATILE_ACCESS = 0x80000000l;
596   public static final long TRANSIENT_ACCESS = 0x100000000l;
597   public static final long ENUM_ACCESS = 0x200000000l;
598   public static final long FINAL_ACCESS = 0x400000000l;
599   public static final long ABSTRACT_ACCESS = 0x800000000l;
600   public static final long SYNCHRONIZED_ACCESS = 0x1000000000l;
601   public static final long STRICTFP_ACCESS = 0x2000000000l;
602   public static final long CLASS_ACCESS_FLAGS =
603     PRIVATE_ACCESS|PROTECTED_ACCESS|ENUM_ACCESS|FINAL_ACCESS|ABSTRACT_ACCESS;
604   public static final long FIELD_ACCESS_FLAGS = PRIVATE_ACCESS|PROTECTED_ACCESS|
605     PUBLIC_ACCESS|PACKAGE_ACCESS|VOLATILE_ACCESS|TRANSIENT_ACCESS|
606     ENUM_ACCESS|FINAL_ACCESS;
607   public static final long METHOD_ACCESS_FLAGS = PRIVATE_ACCESS
608     |PROTECTED_ACCESS|PUBLIC_ACCESS|PACKAGE_ACCESS|FINAL_ACCESS
609     |SYNCHRONIZED_ACCESS|STRICTFP_ACCESS;
610 
611     public static final long MAYBE_UNINITIALIZED_ACCESS = 0x4000000000l;
612   /** Allocate variable on JVM stack as an optimization.
613    * This means load is implemented as a dup instruction.
614    * (This is no faster on decent JVMs, but the bytecode is more compact.)
615    * Note this may cause an InternalError if this is loaded when the
616    * JVM stack has grown since the variable was initialized.
617    */
618   public static final long ALLOCATE_ON_STACK = 0x8000000000l;
619 
620     /** True for a variable inside a pattern, but not the top of the pattern.
621      * E.g. for a pattern [a [b c]] there is a main declaration for the
622      * incoming value - which does not have PATTERN_NESTED set.  There are
623      * three declarations a, b, and c - which do have PATTERN_NESTED set.
624      * In addition there may be helper variables which are anonymous
625      * (i.e. getSymbol() returns null), like the match for the sequence [b c];
626      * these also have PATTERN_NESTED set. */
627     public static final long PATTERN_NESTED = 0x10000000000l;
628 
629     /** See parameterForMethod() */
630     public static final long SKIP_FOR_METHOD_PARAMETER = 0x20000000000l;
631     public static final long IS_REST_PARAMETER = 0x40000000000l;
632     public static final long IS_PARAMETER = 0x80000000000l;
633     /** Is this a supplied-parameter variable?
634      * If IS_SUPPLIED_PARAMETER is true and IS_PARAMETER is false
635      * then this is a boolean variable which reports if the previous parameter
636      * was provided by the argument list, rather than defaulted.
637      * If IS_SUPPLIED_PARAMETER is true and IS_PARAMETER is true then
638      * this is an optional or keyword parameter that has corresponding
639      * supplied-parameter later in the parameter list.
640      */
641     public static final long IS_SUPPLIED_PARAMETER = 0x100000000000l;
642     /** Applies to a 'rest' parameter if it can match keywords. */
643     public static final long KEYWORDS_OK = 0x200000000000l;
644     public static final long DONT_COPY = 0x400000000000l;
645     public static final long SCAN_OWNER = 0x800000000000l;
646 
647     protected long flags = IS_SIMPLE;
648 
getFlag(long flag)649   public final boolean getFlag (long flag)
650   {
651     return (flags & flag) != 0;
652   }
653 
setFlag(boolean setting, long flag)654   public final void setFlag (boolean setting, long flag)
655   {
656     if (setting) flags |= flag;
657     else flags &= ~flag;
658   }
659 
setFlag(long flag)660   public final void setFlag (long flag)
661   {
662     flags |= flag;
663   }
664 
isPublic()665   public final boolean isPublic()
666   { return context instanceof ModuleExp && (flags & PRIVATE) == 0; }
667 
isPrivate()668   public final boolean isPrivate() { return (flags & PRIVATE) != 0; }
669 
isModuleLocal()670     public final boolean isModuleLocal() {
671         return ! isPublic() && ! needsExternalAccess();
672     }
673 
setPrivate(boolean isPrivate)674   public final void setPrivate(boolean isPrivate)
675   {
676     setFlag(isPrivate, PRIVATE);
677   }
678 
getAccessFlags(short defaultFlags)679   public short getAccessFlags (short defaultFlags)
680   {
681     short flags;
682     if (getFlag(PRIVATE_ACCESS|PROTECTED_ACCESS|PACKAGE_ACCESS|PUBLIC_ACCESS))
683       {
684         flags = 0;
685         if (getFlag(PRIVATE_ACCESS))
686           flags |= Access.PRIVATE;
687         if (getFlag(PROTECTED_ACCESS))
688           flags |= Access.PROTECTED;
689         if (getFlag(PUBLIC_ACCESS))
690           flags |= Access.PUBLIC;
691       }
692     else
693       flags = defaultFlags;
694     if (getFlag(VOLATILE_ACCESS))
695       flags |= Access.VOLATILE;
696     if (getFlag(TRANSIENT_ACCESS))
697       flags |= Access.TRANSIENT;
698     if (getFlag(ENUM_ACCESS))
699       flags |= Access.ENUM;
700     if (getFlag(FINAL_ACCESS))
701       flags |= Access.FINAL;
702     if (getFlag(SYNCHRONIZED_ACCESS))
703       flags |= Access.SYNCHRONIZED;
704     if (getFlag(STRICTFP_ACCESS))
705       flags |= Access.STRICT;
706     return flags;
707   }
708 
isAlias()709   public final boolean isAlias() { return (flags & IS_ALIAS) != 0; }
setAlias(boolean flag)710   public final void setAlias(boolean flag) { setFlag(flag, IS_ALIAS); }
711 
712   /** True if this is a fluid binding (in a FluidLetExp).
713    * Also true if this binding is the one re-bound by a FluidLetExp. */
isFluid()714   public final boolean isFluid () { return (flags & IS_FLUID) != 0; }
715 
setFluid(boolean fluid)716   public final void setFluid (boolean fluid) { setFlag(fluid, IS_FLUID); }
717 
isProcedureDecl()718   public final boolean isProcedureDecl () { return (flags & PROCEDURE) != 0; }
719 
setProcedureDecl(boolean val)720   public final void setProcedureDecl (boolean val) { setFlag(val, PROCEDURE); }
721 
isClassMethod()722   public final boolean isClassMethod ()
723   {
724     return (flags & FIELD_OR_METHOD+PROCEDURE) == FIELD_OR_METHOD+PROCEDURE;
725   }
726 
isClassField()727   public final boolean isClassField ()
728   {
729     return (flags & FIELD_OR_METHOD+PROCEDURE) == FIELD_OR_METHOD;
730   }
731 
isNamespaceDecl()732   public final boolean isNamespaceDecl ()
733   {
734     return (flags & IS_NAMESPACE_PREFIX) != 0;
735   }
736 
737     /** Is this a parameter for the generated method?
738      * For example if a lambda's parameter is the pattern {@code [x y]}
739      * then there is an anonymous parameter p0 that is the incoming 2-element
740      * sequence plus named parameters {@code x} and {@code y}.
741      * The later two are parameters for the generated method,
742      * but the anonymous p0 is not.
743      */
parameterForMethod()744     public final boolean parameterForMethod() {
745         return ! getFlag(SKIP_FOR_METHOD_PARAMETER);
746     }
747 
748   /** True if the value of the variable is the contents of a Location.
749    * @see #INDIRECT_BINDING */
isIndirectBinding()750   public final boolean isIndirectBinding()
751   { return (flags & INDIRECT_BINDING) != 0; }
752 
753   /** Note that the value of the variable is the contents of a Location.
754    * @see #INDIRECT_BINDING */
setIndirectBinding(boolean indirectBinding)755   public final void setIndirectBinding(boolean indirectBinding)
756   {
757     setFlag(indirectBinding, INDIRECT_BINDING);
758   }
759 
maybeIndirectBinding(Compilation comp)760     public void maybeIndirectBinding(Compilation comp) {
761         if (isLexical() && ! inExternalModule(comp) && !getFlag(TYPE_SPECIFIED))
762             setIndirectBinding(true);
763     }
764 
inExternalModule(Compilation comp)765     public boolean inExternalModule(Compilation comp) {
766         return context instanceof ModuleExp && context != comp.mainLambda;
767     }
768 
769     /** Does this encapsulate a boolean guard expression?
770      * In that case this is an unnamed pseudo-parameter, that matches no
771      * actual arguments but where {@code getInitValue()} is the expression. */
isGuard()772     public boolean isGuard() {
773         return typeExp == QuoteExp.isTrueTypeExp;
774     }
775 
776   /* Note:  You probably want to use !ignorable(). */
getCanRead()777   public final boolean getCanRead() { return (flags & CAN_READ) != 0; }
setCanRead(boolean read)778   public final void setCanRead(boolean read)
779   {
780     setFlag(read, CAN_READ);
781   }
setCanRead()782   public final void setCanRead()
783   {
784     setFlag(true, CAN_READ);
785     if (base != null)
786       base.setCanRead();
787   }
788 
getCanReadOrCall()789     public final boolean getCanReadOrCall() {
790         return (flags & (CAN_READ|CAN_CALL)) != 0;
791     }
792 
getCanCall()793   public final boolean getCanCall() { return (flags & CAN_CALL) != 0; }
setCanCall(boolean called)794   public final void setCanCall(boolean called) { setFlag(called, CAN_CALL); }
setCanCall()795   public final void setCanCall()
796   {
797     setFlag(true, CAN_CALL);
798     if (base != null)
799       base.setCanRead();
800   }
801 
getCanWrite()802   public final boolean getCanWrite()
803   { return (flags & CAN_WRITE) != 0; }
804 
setCanWrite(boolean written)805   public final void setCanWrite(boolean written)
806   {
807     if (written) flags |= CAN_WRITE;
808     else flags &= ~CAN_WRITE;
809   }
810 
setCanWrite()811   public final void setCanWrite()
812   {
813     flags |= CAN_WRITE;
814     if (base != null)
815       base.setCanRead();
816   }
817 
818   /** Is this an implicit 'this' parameter? */
isThisParameter()819   public final boolean isThisParameter ()
820   {
821     return symbol == ThisExp.THIS_NAME;
822   }
823 
mayBeAccessedUninitialized()824   public boolean mayBeAccessedUninitialized ()
825   {
826     return getFlag(MAYBE_UNINITIALIZED_ACCESS);
827   }
828 
829   /** True if we never need to access this declaration. */
830   // rename to isAccessed?
ignorable()831   public boolean ignorable()
832   {
833     if (getCanRead() || isPublic())
834       return false;
835     if (getCanWrite() && getFlag(IS_UNKNOWN))
836       return false;
837     if (! getCanCall())
838       return true;
839     Expression value = getValue();
840     if (value == null || ! (value instanceof LambdaExp))
841       return false;
842     LambdaExp lexp = (LambdaExp) value;
843     return lexp.getInlineOnly();
844   }
845 
isStatic()846   public boolean isStatic()
847   {
848     if (getField() != null)
849       return getField().getStaticFlag();
850     if (getFlag(STATIC_SPECIFIED)
851         || isCompiletimeConstant())
852       return true;
853     if (getFlag(NONSTATIC_SPECIFIED))
854       return false;
855     LambdaExp lambda = context.currentLambda();
856     return lambda instanceof ModuleExp
857       && ((ModuleExp) lambda).isStatic();
858   }
859 
isLexical()860   public final boolean isLexical()
861   {
862     return (flags & (IS_FLUID|IS_DYNAMIC|IS_UNKNOWN)) == 0;
863   }
864 
isUnknown(Declaration decl)865   public static final boolean isUnknown (Declaration decl)
866   {
867     return decl == null || decl.getFlag(IS_UNKNOWN);
868   }
869 
870   int numReferences;
871 
872   /** List of ApplyExp where this declaration is the function called.
873    * The applications are chained using their nextCall fields.
874    * This is list is built twice:
875    * First in PushApply (for use during InlineCalls),
876    * then the list is clearest, then rebuilt in FindTailCalls.
877    * This is because InlineCalls may inline and re-arrange the call graph.
878    * The chain is not built the second time if STATIC_SPECIFIED. */
879   public ApplyExp firstCall;
880 
881   /** Add a call to the list headed by {@code firstCall}. */
addCaller(ApplyExp exp)882   public void addCaller (ApplyExp exp)
883   {
884     exp.nextCall = firstCall;
885     firstCall = exp;
886   }
887 
888   /** Clear the list of callers headed by {@code firstCall}. */
clearCallList()889   public void clearCallList ()
890   {
891     for (ApplyExp exp = firstCall; exp != null; )
892       {
893         ApplyExp next = exp.nextCall;
894         exp.nextCall = null;
895         exp = next;
896       }
897     firstCall = null;
898   }
899 
Declaration(Object name, Type type)900   public Declaration (Object name, Type type)
901   {
902     setName(name);
903     if (type != null)
904       setType(type);
905   }
906 
Declaration(Variable var)907   public Declaration (Variable var)
908   {
909     this(var.getName(), var.getType());
910     this.var = var;
911   }
912 
Declaration(Object name)913   public Declaration (Object name)
914   {
915     this(name, (Type) null);
916   }
917 
Declaration(Object name, Field field)918   public Declaration (Object name, Field field)
919   {
920     this(name, field.getType());
921     this.field = field;
922     setSimple(false);
923   }
924 
925   List<Expression> annotations;
926 
927   /** The number of annotations associated with the declaration. */
numAnnotations()928   public int numAnnotations ()
929   {
930     return annotations == null ? 0 : annotations.size();
931   }
932 
933   /** Indexed get of one of the annotations associated with this declaration. */
getAnnotation(int i)934   public Expression getAnnotation (int i)
935   {
936     return annotations.get(i);
937   }
938 
939     public <T extends java.lang.annotation.Annotation>
getAnnotation(Class<T> clas)940     T getAnnotation(Class<T> clas) {
941         int n = numAnnotations();
942         for (int i = 0;  i < n;  i++) {
943             Object ann = getAnnotation(i).valueIfConstant();
944             if (clas.isInstance(ann))
945                 return (T) ann;
946         }
947         return null;
948     }
949 
getAnnotation(String className)950     public AnnotationEntry getAnnotation(String className) {
951         int n = numAnnotations();
952         for (int i = 0;  i < n;  i++) {
953             Object ann = getAnnotation(i).valueIfConstant();
954             if (ann instanceof AnnotationEntry) {
955                 AnnotationEntry ae =
956                     (AnnotationEntry) Proxy.getInvocationHandler(ann);
957                 if (className.equals(ae.getAnnotationType())) {
958                     return ae;
959                 }
960             }
961         }
962         return null;
963     }
964 
965   /** Replace one of the annotations associated with this declaration. */
setAnnotation(int i, Expression ann)966   public void setAnnotation (int i, Expression ann)
967   {
968     annotations.set(i, ann);
969   }
970 
971   /** Add an annotation to the set of our annotations.
972    * @param exp A constant-valued expression that evaluates to an Annotation.
973    */
addAnnotation(Expression exp)974   public void addAnnotation (Expression exp)
975   {
976     if (annotations == null)
977       annotations = new ArrayList<Expression>();
978     annotations.add(exp);
979   }
980 
compileAnnotations(AttrContainer container, ElementType etype)981   public void compileAnnotations (AttrContainer container, ElementType etype)
982   {
983     if (container == null)
984       return;
985     int n = numAnnotations();
986     for (int i = 0;  i < n;  i++)
987       {
988         Object ann = getAnnotation(i).valueIfConstant();
989         if (ann != null)
990           {
991             AnnotationEntry ae = (AnnotationEntry) Proxy.getInvocationHandler(ann);
992             if (container != null && ae.hasTarget(etype))
993               RuntimeAnnotationsAttr.maybeAddAnnotation(container, ae);
994           }
995       }
996   }
997 
998   Method makeLocationMethod = null;
999 
1000   /** Create a Location object, given that isIndirectBinding().
1001       Assume the initial value is already pushed on the stack;
1002       leaves initialized Location object on stack.  */
pushIndirectBinding(Compilation comp)1003   public void pushIndirectBinding (Compilation comp)
1004   {
1005     CodeAttr code = comp.getCode();
1006     code.emitPushString(getName());
1007     if (makeLocationMethod == null)
1008       {
1009 	Type[] args = new Type[2];
1010 	args[0] = Type.pointer_type;
1011 	args[1] = Type.string_type;
1012 	makeLocationMethod
1013 	  = Compilation.typeLocation.addMethod("make", args,
1014 					      Compilation.typeLocation,
1015 					      Access.PUBLIC|Access.STATIC);
1016       }
1017     code.emitInvokeStatic(makeLocationMethod);
1018   }
1019 
allocateVariable(CodeAttr code)1020   public final Variable allocateVariable(CodeAttr code)
1021   {
1022     return allocateVariable(code, false);
1023   }
allocateVariable(CodeAttr code, boolean autoPopScope)1024   public final Variable allocateVariable(CodeAttr code, boolean autoPopScope)
1025   {
1026     if (! isSimple() || var == null)
1027       {
1028         String vname = null;
1029         if (symbol != null)
1030           vname = Mangling.mangleVariable(getName());
1031 	if (isAlias() && getValue() instanceof ReferenceExp)
1032 	  {
1033 	    Declaration base = followAliases(this);
1034 	    var = base == null ? null : base.var;
1035 	  }
1036 	else
1037 	  {
1038             Type type = getImplementationType();
1039             Scope scope = autoPopScope ? code.pushAutoPoppableScope()
1040                 : context.getVarScope();
1041 	    var = scope.addVariable(code, type, vname);
1042 	  }
1043       }
1044     return var;
1045   }
1046 
getImplementationType()1047     public Type getImplementationType() {
1048         Type ftype = getType().getImplementationType();
1049         if (isIndirectBinding() && ! ftype.isSubtype(Compilation.typeLocation)) {
1050             if (ftype == null || ftype == Type.objectType)
1051                 ftype = Compilation.typeLocation;
1052             else {
1053                 if (ftype instanceof PrimType)
1054                     ftype = ((PrimType) ftype).boxedType();
1055                 ftype = new ParameterizedType(Compilation.typeLocation, ftype);
1056             }
1057         }
1058         int scan = getScanNesting();
1059         if (scan > 0 && ! (type instanceof MappedArrayType)) {
1060             while (--scan >= 0)
1061                 ftype =  new ParameterizedType(Compilation.typeList, ftype);
1062         }
1063         return ftype;
1064     }
1065 
printInfo(OutPort out)1066   public void printInfo(OutPort out)
1067   {
1068     StringBuffer sbuf = new StringBuffer();
1069     printInfo(sbuf);
1070     out.startLogicalBlock("", "", 2);
1071     out.print(sbuf.toString());
1072     int numAnnotations = numAnnotations();
1073     if (numAnnotations > 0)
1074       {
1075         out.writeSpaceLinear();
1076         out.print("Annotations:");
1077         for (int i = 0;  i < numAnnotations;  i++)
1078           {
1079             out.writeSpaceLinear();
1080             annotations.get(i).print(out);
1081           }
1082       }
1083     out.endLogicalBlock("");
1084   }
1085 
printInfo(StringBuffer sbuf)1086   public void printInfo(StringBuffer sbuf)
1087   {
1088     sbuf.append(symbol);
1089     if (true || // DEBUGGING
1090         symbol == null)
1091       ;
1092     else if (symbol instanceof SimpleSymbol)
1093       sbuf.append("[simple-symbol]");
1094     else if (symbol instanceof Symbol)
1095       sbuf.append("[symbol]");
1096     else if (symbol.toString().intern() == symbol)
1097       sbuf.append("[interned-string]");
1098     else if (symbol instanceof String)
1099       sbuf.append("[noninterned-string]");
1100     sbuf.append('#');
1101     sbuf.append(id);
1102     /*
1103     int line = getLineNumber();
1104     if (line != 0)
1105       {
1106 	sbuf.append("/line:");
1107 	sbuf.append(line);
1108 	int column = getColumnNumber();
1109 	if (column != 0)
1110 	  {
1111 	    sbuf.append(':');
1112 	    sbuf.append(column);
1113 	  }
1114       }
1115     */
1116     sbuf.append("/fl:");
1117     sbuf.append(Long.toHexString(flags));
1118     if (ignorable())
1119       sbuf.append("(ignorable)");
1120     Expression tx = typeExp;
1121     Type t = type;
1122     if (tx != null && ! (tx instanceof QuoteExp))
1123       {
1124 	sbuf.append("::");
1125         sbuf.append(tx);
1126       }
1127     else if (t != null && t != Type.pointer_type)
1128       {
1129 	sbuf.append("::");
1130 	sbuf.append(t.getName());
1131       }
1132     if (base != null)
1133       {
1134         sbuf.append("(base:#");
1135         sbuf.append(base.id);
1136         sbuf.append(')');
1137       }
1138   }
1139 
1140 
toString()1141   public String toString()
1142   {
1143     return "Declaration["+symbol+'#'+id+']';
1144     /*
1145     StringBuffer sbuf = new StringBuffer();
1146     sbuf.append("Declaration[");
1147     printInfo(sbuf);
1148     sbuf.append(']');
1149     return sbuf.toString();
1150     */
1151   }
1152 
followAliases(Declaration decl)1153   public static Declaration followAliases (Declaration decl)
1154   {
1155     while (decl != null && decl.isAlias())
1156       {
1157 	Expression declValue = decl.getValue();
1158 	if (! (declValue instanceof ReferenceExp))
1159 	  break;
1160 	ReferenceExp rexp = (ReferenceExp) declValue;
1161 	Declaration orig = rexp.binding;
1162 	if (orig == null)
1163 	  break;
1164 	decl = orig;
1165       }
1166     return decl;
1167   }
1168 
makeField(Compilation comp, Expression value)1169   public void makeField(Compilation comp, Expression value)
1170   {
1171     setSimple(false);
1172     makeField(comp.mainClass, comp, value);
1173   }
1174 
makeField(ClassType frameType, Compilation comp, Expression value)1175   public void makeField(ClassType frameType, Compilation comp, Expression value)
1176   {
1177     boolean external_access = needsExternalAccess();
1178     int fflags = 0;
1179     boolean isConstant = getFlag(IS_CONSTANT);
1180     boolean typeSpecified = getFlag(TYPE_SPECIFIED);
1181     // In immediate mode we may need to access the field from a future
1182     // command in a different "runtime package" (see JVM spec) because it
1183     // gets loaded by a different class loader.  So make the field public.
1184     if (isPublic() || external_access || comp.immediate) {
1185         fflags |= Access.PUBLIC;
1186         // FIXME do setIndirectBinding even if it's constant,
1187         // as long as just a define-constant or ! and not a class or alias
1188         if (comp.isInteractive() && context == comp.getModule()
1189             && ! isConstant)
1190             setIndirectBinding(true);
1191     }
1192     if (isStatic()
1193         // "Dynamic" variables use ThreadLocation, based on the current
1194         // Environment, so we don't need more than one static field.
1195         || (getFlag(Declaration.IS_UNKNOWN
1196                     |Declaration.IS_DYNAMIC|Declaration.IS_FLUID)
1197             && isIndirectBinding() && ! isAlias())
1198 	|| (value instanceof ClassExp
1199 	    && ! ((LambdaExp) value).getNeedsClosureEnv()))
1200       fflags |= Access.STATIC;
1201     if ((isIndirectBinding()
1202          || (isConstant
1203              && (shouldEarlyInit()
1204                  || (context instanceof ModuleExp && ((ModuleExp) context).staticInitRun()))))
1205         && (context instanceof ClassExp || context instanceof ModuleExp))
1206       fflags |= Access.FINAL;
1207     Type ftype = getImplementationType();
1208     if (! ignorable())
1209       {
1210         String dname = getName();
1211         String fname = dname;
1212         boolean haveName = fname != null;
1213         int nlength;
1214         if (fname==null)
1215           {
1216             fname = "$unnamed$0";
1217             nlength = fname.length() - 2; // Without the "$0".
1218           }
1219         else
1220           {
1221             fname = Mangling.mangleField(fname);
1222             if (getFlag(IS_UNKNOWN))
1223               {
1224                 fname = UNKNOWN_PREFIX + fname;
1225                 haveName = false;
1226               }
1227             if (external_access && ! getFlag(Declaration.MODULE_REFERENCE))
1228               {
1229                 fname = PRIVATE_PREFIX + fname;
1230                 haveName = false;
1231               }
1232            nlength = fname.length();
1233           }
1234         int counter = 0;
1235         while (frameType.getDeclaredField(fname) != null)
1236           fname = fname.substring(0, nlength) + '$' + (++ counter);
1237             setField(frameType.addField (fname, ftype, fflags));
1238         if (getAnnotation(kawa.SourceType.class) == null) {
1239             String encType = comp.getLanguage().encodeType(getType());
1240             if (encType != null && encType.length() > 0) {
1241                 AnnotationEntry ae = new AnnotationEntry(ClassType.make("kawa.SourceType"));
1242                 ae.addMember("value", encType, Type.javalangStringType);
1243                 RuntimeAnnotationsAttr.maybeAddAnnotation(getField(), ae);
1244             }
1245         }
1246         if (haveName)
1247           {
1248               this.maybeSourceName(getField(), Mangling.demangleField(fname));
1249           }
1250         if (value instanceof QuoteExp)
1251           {
1252             Object val = ((QuoteExp) value).getValue();
1253             if (getField().getStaticFlag()
1254                 && val != null
1255                 && val.getClass().getName().equals(ftype.getName()))
1256               {
1257                 Literal literal = comp.litTable.findLiteral(val);
1258                 if (literal.field == null)
1259                   literal.assign(getField(), comp.litTable);
1260               }
1261             else if (ftype instanceof PrimType
1262                      || "java.lang.String".equals(ftype.getName()))
1263               {
1264                 if (val instanceof gnu.text.Char)
1265                   val = gnu.math.IntNum.make(((gnu.text.Char) val).intValue());
1266                 getField().setConstantValue(val, frameType);
1267                 return;
1268               }
1269           }
1270       }
1271     // The EARLY_INIT case is handled in SetExp.compile.
1272     if (! shouldEarlyInit()
1273         && context instanceof ModuleExp
1274 	&& (isIndirectBinding()
1275 	    || (value != null && ! (value instanceof ClassExp))))
1276       {
1277 	BindingInitializer.create(this, value, comp);
1278       }
1279   }
1280 
1281     /** Add SourceName annotation to member, if needed.
1282      */
maybeSourceName(AttrContainer member, String expName)1283     public void maybeSourceName(AttrContainer member, String expName) {
1284         Object fsymbol = getSymbol();
1285         String dname = getName();
1286         String uri, prefix;
1287         boolean haveUri, havePrefix;
1288         // If name is a non-simple Symbol (i.e. with uri or prefix)
1289         // or the field name doesn't demangle to name, then emit
1290         // a SourceName annotation so we can recover the correct name.
1291         if (fsymbol instanceof Symbol) {
1292             uri = ((Symbol) fsymbol).getNamespaceURI();
1293             prefix = ((Symbol) fsymbol).getPrefix();
1294             if (uri == null)
1295                 uri = "";
1296             haveUri = ! "".equals(uri);
1297             havePrefix = ! "".equals(prefix);
1298         } else {
1299             uri = prefix = "";
1300             haveUri = havePrefix = false;
1301         }
1302         // FIXME should optimize if uri == module.getNamespaceUri()
1303         if (haveUri || havePrefix
1304             || expName == null || ! expName.equals(dname)) {
1305             AnnotationEntry ae = new AnnotationEntry(ClassType.make("gnu.expr.SourceName"));
1306             ae.addMember("name", dname, Type.javalangStringType);
1307             if (haveUri)
1308                 ae.addMember("uri", uri, Type.javalangStringType);
1309             if (havePrefix)
1310                 ae.addMember("prefix", prefix, Type.javalangStringType);
1311             RuntimeAnnotationsAttr.maybeAddAnnotation(member, ae);
1312         }
1313     }
1314 
1315   /* Used when evaluating for an indirect binding. */
makeIndirectLocationFor()1316   gnu.mapping.Location makeIndirectLocationFor ()
1317   {
1318     Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
1319       : Namespace.EmptyNamespace.getSymbol(symbol.toString().intern());
1320     return gnu.mapping.Location.make(sym);
1321   }
1322 
1323   /** Create a declaration corresponding to a static field.
1324    * @param cname name of class containing field
1325    * @param fname name of static field
1326    */
1327   public static Declaration
getDeclarationFromStatic(String cname, String fname)1328   getDeclarationFromStatic (String cname, String fname)
1329   {
1330     ClassType clas = ClassType.make(cname);
1331     Field fld = clas.getDeclaredField(fname);
1332     Declaration decl = new Declaration(fname, fld);
1333     decl.setFlag(Declaration.IS_CONSTANT|Declaration.STATIC_SPECIFIED);
1334     return decl;
1335   }
1336 
1337   /** Similar to {@code getDeclarationFromStatic},
1338    * but also do {@code noteValue} with the field's value.
1339    */
1340   public static Declaration
getDeclarationValueFromStatic(String className, String fieldName, String name)1341   getDeclarationValueFromStatic (String className,
1342                                  String fieldName, String name)
1343   {
1344     try
1345       {
1346 	Class cls = Class.forName(className);
1347 	java.lang.reflect.Field fld = cls.getDeclaredField(fieldName);
1348 	Object value = fld.get(null);
1349 
1350 	Declaration decl
1351           = new Declaration(name,
1352                             ClassType.make(className)
1353                             .getDeclaredField(fieldName));
1354 	decl.noteValue(new QuoteExp(value));
1355 	decl.setFlag(Declaration.IS_CONSTANT|Declaration.STATIC_SPECIFIED);
1356         return decl;
1357       }
1358     catch (Exception ex)
1359       {
1360 	throw new WrappedException(ex);
1361       }
1362   }
1363 
getDeclaration(Named proc)1364   public static Declaration getDeclaration(Named proc)
1365   {
1366     return getDeclaration(proc, proc.getName());
1367   }
1368 
getDeclaration(Object proc, String name)1369   public static Declaration getDeclaration(Object proc, String name)
1370   {
1371     gnu.bytecode.Field procField = null;
1372     if (name != null)
1373       {
1374         /*
1375         // This is a way to map from the Procedure's name to a Field,
1376         // by assuming the name as the form "classname:fieldname".
1377         // It may be better to use names of the form "{classname}fieldname".
1378         // For now we don't need this feature.
1379         int colon = name.indexOf(':');
1380         if (colon > 0)
1381           {
1382             try
1383               {
1384                 ClassType procType
1385                   = (ClassType) ClassType.make(name.substring(0, colon));
1386                 name = name.substring(colon+1);
1387                 String fname = Mangling.mangleField(name);
1388                 procField = procType.getDeclaredField(fname);
1389               }
1390             catch (Exception ex)
1391               {
1392                 System.err.println("CAUGHT "+ex+" in getDeclaration for "+proc);
1393                 return null;
1394               }
1395           }
1396         else
1397         */
1398           {
1399             Class procClass = PrimProcedure.getProcedureClass(proc);
1400             if (procClass != null)
1401               {
1402                 ClassType procType = (ClassType) Type.make(procClass);
1403                 String fname = Mangling.mangleField(name);
1404                 procField = procType.getDeclaredField(fname);
1405               }
1406           }
1407       }
1408     if (procField != null)
1409       {
1410         int fflags = procField.getModifiers();
1411         if ((fflags & Access.STATIC) != 0)
1412           {
1413             Declaration decl = new Declaration(name, procField);
1414             decl.noteValue(new QuoteExp(proc));
1415             if ((fflags & Access.FINAL) != 0)
1416               decl.setFlag(Declaration.IS_CONSTANT);
1417             return decl;
1418           }
1419       }
1420     return null;
1421   }
1422 
1423   /** Get the "initial value" expression.
1424    * This is used for the initializing value in a LetExp,
1425    * a parameter's default value, or for pattern-matching.
1426    */
getInitValue()1427   public Expression getInitValue() { return initValue; }
setInitValue(Expression init)1428   public void setInitValue(Expression init) { this.initValue = init; }
1429   private Expression initValue;
1430 
1431   ValueSource values[];
1432   int nvalues;
1433   static final ValueSource unknownValueInstance =
1434     new ValueSource(ValueSource.UNKNOWN_KIND, null, 0);
1435   static final ValueSource[] unknownValueValues = { unknownValueInstance };
1436 
hasUnknownValue()1437   public boolean hasUnknownValue () { return values == Declaration.unknownValueValues; }
1438 
1439   /** The value of this <code>Declaration</code>, if known.
1440    * Usually the expression used to initialize the <code>Declaration</code>,
1441    * or null if the <code>Declaration</code> can be assigned a different
1442    * value after initialization.  Note that this is the semantic value: If the
1443    * <code>INDIRECT_LOCATION</code> is set, then <code>getValue</code> is the
1444    * value <em>after</em> de-referencing the resulting <code>Location</code>.
1445    * An exception is if <code>isAlias()</code>; in that case
1446    * <code>getValue()</code> is an expression yielding a <code>Location</code>
1447    * which needs to be de-referenced to get this <code>Declaration</code>'s
1448    * actual value.
1449    */
getValue()1450   public final Expression getValue()
1451   {
1452     if (nvalues == 0)
1453       {
1454         if (getField() != null
1455             && getField().getDeclaringClass().isExisting()
1456             && ((getField().getModifiers() & Access.STATIC+Access.FINAL)
1457                 == Access.STATIC+Access.FINAL)
1458             && ! isIndirectBinding())
1459           {
1460             try
1461               {
1462                 Expression value = new QuoteExp(getField().getReflectField().get(null));
1463                 noteValue(value);
1464                 return value;
1465               }
1466             catch (Exception ex)
1467               {
1468               }
1469           }
1470         return QuoteExp.undefined_exp;
1471       }
1472     if (nvalues == 1)
1473       return values[0].getValue(this);
1474     return null;
1475   }
1476 
getValueRaw()1477   public Expression getValueRaw ()
1478   {
1479     if (nvalues == 0)
1480       return QuoteExp.undefined_exp;
1481     if (nvalues == 1)
1482       return values[0].getValue(this);
1483     return null;
1484   }
1485 
1486   /** Set the value associated with this Declaration.
1487    * Most code should use noteValue instead. */
setValue(Expression value)1488   public final void setValue(Expression value)
1489   {
1490     values = null;
1491     nvalues = 0;
1492     noteValue(value);
1493   }
1494 
1495   /** If getValue() is a constant, return the constant value, otherwise null. */
getConstantValue()1496   public final Object getConstantValue()
1497   {
1498     Object v = getValue();
1499     if (! (v instanceof QuoteExp) || v == QuoteExp.undefined_exp)
1500       return null;
1501     return ((QuoteExp) v).getValue();
1502   }
1503 
hasConstantValue()1504   public final boolean hasConstantValue ()
1505   {
1506     Object v = getValue();
1507     return (v instanceof QuoteExp) && v != QuoteExp.undefined_exp;
1508   }
1509 
getLambdaValue()1510   public LambdaExp getLambdaValue ()
1511   {
1512     if (! isAlias() && nvalues == 1)
1513       {
1514         Expression val = values[0].getValue(this);
1515         if (val != null && val.getClass() == LambdaExp.class)
1516           return (LambdaExp) val;
1517       }
1518     return null;
1519   }
1520 
noteValue(Expression value)1521   public void noteValue (Expression value)
1522   {
1523     checkNameDecl(value);
1524     if (value == null)
1525       noteValueUnknown();
1526     else if (values != unknownValueValues)
1527       noteValue(new ValueSource(ValueSource.GENERAL_KIND, value, 0));
1528   }
1529 
noteValue(ValueSource value)1530   void noteValue (ValueSource value)
1531   {
1532     if (values == unknownValueValues)
1533       throw new InternalError();
1534     if (values == null)
1535       values = new ValueSource[4];
1536     else if (nvalues >= values.length)
1537       {
1538         ValueSource[] tmp = new ValueSource[2 * nvalues];
1539         System.arraycopy(values, 0, tmp, 0, nvalues);
1540         values = tmp;
1541       }
1542     values[nvalues++] = value;
1543   }
1544 
noteValueConstant(Object value)1545   public void noteValueConstant (Object value)
1546   {
1547     if (values != unknownValueValues)
1548       {
1549         noteValue(new QuoteExp(value));
1550       }
1551   }
1552 
noteValueUnknown()1553   public void noteValueUnknown ()
1554   {
1555     checkNameDecl(null);
1556     values = unknownValueValues;
1557     nvalues = 1;
1558   }
1559 
noteValueFromSet(SetExp setter)1560   public void noteValueFromSet (SetExp setter)
1561   {
1562     if (values != unknownValueValues)
1563       {
1564         checkNameDecl(setter.new_value);
1565         setter.valueIndex = nvalues;
1566         noteValue(new ValueSource(ValueSource.SET_RHS_KIND, setter, 0));
1567       }
1568   }
1569 
noteValueFromLet(ScopeExp letter)1570   public void noteValueFromLet (ScopeExp letter)
1571   {
1572     Expression init = getInitValue();
1573     if (init != QuoteExp.undefined_exp && values != unknownValueValues)
1574       {
1575         checkNameDecl(init);
1576         noteValue(new ValueSource(ValueSource.LET_INIT_KIND, letter, 0));
1577       }
1578   }
1579 
noteValueFromApply(ApplyExp app, int index)1580   public void noteValueFromApply (ApplyExp app, int index)
1581   {
1582     if (values != unknownValueValues)
1583       noteValue(new ValueSource(ValueSource.APPLY_KIND, app, index));
1584   }
1585 
1586     /** Set symbol from initializing SetExp.
1587      * Used for an export-only alias, for handling export-with-rename.
1588      */
patchSymbolFromSet()1589     public boolean patchSymbolFromSet() {
1590         if (nvalues != 1 || values[0].kind != ValueSource.SET_RHS_KIND)
1591             return false;
1592         SetExp sexp = (SetExp) values[0].base;
1593         setSymbol(((SetExp) values[0].base).getSymbol());
1594         return true;
1595     }
1596 
checkNameDecl(Expression value)1597     private void checkNameDecl(Expression value) {
1598         if (nvalues == 1) {
1599             Expression old = values[0].getValue(this);
1600             if (old == value)
1601                 return;
1602             if (old instanceof LambdaExp)
1603                 ((LambdaExp) old).nameDecl = null;
1604         }
1605         if (value instanceof LambdaExp)
1606             ((LambdaExp) value).nameDecl = nvalues == 0 ? this : null;
1607     }
1608 
getField()1609     public Field getField() { return field; }
setField(Field field)1610     public void setField(Field field) { this.field = field; }
1611 
1612   public static class ValueSource
1613   {
1614     static final int UNKNOWN_KIND = 0;
1615     static final int GENERAL_KIND = 1;
1616     static final int SET_RHS_KIND = 2;
1617     static final int LET_INIT_KIND = 3;
1618     static final int APPLY_KIND = 4;
1619     public int kind;
1620     public Expression base;
1621     public int index;
1622 
ValueSource(int kind, Expression base, int index)1623     ValueSource (int kind, Expression base, int index)
1624     {
1625       this.kind = kind;
1626       this.base = base;
1627       this.index = index;
1628     }
1629 
getValue(Declaration decl)1630     Expression getValue (Declaration decl)
1631     {
1632       switch (kind)
1633         {
1634         case UNKNOWN_KIND:
1635           return null;
1636         case GENERAL_KIND:
1637           return base;
1638         case SET_RHS_KIND:
1639           return ((SetExp) base).new_value;
1640         case LET_INIT_KIND:
1641           return decl.getInitValue();
1642         case APPLY_KIND:
1643           ApplyExp app = (ApplyExp) base;
1644           int i = index;
1645           // If a function is called via an apply-function, the latter
1646           // might distribute a multiple-valued argument among multiple
1647           // parameters.  Punt on that for now.
1648           Compilation comp = Compilation.getCurrent();
1649           Expression afunc = app.getFunction();
1650           if (comp.isSimpleApplyFunction(afunc))
1651               i++;
1652           else if (comp.isApplyFunction(afunc))
1653               return null;
1654           if (i >= app.getArgCount())
1655               return null;
1656           return app.getArg(i);
1657         default:
1658           throw new Error();
1659         }
1660     }
1661   }
1662 }
1663