KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > expr > Declaration


1 // Copyright (c) 2003 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.mapping.*;
7 import gnu.text.SourceLocator;
8
9 /**
10  * The static information associated with a local variable binding.
11  * @author Per Bothner
12  *
13  * These are the kinds of Declaration we use:
14  *
15  * A local variable that is not captured by an inner lambda is stored
16  * in a Java local variables slot (register). The predicate isSimple ()
17  * is true, and offset is the number of the local variable slot.
18  *
19  * If a local variable is captured by an inner lambda, the
20  * variable is stored in a field of the LambdaExp's heapFrame variable.
21  * (The latter declaration has isSimple and isArtificial true.)
22  * The Declaration's field specifies the Field used.
23  *
24  * If a function takes a fixed number of parameters, at most four,
25  * then the arguments are passed in Java registers 1..4.
26  * If a parameter is not captured by an inner lambda, the parameter
27  * has the flags isSimple and isParameter true.
28  *
29  * If a function takes more than 4 or a variable number of parameters,
30  * the arguments are passed in an array (using the applyN virtual method).
31  * This array is referenced by the argsArray declaration, which has
32  * isSimple(), isParameter(), and isArtificial() true, and its offset is 1.
33  * The parameters are copied into the program-named variables by the
34  * procedure prologue, so the parameters henceforth act like local variables.
35  */

36
37 public class Declaration
38   implements SourceLocator
39 {
40   static int counter;
41   /** Unique id number, to ease print-outs and debugging.
42    * If negative, a code to specify a builtin function. */

43   protected int id = ++counter;
44
45   /** The name of the new variable, either an interned String or a Symbol.
46    * This is the source-level (non-mangled) name. */

47   Object JavaDoc symbol;
48
49   public void setCode (int code)
50   {
51     if (code >= 0) throw new Error JavaDoc("code must be negative");
52     this.id = code;
53   }
54
55   public int getCode () { return id; }
56
57   public ScopeExp context;
58
59   protected Type type;
60   protected Expression typeExp;
61   public final Expression getTypeExp() { return typeExp; }
62   public final Type getType() { return type; }
63   public final void setType(Type type)
64   {
65     this.type = type;
66     if (var != null) var.setType(type);
67     typeExp = QuoteExp.getInstance(type);
68   }
69
70   public final void setTypeExp (Expression typeExp)
71   {
72     this.typeExp = typeExp;
73     Object JavaDoc typeValue;
74     Type t = (typeExp instanceof QuoteExp
75               && (typeValue = ((QuoteExp) typeExp).getValue()) instanceof Type
76               ? (Type) typeValue
77               : typeExp instanceof TypeValue
78               ? ((TypeValue) typeExp).getImplementationType()
79               : (Type) Type.pointer_type);
80     this.type = t;
81     if (var != null) var.setType(t);
82   }
83
84   public final String JavaDoc getName()
85   {
86     return symbol == null ? null : symbol instanceof Symbol ? ((Symbol) symbol).getName()
87       : symbol.toString();
88   }
89   public final void setName(Object JavaDoc symbol)
90   {
91     this.symbol = symbol;
92   }
93
94   public final Object JavaDoc getSymbol() { return symbol; }
95   public final void setSymbol(Object JavaDoc symbol) { this.symbol = symbol; }
96
97   /* Declarations in a ScopeExp are linked together in a linked list. */
98   Declaration next;
99
100   public final Declaration nextDecl() { return next; }
101   public final void setNext(Declaration next) { this.next = next; }
102
103   /** Index in evalFrame for this scope, if interpreting. */
104   int evalIndex;
105
106   Variable var;
107   public Variable getVariable() { return var; }
108
109   public final boolean isSimple()
110   { return (flags & IS_SIMPLE) != 0; }
111
112   public final void setSimple(boolean b)
113   {
114     setFlag(b, IS_SIMPLE);
115     if (var != null && ! var.isParameter()) var.setSimple(b);
116   }
117
118   public final void setSyntax ()
119   {
120     setSimple(false);
121     setFlag(Declaration.IS_CONSTANT | Declaration.IS_SYNTAX);
122   }
123
124   /** Return the ScopeExp that contains (declares) this Declaration. */
125   public final ScopeExp getContext() { return context; }
126
127   /** Used to link Declarations in a LambdaExp's capturedVars list. */
128   Declaration nextCapturedVar;
129
130   /** If non-null, field is relative to base.
131    * If IS_FLUID, base points to IS_UNKNOWN Symbol. */

132   public Declaration base;
133
134   public Field field;
135
136   /** If this is a field in some object, load a reference to that object. */
137   void loadOwningObject (Declaration owner, Compilation comp)
138   {
139     if (owner == null)
140       owner = base;
141     if (owner != null)
142       owner.load(null, 0, comp, Target.pushObject);
143     else
144       getContext().currentLambda().loadHeapFrame(comp);
145   }
146
147   public void load (AccessExp access, int flags,
148                     Compilation comp, Target target)
149   {
150     if (target instanceof IgnoreTarget)
151       return;
152     Declaration owner = access == null ? null : access.contextDecl();
153     if (isAlias() && value instanceof ReferenceExp)
154       {
155         ReferenceExp rexp = (ReferenceExp) value;
156         Declaration orig = rexp.binding;
157         if (orig != null
158             && ((flags & ReferenceExp.DONT_DEREFERENCE) == 0
159                 || orig.isIndirectBinding())
160             && (owner == null || ! orig.needsContext()))
161           {
162             orig.load(rexp, flags, comp, target);
163             return;
164           }
165       }
166     CodeAttr code = comp.getCode();
167     Type rtype = getType();
168     if ((flags & ReferenceExp.CREATE_FIELD_REFERENCE) != 0)
169       {
170         if (field == null)
171           throw new Error JavaDoc("internal error: cannot take location of "+this);
172         Method meth;
173         ClassType ltype;
174         boolean immediate = comp.immediate;
175         if (field.getStaticFlag())
176           {
177             ltype = ClassType.make("gnu.kawa.reflect.StaticFieldLocation");
178             meth = ltype.getDeclaredMethod("make", immediate ? 1 : 2);
179           }
180         else
181           {
182             ltype = ClassType.make("gnu.kawa.reflect.FieldLocation");
183             meth = ltype.getDeclaredMethod("make", immediate ? 2 : 3);
184
185             loadOwningObject(owner, comp);
186           }
187         if (immediate)
188           comp.compileConstant(this);
189         else
190           {
191             comp.compileConstant(field.getDeclaringClass().getName());
192             comp.compileConstant(field.getName());
193           }
194         code.emitInvokeStatic(meth);
195         rtype = ltype;
196       }
197     else
198       {
199         Object JavaDoc val;
200         if (field != null)
201           {
202             comp.usedClass(field.getDeclaringClass());
203             if (! field.getStaticFlag())
204               {
205                 loadOwningObject(owner, comp);
206                 code.emitGetField(field);
207               }
208             else
209               code.emitGetStatic(field);
210           }
211         else if (isIndirectBinding() && comp.immediate && getVariable() == null)
212           {
213             // This is a bit of a kludge. See comment in ModuleExp.evalModule.
214
Environment env = Environment.getCurrent();
215             Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
216               : env.getSymbol(symbol.toString());
217             Object JavaDoc property = null;
218             if (isProcedureDecl()
219                 && comp.getLanguage().hasSeparateFunctionNamespace())
220               property = EnvironmentKey.FUNCTION;
221             gnu.mapping.Location loc = env.getLocation(sym, property);
222             comp.compileConstant(loc, Target.pushValue(Compilation.typeLocation));
223           }
224         else if (comp.immediate && (val = getConstantValue()) != null)
225           {
226             comp.compileConstant(val, target);
227             return;
228           }
229         else
230           {
231             Variable var = getVariable();
232             ClassExp cl;
233             if (context instanceof ClassExp && var == null
234                 && ! getFlag(PROCEDURE)
235                 && (cl = (ClassExp) context).isMakingClassPair())
236               {
237                 String JavaDoc getName = ClassExp.slotToMethodName("get", getName());
238                 Method getter = cl.type.getDeclaredMethod(getName, 0);
239                 cl.loadHeapFrame(comp);
240                 code.emitInvoke(getter);
241               }
242             else
243               {
244                 if (var == null)
245                   var = allocateVariable(code);
246                 code.emitLoad(var);
247               }
248           }
249         if (isIndirectBinding()
250             && (flags & ReferenceExp.DONT_DEREFERENCE) == 0)
251           {
252
253             String JavaDoc filename;
254             int line;
255             if (access != null
256                 && (filename = access.getFileName()) != null
257                 && (line = access.getLineNumber()) > 0)
258               {
259                 // Wrap call to Location.get by a catch handler that
260
// calls setLine on the UnboundLocationException.
261
ClassType typeUnboundLocationException
262                   = ClassType.make("gnu.mapping.UnboundLocationException");
263                 // See comment in CheckedTarget.emitCheckedCoerce.
264
boolean isInTry = code.isInTry();
265                 int column = access.getColumnNumber();
266                 Label startTry = new Label(code);
267                 startTry.define(code);
268                 code.emitInvokeVirtual(Compilation.getLocationMethod);
269                 Label endTry = new Label(code);
270                 endTry.define(code);
271                 Label endLabel = new Label(code);
272                 if (isInTry)
273                   code.emitGoto(endLabel);
274                 int fragment_cookie = 0;
275                 if (! isInTry)
276                   fragment_cookie
277                     = code.beginFragment(new Label(code), endLabel);
278                 code.addHandler(startTry, endTry, typeUnboundLocationException);
279
280                 code.pushType(typeUnboundLocationException);
281                 code.emitDup(typeUnboundLocationException);
282                 code.emitPushString(filename);
283                 code.emitPushInt(line);
284                 code.emitPushInt(column);
285                 code.emitInvokeVirtual(typeUnboundLocationException
286                                        .getDeclaredMethod("setLine", 3));
287                 code.emitThrow();
288                 if (isInTry)
289                   endLabel.define(code);
290                 else
291                   code.endFragment(fragment_cookie);
292               }
293             else
294               code.emitInvokeVirtual(Compilation.getLocationMethod);
295
296             rtype = Type.pointer_type;
297           }
298       }
299     if (target instanceof SeriesTarget
300     && getFlag(Declaration.IS_SINGLE_VALUE))
301       // A kludge until we get a better type system.
302
((SeriesTarget) target).compileFromStackSimple(comp, rtype);
303     else
304       target.compileFromStack(comp, rtype);
305   }
306
307   /* Compile code to store a value (which must already be on the
308      stack) into this variable. */

309   public void compileStore (Compilation comp)
310   {
311     gnu.bytecode.CodeAttr code = comp.getCode();
312     if (isSimple ())
313       code.emitStore(getVariable());
314     else
315       {
316         if (! field.getStaticFlag())
317           {
318             loadOwningObject(null, comp);
319             code.emitSwap();
320         code.emitPutField(field);
321           }
322     else
323       code.emitPutStatic(field);
324       }
325   }
326
327   /** If non-null, the single expression used to set this variable.
328    * If the variable can be set more than once, then value is null. */

329   protected Expression value = QuoteExp.undefined_exp;
330
331   /** The value of this <code>Declaration</code>, if known.
332    * Usually the expression used to initialize the <code>Declaration</code>,
333    * or null if the <code>Declaration</code> can be assigned a different
334    * value after initialization. Note that this is the semantic value: If the
335    * <code>INDIRECT_LOCATION</code> is set, then <code>getValue</code> is the
336    * value <em>after</em> de-referencing the resulting <code>Location</code>.
337    * An exception is if <code>isAlias()</code>; in that case
338    * <code>getValue()</code> is an expression yielding a <code>Location</code>
339    * which needs to be de-referenced to get this <code>Declaration</code>'s
340    * actual value.
341    */

342   public final Expression getValue()
343   {
344     if (value == QuoteExp.undefined_exp
345         && field != null
346         && ((field.getModifiers() & Access.STATIC+Access.FINAL)
347             == Access.STATIC+Access.FINAL)
348         && ! isIndirectBinding())
349       {
350         try
351           {
352             value = new QuoteExp(field.getReflectField().get(null));
353           }
354         catch (Throwable JavaDoc ex)
355           {
356           }
357       }
358     return value;
359   }
360
361   /** Set the value assoociated with this Declaration.
362    * Most code should use noteValue instead. */

363   public final void setValue(Expression value) { this.value = value; }
364
365   /** If getValue() is a constant, return the constant value, otherwise null. */
366   public final Object JavaDoc getConstantValue()
367   {
368     Object JavaDoc v = getValue();
369     if (! (v instanceof QuoteExp) || v == QuoteExp.undefined_exp)
370       return null;
371     return ((QuoteExp) v).getValue();
372   }
373
374   /** This prefix is prepended to field names for unknown names. */
375   static final String JavaDoc UNKNOWN_PREFIX = "loc$";
376
377   /** This prefix is used in field names for a declaration that has
378    * both EXTERNAL_ACCESS and IS_PRIVATE set. */

379   public static final String JavaDoc PRIVATE_PREFIX = "$Prvt$";
380
381   /** If this flag is set then to get the actual value you have to dereference
382    * a <code>gnu.mapping.Location</code>. I.e. this <code>Declaration</code>'s
383    * <code>var</code> or <code>field</code> does not contain the
384    * <code>Declaration</code>'s value directly, but rather yields a
385    * <code>Location</code> that contains the <code>Declaration</code>'s value.
386    * Note that this flag indicates the <em>representation</em>:
387    * The result of <code>getValue()</code> is not the location, but the
388    * semantic value. after dereferencing. Likewise <code>getType</code> is
389    * the value after de-referencing, not a <code>Location</code> sub-class. */

390   static final int INDIRECT_BINDING = 1;
391
392   static final int CAN_READ = 2;
393   static final int CAN_CALL = 4;
394   static final int CAN_WRITE = 8;
395   static final int IS_FLUID = 0x10;
396   static final int PRIVATE = 0x20;
397   static final int IS_SIMPLE = 0x40;
398
399   /** True if in the function namespace, for languages that distinguishes them.
400    * I.e. a function definition or macro definition. */

401   static final int PROCEDURE = 0x80;
402
403   public static final int IS_ALIAS = 0x100;
404
405   /** Set if this is just a declaration, not a definition. */
406   public static final int NOT_DEFINING = 0x200;
407
408   public static final int EXPORT_SPECIFIED = 0x400;
409   public static final int STATIC_SPECIFIED = 0x800;
410   public static final int NONSTATIC_SPECIFIED = 0x1000;
411   public static final int TYPE_SPECIFIED = 0x2000;
412   public static final int IS_CONSTANT = 0x4000;
413   public static final int IS_SYNTAX = 0x8000;
414   public static final int IS_UNKNOWN = 0x10000;
415   public static final int IS_IMPORTED = 0x20000;
416
417   // This should be a type property, not a variable property, at some point!
418
public static final int IS_SINGLE_VALUE = 0x40000;
419
420   /** This flag bit is set if this can be be acceessed from other modules.
421    * Ignored unless PRIVATE.
422    * Used when an exported macro references a non-exported name. */

423   public static final int EXTERNAL_ACCESS = 0x80000;
424
425   public final boolean needsExternalAccess ()
426   {
427     return (flags & EXTERNAL_ACCESS+PRIVATE) == EXTERNAL_ACCESS+PRIVATE
428       // Kludge - needed for macros - see Savannah bug #13601.
429
|| (flags & IS_NAMESPACE_PREFIX+PRIVATE) == IS_NAMESPACE_PREFIX+PRIVATE;
430   }
431
432   /** If we need a 'context' supplied from a ReferenceExp or 'this. */
433   public final boolean needsContext ()
434   {
435     return base == null && field != null && ! field.getStaticFlag();
436   }
437
438   /** True if this is a field or method in a class definition. */
439   public static final int FIELD_OR_METHOD = 0x100000;
440
441   /** Set if this declares a namespace prefix (as in XML namespaces). */
442   public static final int IS_NAMESPACE_PREFIX = 0x200000;
443
444   public static final int PRIVATE_ACCESS = 0x1000000;
445   public static final int PRIVATE_SPECIFIED = PRIVATE_ACCESS; /* deprecated*/
446   public static final int PROTECTED_ACCESS = 0x2000000;
447   public static final int PUBLIC_ACCESS = 0x4000000;
448   public static final int PACKAGE_ACCESS = 0x8000000;
449
450   public static final int IS_DYNAMIC = 0x10000000;
451
452   /** Initialize in {@code <init>}/{@code <clinit>}
453    * rather than in {@code run}/{@code $run$}>. */

454   public static final int EARLY_INIT = 0x20000000;
455   /** A reference to a module instance. */
456   public static final int MODULE_REFERENCE = 0x40000000;
457
458   protected int flags = IS_SIMPLE;
459
460   public final boolean getFlag (int flag)
461   {
462     return (flags & flag) != 0;
463   }
464
465   public final void setFlag (boolean setting, int flag)
466   {
467     if (setting) flags |= flag;
468     else flags &= ~flag;
469   }
470
471   public final void setFlag (int flag)
472   {
473     flags |= flag;
474   }
475
476   public final boolean isPublic()
477   { return context instanceof ModuleExp && (flags & PRIVATE) == 0; }
478
479   public final boolean isPrivate() { return (flags & PRIVATE) != 0; }
480
481   public final void setPrivate(boolean isPrivate)
482   {
483     setFlag(isPrivate, PRIVATE);
484   }
485
486   public short getAccessFlags (short defaultFlags)
487   {
488     if (getFlag(Declaration.PRIVATE_ACCESS))
489       return Access.PRIVATE;
490     if (getFlag(Declaration.PROTECTED_ACCESS))
491       return Access.PROTECTED;
492     if (getFlag(Declaration.PACKAGE_ACCESS))
493       return 0;
494     if (getFlag(Declaration.PUBLIC_ACCESS))
495       return Access.PUBLIC;
496     return defaultFlags;
497   }
498
499   public final boolean isAlias() { return (flags & IS_ALIAS) != 0; }
500   public final void setAlias(boolean flag) { setFlag(flag, IS_ALIAS); }
501
502   /** True if this is a fluid binding (in a FluidLetExp). */
503   public final boolean isFluid () { return (flags & IS_FLUID) != 0; }
504
505   public final void setFluid (boolean fluid) { setFlag(fluid, IS_FLUID); }
506
507   public final boolean isProcedureDecl () { return (flags & PROCEDURE) != 0; }
508
509   public final void setProcedureDecl (boolean val) { setFlag(val, PROCEDURE); }
510
511   public final boolean isNamespaceDecl ()
512   {
513     return (flags & IS_NAMESPACE_PREFIX) != 0;
514   }
515
516   /** True if the value of the variable is the contents of a Location.
517    * @see #INDIRECT_BINDING */

518   public final boolean isIndirectBinding()
519   { return (flags & INDIRECT_BINDING) != 0; }
520
521   /** Note that the value of the variable is the contents of a Location.
522    * @see #INDIRECT_BINDING */

523   public final void setIndirectBinding(boolean indirectBinding)
524   {
525     setFlag(indirectBinding, INDIRECT_BINDING);
526   }
527
528   /* Note: You probably want to use !ignorable(). */
529   public final boolean getCanRead() { return (flags & CAN_READ) != 0; }
530   public final void setCanRead(boolean read)
531   {
532     setFlag(read, CAN_READ);
533   }
534   public final void setCanRead()
535   {
536     setFlag(true, CAN_READ);
537     if (base != null)
538       base.setCanRead();
539   }
540
541   public final boolean getCanCall() { return (flags & CAN_CALL) != 0; }
542   public final void setCanCall(boolean called) { setFlag(called, CAN_CALL); }
543   public final void setCanCall()
544   {
545     setFlag(true, CAN_CALL);
546     if (base != null)
547       base.setCanRead();
548   }
549
550   public final boolean getCanWrite()
551   { return (flags & CAN_WRITE) != 0; }
552
553   public final void setCanWrite(boolean written)
554   {
555     if (written) flags |= CAN_WRITE;
556     else flags &= ~CAN_WRITE;
557   }
558
559   public final void setCanWrite()
560   {
561     flags |= CAN_WRITE;
562     if (base != null)
563       base.setCanRead();
564   }
565
566   /** Is this an implicit 'this' parameter? */
567   public final boolean isThisParameter ()
568   {
569     return symbol == ThisExp.THIS_NAME;
570   }
571
572   /** True if we never need to access this declaration. */
573   // rename to isAccessed?
574
public boolean ignorable()
575   {
576     if (getCanRead() || isPublic())
577       return false;
578     if (getCanWrite() && getFlag(IS_UNKNOWN))
579       return false;
580     if (! getCanCall())
581       return true;
582     Expression value = getValue();
583     if (value == null || ! (value instanceof LambdaExp))
584       return false;
585     LambdaExp lexp = (LambdaExp) value;
586     return ! lexp.isHandlingTailCalls() || lexp.getInlineOnly();
587   }
588
589   /** Does this variable need to be initialized or is default ok
590    */

591   public boolean needsInit()
592   {
593     // This is a kludge. Ideally, we should do some data-flow analysis.
594
// But at least it makes sure require'd variables are not initialized.
595
return ! ignorable()
596       && ! (value == QuoteExp.nullExp && base != null);
597   }
598
599   public boolean isStatic()
600   {
601     if (getFlag(STATIC_SPECIFIED))
602       return true;
603     if (getFlag(NONSTATIC_SPECIFIED))
604       return false;
605     LambdaExp lambda = context.currentLambda();
606     return lambda instanceof ModuleExp
607       && ((ModuleExp) lambda).isStatic();
608   }
609
610   public final boolean isLexical()
611   {
612     return (flags & (IS_FLUID|IS_DYNAMIC|IS_UNKNOWN)) == 0;
613   }
614
615   public static final boolean isUnknown (Declaration decl)
616   {
617     return decl == null || decl.getFlag(IS_UNKNOWN);
618   }
619
620   /** List of ApplyExp where this declaration is the function called.
621    * The applications are chained using their nextCall fields.
622    * The chain is not built if STATIC_SPECIFIED. */

623   public ApplyExp firstCall;
624
625   public void noteValue (Expression value)
626   {
627     // We allow assigning a real value after undefined ...
628
if (this.value == QuoteExp.undefined_exp)
629       {
630     if (value instanceof LambdaExp)
631       ((LambdaExp) value).nameDecl = this;
632     this.value = value;
633       }
634     else if (this.value != value)
635       {
636     if (this.value instanceof LambdaExp)
637       ((LambdaExp) this.value).nameDecl = null;
638     this.value = null;
639       }
640   }
641
642   protected Declaration()
643   {
644   }
645
646   public Declaration (Variable var)
647   {
648     this(var.getName(), var.getType());
649     this.var = var;
650   }
651
652   public Declaration (Object JavaDoc name)
653   {
654     this(name, Type.pointer_type);
655   }
656
657   public Declaration (Object JavaDoc s, Type type)
658   {
659     setName(s);
660     setType(type);
661   }
662
663   public Declaration (Object JavaDoc name, Field field)
664   {
665     this(name, field.getType());
666     this.field = field;
667     setSimple(false);
668   }
669
670   Method makeLocationMethod = null;
671
672   /** Create a Location object, given that isIndirectBinding().
673       Assume the initial value is already pushed on the stack;
674       leaves initialized Location object on stack. */

675   public void pushIndirectBinding (Compilation comp)
676   {
677     CodeAttr code = comp.getCode();
678     code.emitPushString(getName());
679     if (makeLocationMethod == null)
680       {
681     Type[] args = new Type[2];
682     args[0] = Type.pointer_type;
683     args[1] = Type.string_type;
684     makeLocationMethod
685       = Compilation.typeLocation.addMethod("make", args,
686                           Compilation.typeLocation,
687                           Access.PUBLIC|Access.STATIC);
688       }
689     code.emitInvokeStatic(makeLocationMethod);
690   }
691
692   public final Variable allocateVariable(CodeAttr code)
693   {
694     if (! isSimple() || var == null)
695       {
696         String JavaDoc vname = null;
697         if (symbol != null)
698           vname = Compilation.mangleNameIfNeeded(getName());
699     if (isAlias() && getValue() instanceof ReferenceExp)
700       {
701         Declaration base = followAliases(this);
702         var = base == null ? null : base.var;
703       }
704     else
705       {
706         Type type = isIndirectBinding() ? Compilation.typeLocation
707           : getType().getImplementationType();
708         var = context.getVarScope().addVariable(code, type, vname);
709       }
710       }
711     return var;
712   }
713
714   String JavaDoc filename;
715   int position;
716
717   public final void setLocation (SourceLocator location)
718   {
719     this.filename = location.getFileName();
720     setLine(location.getLineNumber(), location.getColumnNumber());
721   }
722
723   public final void setFile (String JavaDoc filename)
724   {
725     this.filename = filename;
726   }
727
728   public final void setLine (int lineno, int colno)
729   {
730     if (lineno < 0)
731       lineno = 0;
732     if (colno < 0)
733       colno = 0;
734     position = (lineno << 12) + colno;
735   }
736
737   public final void setLine (int lineno)
738   {
739     setLine (lineno, 0);
740   }
741
742   public final String JavaDoc getFileName ()
743   {
744     return filename;
745   }
746
747   public String JavaDoc getPublicId ()
748   {
749     return null;
750   }
751
752   public String JavaDoc getSystemId ()
753   {
754     return filename;
755   }
756
757   /** Get the line number of (the start of) this Expression.
758     * The "first" line is line 1; unknown is -1. */

759   public final int getLineNumber()
760   {
761     int line = position >> 12;
762     return line == 0 ? -1 : line;
763   }
764
765   public final int getColumnNumber()
766   {
767     int column = position & ((1 << 12) - 1);
768     return column == 0 ? -1 : column;
769   }
770
771   public boolean isStableSourceLocation() { return true; }
772
773   public void printInfo(OutPort out)
774   {
775     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
776     printInfo(sbuf);
777     out.print(sbuf.toString());
778   }
779
780   public void printInfo(StringBuffer JavaDoc sbuf)
781   {
782     sbuf.append(symbol);
783     sbuf.append('/');
784     sbuf.append(id);
785     /*
786     int line = getLineNumber();
787     if (line != 0)
788       {
789     sbuf.append("/line:");
790     sbuf.append(line);
791     int column = getColumnNumber();
792     if (column != 0)
793       {
794         sbuf.append(':');
795         sbuf.append(column);
796       }
797       }
798     */

799     sbuf.append("/fl:");
800     sbuf.append(Integer.toHexString(flags));
801     Expression tx = typeExp;
802     Type t = getType();
803     if (tx != null && ! (tx instanceof QuoteExp))
804       {
805     sbuf.append("::");
806         sbuf.append(tx);
807       }
808     else if (type != null && t != Type.pointer_type)
809       {
810     sbuf.append("::");
811     sbuf.append(t.getName());
812       }
813   }
814
815
816   public String JavaDoc toString()
817   {
818     return "Declaration["+symbol+'/'+id+']';
819     /*
820     StringBuffer sbuf = new StringBuffer();
821     sbuf.append("Declaration[");
822     printInfo(sbuf);
823     sbuf.append(']');
824     return sbuf.toString();
825     */

826   }
827
828   public static Declaration followAliases (Declaration decl)
829   {
830     while (decl != null && decl.isAlias())
831       {
832     Expression declValue = decl.getValue();
833     if (! (declValue instanceof ReferenceExp))
834       break;
835     ReferenceExp rexp = (ReferenceExp) declValue;
836     Declaration orig = rexp.binding;
837     if (orig == null)
838       break;
839     decl = orig;
840       }
841     return decl;
842   }
843
844   public void makeField(Compilation comp, Expression value)
845   {
846     setSimple(false);
847     makeField(comp.mainClass, comp, value);
848   }
849
850   public void makeField(ClassType frameType, Compilation comp, Expression value)
851   {
852     boolean external_access = needsExternalAccess();
853     int fflags = 0;
854     boolean isConstant = getFlag(IS_CONSTANT);
855     boolean typeSpecified = getFlag(TYPE_SPECIFIED);
856     if (isPublic() && ! isConstant && ! typeSpecified)
857       setIndirectBinding(true);
858     if (isPublic() || external_access)
859       fflags |= Access.PUBLIC;
860     if (isStatic()
861     || (isConstant && value instanceof QuoteExp)
862         // "Dynamic" variables use ThreadLocation, based on the current
863
// Environment, so we don't need more than one static field.
864
|| (getFlag(Declaration.IS_UNKNOWN
865                     |Declaration.IS_DYNAMIC|Declaration.IS_FLUID)
866             && isIndirectBinding() && ! isAlias())
867     || (value instanceof ClassExp
868         && ! ((LambdaExp) value).getNeedsClosureEnv()))
869       fflags |= Access.STATIC;
870     if ((isIndirectBinding() || isConstant)
871         && (context instanceof ClassExp || context instanceof ModuleExp))
872       fflags |= Access.FINAL;
873     Type ftype = getType().getImplementationType();
874     if (isIndirectBinding() && ! ftype.isSubtype(Compilation.typeLocation))
875       if (getFlag(EARLY_INIT) && isAlias())
876         ftype = ClassType.make("gnu.kawa.reflect.FieldLocation");
877       else
878         ftype = Compilation.typeLocation;
879     String JavaDoc fname = getName();
880     int nlength;
881     if (fname==null)
882       {
883         fname = "$unnamed$0";
884         nlength = fname.length() - 2; // Without the "$0".
885
}
886     else
887       {
888         fname = Compilation.mangleNameIfNeeded(fname);
889         if (getFlag(IS_UNKNOWN))
890           fname = UNKNOWN_PREFIX + fname;
891         if (external_access && ! getFlag(Declaration.MODULE_REFERENCE))
892           fname = PRIVATE_PREFIX + fname;
893         nlength = fname.length();
894       }
895     int counter = 0;
896     while (frameType.getDeclaredField(fname) != null)
897       fname = fname.substring(0, nlength) + '$' + (++ counter);
898
899     field = frameType.addField (fname, ftype, fflags);
900     if (value instanceof QuoteExp)
901       {
902     Object JavaDoc val = ((QuoteExp) value).getValue();
903     if (val.getClass().getName().equals(ftype.getName()))
904       {
905         Literal literal = comp.litTable.findLiteral(val);
906         if (literal.field == null)
907           literal.assign(field, comp.litTable);
908       }
909     else if (ftype instanceof PrimType
910          || "java.lang.String".equals(ftype.getName()))
911       {
912         if (val instanceof gnu.text.Char)
913           val = gnu.math.IntNum.make(((gnu.text.Char) val).intValue());
914         field.setConstantValue(val, frameType);
915         return;
916       }
917       }
918     // The EARLY_INIT case is handled in SetExp.compile.
919
if (! getFlag(EARLY_INIT)
920     && (isIndirectBinding()
921         || (value != null && ! (value instanceof ClassExp))))
922       {
923     BindingInitializer.create(this, value, comp);
924       }
925   }
926
927   /* Used when evaluating for an indirect binding. */
928   gnu.mapping.Location makeIndirectLocationFor ()
929   {
930     Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
931       : Namespace.EmptyNamespace.getSymbol(symbol.toString().intern());
932     return gnu.mapping.Location.make(sym);
933   }
934
935   /** Create a declaration corresponding to a static field.
936    * @param cname name of class containing field
937    * @param fname name of static field
938    */

939   public static Declaration
940   getDeclarationFromStatic (String JavaDoc cname, String JavaDoc fname)
941   {
942     ClassType clas = ClassType.make(cname);
943     Field fld = clas.getDeclaredField(fname);
944     Declaration decl = new Declaration(fname, fld);
945     decl.setFlag(Declaration.IS_CONSTANT|Declaration.STATIC_SPECIFIED);
946     return decl;
947   }
948
949   /** Similar to {@code getDeclarationFromStatic},
950    * but also do {@code noteValue} with the field's value.
951    */

952   public static Declaration
953   getDeclarationValueFromStatic (String JavaDoc className,
954                                  String JavaDoc fieldName, String JavaDoc name)
955   {
956     try
957       {
958     Class JavaDoc cls = Class.forName(className);
959     java.lang.reflect.Field JavaDoc fld = cls.getDeclaredField(fieldName);
960     Object JavaDoc value = fld.get(null);
961
962     Declaration decl
963           = new Declaration(name,
964                             ClassType.make(className)
965                             .getDeclaredField(fieldName));
966     decl.noteValue(new QuoteExp(value));
967     decl.setFlag(Declaration.IS_CONSTANT|Declaration.STATIC_SPECIFIED);
968         return decl;
969       }
970     catch (Exception JavaDoc ex)
971       {
972     throw new WrappedException(ex);
973       }
974   }
975
976   public static Declaration getDeclaration(Named proc)
977   {
978     return getDeclaration(proc, proc.getName());
979   }
980
981   public static Declaration getDeclaration(Object JavaDoc proc, String JavaDoc name)
982   {
983     gnu.bytecode.Field procField = null;
984     if (name != null)
985       {
986         /*
987         // This is a way to map from the Procedure's name to a Field,
988         // by assuming the name as the form "classname:fieldname".
989         // It may be better to use names of the form "{classname}fieldname".
990         // For now we don't need this feature.
991         int colon = name.indexOf(':');
992         if (colon > 0)
993           {
994             try
995               {
996                 ClassType procType
997                   = (ClassType) ClassType.make(name.substring(0, colon));
998                 name = name.substring(colon+1);
999                 String fname = Compilation.mangleNameIfNeeded(name);
1000                procField = procType.getDeclaredField(fname);
1001              }
1002            catch (Throwable ex)
1003              {
1004                System.err.println("CAUGHT "+ex+" in getDeclaration for "+proc);
1005                return null;
1006              }
1007          }
1008        else
1009        */

1010          {
1011            Class JavaDoc procClass = PrimProcedure.getProcedureClass(proc);
1012            if (procClass != null)
1013              {
1014                ClassType procType = (ClassType) Type.make(procClass);
1015                String JavaDoc fname = Compilation.mangleNameIfNeeded(name);
1016                procField = procType.getDeclaredField(fname);
1017              }
1018          }
1019      }
1020    if (procField != null)
1021      {
1022        int fflags = procField.getModifiers();
1023        if ((fflags & Access.STATIC) != 0)
1024          {
1025            Declaration decl = new Declaration(name, procField);
1026            decl.noteValue(new QuoteExp(proc));
1027            if ((fflags & Access.FINAL) != 0)
1028              decl.setFlag(Declaration.IS_CONSTANT);
1029            return decl;
1030          }
1031      }
1032    return null;
1033  }
1034}
1035
Popular Tags