0001: // Copyright (c) 2003 Per M.A. Bothner.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.expr;
0005:
0006: import gnu.bytecode.*;
0007: import gnu.mapping.*;
0008: import gnu.text.SourceLocator;
0009:
0010: /**
0011: * The static information associated with a local variable binding.
0012: * @author Per Bothner
0013: *
0014: * These are the kinds of Declaration we use:
0015: *
0016: * A local variable that is not captured by an inner lambda is stored
0017: * in a Java local variables slot (register). The predicate isSimple ()
0018: * is true, and offset is the number of the local variable slot.
0019: *
0020: * If a local variable is captured by an inner lambda, the
0021: * variable is stored in a field of the LambdaExp's heapFrame variable.
0022: * (The latter declaration has isSimple and isArtificial true.)
0023: * The Declaration's field specifies the Field used.
0024: *
0025: * If a function takes a fixed number of parameters, at most four,
0026: * then the arguments are passed in Java registers 1..4.
0027: * If a parameter is not captured by an inner lambda, the parameter
0028: * has the flags isSimple and isParameter true.
0029: *
0030: * If a function takes more than 4 or a variable number of parameters,
0031: * the arguments are passed in an array (using the applyN virtual method).
0032: * This array is referenced by the argsArray declaration, which has
0033: * isSimple(), isParameter(), and isArtificial() true, and its offset is 1.
0034: * The parameters are copied into the program-named variables by the
0035: * procedure prologue, so the parameters henceforth act like local variables.
0036: */
0037:
0038: public class Declaration implements SourceLocator {
0039: static int counter;
0040: /** Unique id number, to ease print-outs and debugging.
0041: * If negative, a code to specify a builtin function. */
0042: protected int id = ++counter;
0043:
0044: /** The name of the new variable, either an interned String or a Symbol.
0045: * This is the source-level (non-mangled) name. */
0046: Object symbol;
0047:
0048: public void setCode(int code) {
0049: if (code >= 0)
0050: throw new Error("code must be negative");
0051: this .id = code;
0052: }
0053:
0054: public int getCode() {
0055: return id;
0056: }
0057:
0058: public ScopeExp context;
0059:
0060: protected Type type;
0061: protected Expression typeExp;
0062:
0063: public final Expression getTypeExp() {
0064: return typeExp;
0065: }
0066:
0067: public final Type getType() {
0068: return type;
0069: }
0070:
0071: public final void setType(Type type) {
0072: this .type = type;
0073: if (var != null)
0074: var.setType(type);
0075: typeExp = QuoteExp.getInstance(type);
0076: }
0077:
0078: public final void setTypeExp(Expression typeExp) {
0079: this .typeExp = typeExp;
0080: Object typeValue;
0081: Type t = (typeExp instanceof QuoteExp
0082: && (typeValue = ((QuoteExp) typeExp).getValue()) instanceof Type ? (Type) typeValue
0083: : typeExp instanceof TypeValue ? ((TypeValue) typeExp)
0084: .getImplementationType()
0085: : (Type) Type.pointer_type);
0086: this .type = t;
0087: if (var != null)
0088: var.setType(t);
0089: }
0090:
0091: public final String getName() {
0092: return symbol == null ? null
0093: : symbol instanceof Symbol ? ((Symbol) symbol)
0094: .getName() : symbol.toString();
0095: }
0096:
0097: public final void setName(Object symbol) {
0098: this .symbol = symbol;
0099: }
0100:
0101: public final Object getSymbol() {
0102: return symbol;
0103: }
0104:
0105: public final void setSymbol(Object symbol) {
0106: this .symbol = symbol;
0107: }
0108:
0109: /* Declarations in a ScopeExp are linked together in a linked list. */
0110: Declaration next;
0111:
0112: public final Declaration nextDecl() {
0113: return next;
0114: }
0115:
0116: public final void setNext(Declaration next) {
0117: this .next = next;
0118: }
0119:
0120: /** Index in evalFrame for this scope, if interpreting. */
0121: int evalIndex;
0122:
0123: Variable var;
0124:
0125: public Variable getVariable() {
0126: return var;
0127: }
0128:
0129: public final boolean isSimple() {
0130: return (flags & IS_SIMPLE) != 0;
0131: }
0132:
0133: public final void setSimple(boolean b) {
0134: setFlag(b, IS_SIMPLE);
0135: if (var != null && !var.isParameter())
0136: var.setSimple(b);
0137: }
0138:
0139: public final void setSyntax() {
0140: setSimple(false);
0141: setFlag(Declaration.IS_CONSTANT | Declaration.IS_SYNTAX);
0142: }
0143:
0144: /** Return the ScopeExp that contains (declares) this Declaration. */
0145: public final ScopeExp getContext() {
0146: return context;
0147: }
0148:
0149: /** Used to link Declarations in a LambdaExp's capturedVars list. */
0150: Declaration nextCapturedVar;
0151:
0152: /** If non-null, field is relative to base.
0153: * If IS_FLUID, base points to IS_UNKNOWN Symbol. */
0154: public Declaration base;
0155:
0156: public Field field;
0157:
0158: /** If this is a field in some object, load a reference to that object. */
0159: void loadOwningObject(Declaration owner, Compilation comp) {
0160: if (owner == null)
0161: owner = base;
0162: if (owner != null)
0163: owner.load(null, 0, comp, Target.pushObject);
0164: else
0165: getContext().currentLambda().loadHeapFrame(comp);
0166: }
0167:
0168: public void load(AccessExp access, int flags, Compilation comp,
0169: Target target) {
0170: if (target instanceof IgnoreTarget)
0171: return;
0172: Declaration owner = access == null ? null : access
0173: .contextDecl();
0174: if (isAlias() && value instanceof ReferenceExp) {
0175: ReferenceExp rexp = (ReferenceExp) value;
0176: Declaration orig = rexp.binding;
0177: if (orig != null
0178: && ((flags & ReferenceExp.DONT_DEREFERENCE) == 0 || orig
0179: .isIndirectBinding())
0180: && (owner == null || !orig.needsContext())) {
0181: orig.load(rexp, flags, comp, target);
0182: return;
0183: }
0184: }
0185: CodeAttr code = comp.getCode();
0186: Type rtype = getType();
0187: if ((flags & ReferenceExp.CREATE_FIELD_REFERENCE) != 0) {
0188: if (field == null)
0189: throw new Error(
0190: "internal error: cannot take location of "
0191: + this );
0192: Method meth;
0193: ClassType ltype;
0194: boolean immediate = comp.immediate;
0195: if (field.getStaticFlag()) {
0196: ltype = ClassType
0197: .make("gnu.kawa.reflect.StaticFieldLocation");
0198: meth = ltype.getDeclaredMethod("make", immediate ? 1
0199: : 2);
0200: } else {
0201: ltype = ClassType
0202: .make("gnu.kawa.reflect.FieldLocation");
0203: meth = ltype.getDeclaredMethod("make", immediate ? 2
0204: : 3);
0205:
0206: loadOwningObject(owner, comp);
0207: }
0208: if (immediate)
0209: comp.compileConstant(this );
0210: else {
0211: comp.compileConstant(field.getDeclaringClass()
0212: .getName());
0213: comp.compileConstant(field.getName());
0214: }
0215: code.emitInvokeStatic(meth);
0216: rtype = ltype;
0217: } else {
0218: Object val;
0219: if (field != null) {
0220: comp.usedClass(field.getDeclaringClass());
0221: if (!field.getStaticFlag()) {
0222: loadOwningObject(owner, comp);
0223: code.emitGetField(field);
0224: } else
0225: code.emitGetStatic(field);
0226: } else if (isIndirectBinding() && comp.immediate
0227: && getVariable() == null) {
0228: // This is a bit of a kludge. See comment in ModuleExp.evalModule.
0229: Environment env = Environment.getCurrent();
0230: Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
0231: : env.getSymbol(symbol.toString());
0232: Object property = null;
0233: if (isProcedureDecl()
0234: && comp.getLanguage()
0235: .hasSeparateFunctionNamespace())
0236: property = EnvironmentKey.FUNCTION;
0237: gnu.mapping.Location loc = env.getLocation(sym,
0238: property);
0239: comp.compileConstant(loc, Target
0240: .pushValue(Compilation.typeLocation));
0241: } else if (comp.immediate
0242: && (val = getConstantValue()) != null) {
0243: comp.compileConstant(val, target);
0244: return;
0245: } else {
0246: Variable var = getVariable();
0247: ClassExp cl;
0248: if (context instanceof ClassExp
0249: && var == null
0250: && !getFlag(PROCEDURE)
0251: && (cl = (ClassExp) context)
0252: .isMakingClassPair()) {
0253: String getName = ClassExp.slotToMethodName("get",
0254: getName());
0255: Method getter = cl.type.getDeclaredMethod(getName,
0256: 0);
0257: cl.loadHeapFrame(comp);
0258: code.emitInvoke(getter);
0259: } else {
0260: if (var == null)
0261: var = allocateVariable(code);
0262: code.emitLoad(var);
0263: }
0264: }
0265: if (isIndirectBinding()
0266: && (flags & ReferenceExp.DONT_DEREFERENCE) == 0) {
0267:
0268: String filename;
0269: int line;
0270: if (access != null
0271: && (filename = access.getFileName()) != null
0272: && (line = access.getLineNumber()) > 0) {
0273: // Wrap call to Location.get by a catch handler that
0274: // calls setLine on the UnboundLocationException.
0275: ClassType typeUnboundLocationException = ClassType
0276: .make("gnu.mapping.UnboundLocationException");
0277: // See comment in CheckedTarget.emitCheckedCoerce.
0278: boolean isInTry = code.isInTry();
0279: int column = access.getColumnNumber();
0280: Label startTry = new Label(code);
0281: startTry.define(code);
0282: code
0283: .emitInvokeVirtual(Compilation.getLocationMethod);
0284: Label endTry = new Label(code);
0285: endTry.define(code);
0286: Label endLabel = new Label(code);
0287: if (isInTry)
0288: code.emitGoto(endLabel);
0289: int fragment_cookie = 0;
0290: if (!isInTry)
0291: fragment_cookie = code.beginFragment(new Label(
0292: code), endLabel);
0293: code.addHandler(startTry, endTry,
0294: typeUnboundLocationException);
0295:
0296: code.pushType(typeUnboundLocationException);
0297: code.emitDup(typeUnboundLocationException);
0298: code.emitPushString(filename);
0299: code.emitPushInt(line);
0300: code.emitPushInt(column);
0301: code.emitInvokeVirtual(typeUnboundLocationException
0302: .getDeclaredMethod("setLine", 3));
0303: code.emitThrow();
0304: if (isInTry)
0305: endLabel.define(code);
0306: else
0307: code.endFragment(fragment_cookie);
0308: } else
0309: code
0310: .emitInvokeVirtual(Compilation.getLocationMethod);
0311:
0312: rtype = Type.pointer_type;
0313: }
0314: }
0315: if (target instanceof SeriesTarget
0316: && getFlag(Declaration.IS_SINGLE_VALUE))
0317: // A kludge until we get a better type system.
0318: ((SeriesTarget) target).compileFromStackSimple(comp, rtype);
0319: else
0320: target.compileFromStack(comp, rtype);
0321: }
0322:
0323: /* Compile code to store a value (which must already be on the
0324: stack) into this variable. */
0325: public void compileStore(Compilation comp) {
0326: gnu.bytecode.CodeAttr code = comp.getCode();
0327: if (isSimple())
0328: code.emitStore(getVariable());
0329: else {
0330: if (!field.getStaticFlag()) {
0331: loadOwningObject(null, comp);
0332: code.emitSwap();
0333: code.emitPutField(field);
0334: } else
0335: code.emitPutStatic(field);
0336: }
0337: }
0338:
0339: /** If non-null, the single expression used to set this variable.
0340: * If the variable can be set more than once, then value is null. */
0341: protected Expression value = QuoteExp.undefined_exp;
0342:
0343: /** The value of this <code>Declaration</code>, if known.
0344: * Usually the expression used to initialize the <code>Declaration</code>,
0345: * or null if the <code>Declaration</code> can be assigned a different
0346: * value after initialization. Note that this is the semantic value: If the
0347: * <code>INDIRECT_LOCATION</code> is set, then <code>getValue</code> is the
0348: * value <em>after</em> de-referencing the resulting <code>Location</code>.
0349: * An exception is if <code>isAlias()</code>; in that case
0350: * <code>getValue()</code> is an expression yielding a <code>Location</code>
0351: * which needs to be de-referenced to get this <code>Declaration</code>'s
0352: * actual value.
0353: */
0354: public final Expression getValue() {
0355: if (value == QuoteExp.undefined_exp
0356: && field != null
0357: && ((field.getModifiers() & Access.STATIC
0358: + Access.FINAL) == Access.STATIC + Access.FINAL)
0359: && !isIndirectBinding()) {
0360: try {
0361: value = new QuoteExp(field.getReflectField().get(null));
0362: } catch (Throwable ex) {
0363: }
0364: }
0365: return value;
0366: }
0367:
0368: /** Set the value assoociated with this Declaration.
0369: * Most code should use noteValue instead. */
0370: public final void setValue(Expression value) {
0371: this .value = value;
0372: }
0373:
0374: /** If getValue() is a constant, return the constant value, otherwise null. */
0375: public final Object getConstantValue() {
0376: Object v = getValue();
0377: if (!(v instanceof QuoteExp) || v == QuoteExp.undefined_exp)
0378: return null;
0379: return ((QuoteExp) v).getValue();
0380: }
0381:
0382: /** This prefix is prepended to field names for unknown names. */
0383: static final String UNKNOWN_PREFIX = "loc$";
0384:
0385: /** This prefix is used in field names for a declaration that has
0386: * both EXTERNAL_ACCESS and IS_PRIVATE set. */
0387: public static final String PRIVATE_PREFIX = "$Prvt$";
0388:
0389: /** If this flag is set then to get the actual value you have to dereference
0390: * a <code>gnu.mapping.Location</code>. I.e. this <code>Declaration</code>'s
0391: * <code>var</code> or <code>field</code> does not contain the
0392: * <code>Declaration</code>'s value directly, but rather yields a
0393: * <code>Location</code> that contains the <code>Declaration</code>'s value.
0394: * Note that this flag indicates the <em>representation</em>:
0395: * The result of <code>getValue()</code> is not the location, but the
0396: * semantic value. after dereferencing. Likewise <code>getType</code> is
0397: * the value after de-referencing, not a <code>Location</code> sub-class. */
0398: static final int INDIRECT_BINDING = 1;
0399:
0400: static final int CAN_READ = 2;
0401: static final int CAN_CALL = 4;
0402: static final int CAN_WRITE = 8;
0403: static final int IS_FLUID = 0x10;
0404: static final int PRIVATE = 0x20;
0405: static final int IS_SIMPLE = 0x40;
0406:
0407: /** True if in the function namespace, for languages that distinguishes them.
0408: * I.e. a function definition or macro definition. */
0409: static final int PROCEDURE = 0x80;
0410:
0411: public static final int IS_ALIAS = 0x100;
0412:
0413: /** Set if this is just a declaration, not a definition. */
0414: public static final int NOT_DEFINING = 0x200;
0415:
0416: public static final int EXPORT_SPECIFIED = 0x400;
0417: public static final int STATIC_SPECIFIED = 0x800;
0418: public static final int NONSTATIC_SPECIFIED = 0x1000;
0419: public static final int TYPE_SPECIFIED = 0x2000;
0420: public static final int IS_CONSTANT = 0x4000;
0421: public static final int IS_SYNTAX = 0x8000;
0422: public static final int IS_UNKNOWN = 0x10000;
0423: public static final int IS_IMPORTED = 0x20000;
0424:
0425: // This should be a type property, not a variable property, at some point!
0426: public static final int IS_SINGLE_VALUE = 0x40000;
0427:
0428: /** This flag bit is set if this can be be acceessed from other modules.
0429: * Ignored unless PRIVATE.
0430: * Used when an exported macro references a non-exported name. */
0431: public static final int EXTERNAL_ACCESS = 0x80000;
0432:
0433: public final boolean needsExternalAccess() {
0434: return (flags & EXTERNAL_ACCESS + PRIVATE) == EXTERNAL_ACCESS
0435: + PRIVATE
0436: // Kludge - needed for macros - see Savannah bug #13601.
0437: || (flags & IS_NAMESPACE_PREFIX + PRIVATE) == IS_NAMESPACE_PREFIX
0438: + PRIVATE;
0439: }
0440:
0441: /** If we need a 'context' supplied from a ReferenceExp or 'this. */
0442: public final boolean needsContext() {
0443: return base == null && field != null && !field.getStaticFlag();
0444: }
0445:
0446: /** True if this is a field or method in a class definition. */
0447: public static final int FIELD_OR_METHOD = 0x100000;
0448:
0449: /** Set if this declares a namespace prefix (as in XML namespaces). */
0450: public static final int IS_NAMESPACE_PREFIX = 0x200000;
0451:
0452: public static final int PRIVATE_ACCESS = 0x1000000;
0453: public static final int PRIVATE_SPECIFIED = PRIVATE_ACCESS; /* deprecated*/
0454: public static final int PROTECTED_ACCESS = 0x2000000;
0455: public static final int PUBLIC_ACCESS = 0x4000000;
0456: public static final int PACKAGE_ACCESS = 0x8000000;
0457:
0458: public static final int IS_DYNAMIC = 0x10000000;
0459:
0460: /** Initialize in {@code <init>}/{@code <clinit>}
0461: * rather than in {@code run}/{@code $run$}>. */
0462: public static final int EARLY_INIT = 0x20000000;
0463: /** A reference to a module instance. */
0464: public static final int MODULE_REFERENCE = 0x40000000;
0465:
0466: protected int flags = IS_SIMPLE;
0467:
0468: public final boolean getFlag(int flag) {
0469: return (flags & flag) != 0;
0470: }
0471:
0472: public final void setFlag(boolean setting, int flag) {
0473: if (setting)
0474: flags |= flag;
0475: else
0476: flags &= ~flag;
0477: }
0478:
0479: public final void setFlag(int flag) {
0480: flags |= flag;
0481: }
0482:
0483: public final boolean isPublic() {
0484: return context instanceof ModuleExp && (flags & PRIVATE) == 0;
0485: }
0486:
0487: public final boolean isPrivate() {
0488: return (flags & PRIVATE) != 0;
0489: }
0490:
0491: public final void setPrivate(boolean isPrivate) {
0492: setFlag(isPrivate, PRIVATE);
0493: }
0494:
0495: public short getAccessFlags(short defaultFlags) {
0496: if (getFlag(Declaration.PRIVATE_ACCESS))
0497: return Access.PRIVATE;
0498: if (getFlag(Declaration.PROTECTED_ACCESS))
0499: return Access.PROTECTED;
0500: if (getFlag(Declaration.PACKAGE_ACCESS))
0501: return 0;
0502: if (getFlag(Declaration.PUBLIC_ACCESS))
0503: return Access.PUBLIC;
0504: return defaultFlags;
0505: }
0506:
0507: public final boolean isAlias() {
0508: return (flags & IS_ALIAS) != 0;
0509: }
0510:
0511: public final void setAlias(boolean flag) {
0512: setFlag(flag, IS_ALIAS);
0513: }
0514:
0515: /** True if this is a fluid binding (in a FluidLetExp). */
0516: public final boolean isFluid() {
0517: return (flags & IS_FLUID) != 0;
0518: }
0519:
0520: public final void setFluid(boolean fluid) {
0521: setFlag(fluid, IS_FLUID);
0522: }
0523:
0524: public final boolean isProcedureDecl() {
0525: return (flags & PROCEDURE) != 0;
0526: }
0527:
0528: public final void setProcedureDecl(boolean val) {
0529: setFlag(val, PROCEDURE);
0530: }
0531:
0532: public final boolean isNamespaceDecl() {
0533: return (flags & IS_NAMESPACE_PREFIX) != 0;
0534: }
0535:
0536: /** True if the value of the variable is the contents of a Location.
0537: * @see #INDIRECT_BINDING */
0538: public final boolean isIndirectBinding() {
0539: return (flags & INDIRECT_BINDING) != 0;
0540: }
0541:
0542: /** Note that the value of the variable is the contents of a Location.
0543: * @see #INDIRECT_BINDING */
0544: public final void setIndirectBinding(boolean indirectBinding) {
0545: setFlag(indirectBinding, INDIRECT_BINDING);
0546: }
0547:
0548: /* Note: You probably want to use !ignorable(). */
0549: public final boolean getCanRead() {
0550: return (flags & CAN_READ) != 0;
0551: }
0552:
0553: public final void setCanRead(boolean read) {
0554: setFlag(read, CAN_READ);
0555: }
0556:
0557: public final void setCanRead() {
0558: setFlag(true, CAN_READ);
0559: if (base != null)
0560: base.setCanRead();
0561: }
0562:
0563: public final boolean getCanCall() {
0564: return (flags & CAN_CALL) != 0;
0565: }
0566:
0567: public final void setCanCall(boolean called) {
0568: setFlag(called, CAN_CALL);
0569: }
0570:
0571: public final void setCanCall() {
0572: setFlag(true, CAN_CALL);
0573: if (base != null)
0574: base.setCanRead();
0575: }
0576:
0577: public final boolean getCanWrite() {
0578: return (flags & CAN_WRITE) != 0;
0579: }
0580:
0581: public final void setCanWrite(boolean written) {
0582: if (written)
0583: flags |= CAN_WRITE;
0584: else
0585: flags &= ~CAN_WRITE;
0586: }
0587:
0588: public final void setCanWrite() {
0589: flags |= CAN_WRITE;
0590: if (base != null)
0591: base.setCanRead();
0592: }
0593:
0594: /** Is this an implicit 'this' parameter? */
0595: public final boolean isThisParameter() {
0596: return symbol == ThisExp.THIS_NAME;
0597: }
0598:
0599: /** True if we never need to access this declaration. */
0600: // rename to isAccessed?
0601: public boolean ignorable() {
0602: if (getCanRead() || isPublic())
0603: return false;
0604: if (getCanWrite() && getFlag(IS_UNKNOWN))
0605: return false;
0606: if (!getCanCall())
0607: return true;
0608: Expression value = getValue();
0609: if (value == null || !(value instanceof LambdaExp))
0610: return false;
0611: LambdaExp lexp = (LambdaExp) value;
0612: return !lexp.isHandlingTailCalls() || lexp.getInlineOnly();
0613: }
0614:
0615: /** Does this variable need to be initialized or is default ok
0616: */
0617: public boolean needsInit() {
0618: // This is a kludge. Ideally, we should do some data-flow analysis.
0619: // But at least it makes sure require'd variables are not initialized.
0620: return !ignorable()
0621: && !(value == QuoteExp.nullExp && base != null);
0622: }
0623:
0624: public boolean isStatic() {
0625: if (getFlag(STATIC_SPECIFIED))
0626: return true;
0627: if (getFlag(NONSTATIC_SPECIFIED))
0628: return false;
0629: LambdaExp lambda = context.currentLambda();
0630: return lambda instanceof ModuleExp
0631: && ((ModuleExp) lambda).isStatic();
0632: }
0633:
0634: public final boolean isLexical() {
0635: return (flags & (IS_FLUID | IS_DYNAMIC | IS_UNKNOWN)) == 0;
0636: }
0637:
0638: public static final boolean isUnknown(Declaration decl) {
0639: return decl == null || decl.getFlag(IS_UNKNOWN);
0640: }
0641:
0642: /** List of ApplyExp where this declaration is the function called.
0643: * The applications are chained using their nextCall fields.
0644: * The chain is not built if STATIC_SPECIFIED. */
0645: public ApplyExp firstCall;
0646:
0647: public void noteValue(Expression value) {
0648: // We allow assigning a real value after undefined ...
0649: if (this .value == QuoteExp.undefined_exp) {
0650: if (value instanceof LambdaExp)
0651: ((LambdaExp) value).nameDecl = this ;
0652: this .value = value;
0653: } else if (this .value != value) {
0654: if (this .value instanceof LambdaExp)
0655: ((LambdaExp) this .value).nameDecl = null;
0656: this .value = null;
0657: }
0658: }
0659:
0660: protected Declaration() {
0661: }
0662:
0663: public Declaration(Variable var) {
0664: this (var.getName(), var.getType());
0665: this .var = var;
0666: }
0667:
0668: public Declaration(Object name) {
0669: this (name, Type.pointer_type);
0670: }
0671:
0672: public Declaration(Object s, Type type) {
0673: setName(s);
0674: setType(type);
0675: }
0676:
0677: public Declaration(Object name, Field field) {
0678: this (name, field.getType());
0679: this .field = field;
0680: setSimple(false);
0681: }
0682:
0683: Method makeLocationMethod = null;
0684:
0685: /** Create a Location object, given that isIndirectBinding().
0686: Assume the initial value is already pushed on the stack;
0687: leaves initialized Location object on stack. */
0688: public void pushIndirectBinding(Compilation comp) {
0689: CodeAttr code = comp.getCode();
0690: code.emitPushString(getName());
0691: if (makeLocationMethod == null) {
0692: Type[] args = new Type[2];
0693: args[0] = Type.pointer_type;
0694: args[1] = Type.string_type;
0695: makeLocationMethod = Compilation.typeLocation.addMethod(
0696: "make", args, Compilation.typeLocation,
0697: Access.PUBLIC | Access.STATIC);
0698: }
0699: code.emitInvokeStatic(makeLocationMethod);
0700: }
0701:
0702: public final Variable allocateVariable(CodeAttr code) {
0703: if (!isSimple() || var == null) {
0704: String vname = null;
0705: if (symbol != null)
0706: vname = Compilation.mangleNameIfNeeded(getName());
0707: if (isAlias() && getValue() instanceof ReferenceExp) {
0708: Declaration base = followAliases(this );
0709: var = base == null ? null : base.var;
0710: } else {
0711: Type type = isIndirectBinding() ? Compilation.typeLocation
0712: : getType().getImplementationType();
0713: var = context.getVarScope().addVariable(code, type,
0714: vname);
0715: }
0716: }
0717: return var;
0718: }
0719:
0720: String filename;
0721: int position;
0722:
0723: public final void setLocation(SourceLocator location) {
0724: this .filename = location.getFileName();
0725: setLine(location.getLineNumber(), location.getColumnNumber());
0726: }
0727:
0728: public final void setFile(String filename) {
0729: this .filename = filename;
0730: }
0731:
0732: public final void setLine(int lineno, int colno) {
0733: if (lineno < 0)
0734: lineno = 0;
0735: if (colno < 0)
0736: colno = 0;
0737: position = (lineno << 12) + colno;
0738: }
0739:
0740: public final void setLine(int lineno) {
0741: setLine(lineno, 0);
0742: }
0743:
0744: public final String getFileName() {
0745: return filename;
0746: }
0747:
0748: public String getPublicId() {
0749: return null;
0750: }
0751:
0752: public String getSystemId() {
0753: return filename;
0754: }
0755:
0756: /** Get the line number of (the start of) this Expression.
0757: * The "first" line is line 1; unknown is -1. */
0758: public final int getLineNumber() {
0759: int line = position >> 12;
0760: return line == 0 ? -1 : line;
0761: }
0762:
0763: public final int getColumnNumber() {
0764: int column = position & ((1 << 12) - 1);
0765: return column == 0 ? -1 : column;
0766: }
0767:
0768: public boolean isStableSourceLocation() {
0769: return true;
0770: }
0771:
0772: public void printInfo(OutPort out) {
0773: StringBuffer sbuf = new StringBuffer();
0774: printInfo(sbuf);
0775: out.print(sbuf.toString());
0776: }
0777:
0778: public void printInfo(StringBuffer sbuf) {
0779: sbuf.append(symbol);
0780: sbuf.append('/');
0781: sbuf.append(id);
0782: /*
0783: int line = getLineNumber();
0784: if (line != 0)
0785: {
0786: sbuf.append("/line:");
0787: sbuf.append(line);
0788: int column = getColumnNumber();
0789: if (column != 0)
0790: {
0791: sbuf.append(':');
0792: sbuf.append(column);
0793: }
0794: }
0795: */
0796: sbuf.append("/fl:");
0797: sbuf.append(Integer.toHexString(flags));
0798: Expression tx = typeExp;
0799: Type t = getType();
0800: if (tx != null && !(tx instanceof QuoteExp)) {
0801: sbuf.append("::");
0802: sbuf.append(tx);
0803: } else if (type != null && t != Type.pointer_type) {
0804: sbuf.append("::");
0805: sbuf.append(t.getName());
0806: }
0807: }
0808:
0809: public String toString() {
0810: return "Declaration[" + symbol + '/' + id + ']';
0811: /*
0812: StringBuffer sbuf = new StringBuffer();
0813: sbuf.append("Declaration[");
0814: printInfo(sbuf);
0815: sbuf.append(']');
0816: return sbuf.toString();
0817: */
0818: }
0819:
0820: public static Declaration followAliases(Declaration decl) {
0821: while (decl != null && decl.isAlias()) {
0822: Expression declValue = decl.getValue();
0823: if (!(declValue instanceof ReferenceExp))
0824: break;
0825: ReferenceExp rexp = (ReferenceExp) declValue;
0826: Declaration orig = rexp.binding;
0827: if (orig == null)
0828: break;
0829: decl = orig;
0830: }
0831: return decl;
0832: }
0833:
0834: public void makeField(Compilation comp, Expression value) {
0835: setSimple(false);
0836: makeField(comp.mainClass, comp, value);
0837: }
0838:
0839: public void makeField(ClassType frameType, Compilation comp,
0840: Expression value) {
0841: boolean external_access = needsExternalAccess();
0842: int fflags = 0;
0843: boolean isConstant = getFlag(IS_CONSTANT);
0844: boolean typeSpecified = getFlag(TYPE_SPECIFIED);
0845: if (isPublic() && !isConstant && !typeSpecified)
0846: setIndirectBinding(true);
0847: if (isPublic() || external_access)
0848: fflags |= Access.PUBLIC;
0849: if (isStatic()
0850: || (isConstant && value instanceof QuoteExp)
0851: // "Dynamic" variables use ThreadLocation, based on the current
0852: // Environment, so we don't need more than one static field.
0853: || (getFlag(Declaration.IS_UNKNOWN
0854: | Declaration.IS_DYNAMIC | Declaration.IS_FLUID)
0855: && isIndirectBinding() && !isAlias())
0856: || (value instanceof ClassExp && !((LambdaExp) value)
0857: .getNeedsClosureEnv()))
0858: fflags |= Access.STATIC;
0859: if ((isIndirectBinding() || isConstant)
0860: && (context instanceof ClassExp || context instanceof ModuleExp))
0861: fflags |= Access.FINAL;
0862: Type ftype = getType().getImplementationType();
0863: if (isIndirectBinding()
0864: && !ftype.isSubtype(Compilation.typeLocation))
0865: if (getFlag(EARLY_INIT) && isAlias())
0866: ftype = ClassType
0867: .make("gnu.kawa.reflect.FieldLocation");
0868: else
0869: ftype = Compilation.typeLocation;
0870: String fname = getName();
0871: int nlength;
0872: if (fname == null) {
0873: fname = "$unnamed$0";
0874: nlength = fname.length() - 2; // Without the "$0".
0875: } else {
0876: fname = Compilation.mangleNameIfNeeded(fname);
0877: if (getFlag(IS_UNKNOWN))
0878: fname = UNKNOWN_PREFIX + fname;
0879: if (external_access
0880: && !getFlag(Declaration.MODULE_REFERENCE))
0881: fname = PRIVATE_PREFIX + fname;
0882: nlength = fname.length();
0883: }
0884: int counter = 0;
0885: while (frameType.getDeclaredField(fname) != null)
0886: fname = fname.substring(0, nlength) + '$' + (++counter);
0887:
0888: field = frameType.addField(fname, ftype, fflags);
0889: if (value instanceof QuoteExp) {
0890: Object val = ((QuoteExp) value).getValue();
0891: if (val.getClass().getName().equals(ftype.getName())) {
0892: Literal literal = comp.litTable.findLiteral(val);
0893: if (literal.field == null)
0894: literal.assign(field, comp.litTable);
0895: } else if (ftype instanceof PrimType
0896: || "java.lang.String".equals(ftype.getName())) {
0897: if (val instanceof gnu.text.Char)
0898: val = gnu.math.IntNum.make(((gnu.text.Char) val)
0899: .intValue());
0900: field.setConstantValue(val, frameType);
0901: return;
0902: }
0903: }
0904: // The EARLY_INIT case is handled in SetExp.compile.
0905: if (!getFlag(EARLY_INIT)
0906: && (isIndirectBinding() || (value != null && !(value instanceof ClassExp)))) {
0907: BindingInitializer.create(this , value, comp);
0908: }
0909: }
0910:
0911: /* Used when evaluating for an indirect binding. */
0912: gnu.mapping.Location makeIndirectLocationFor() {
0913: Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
0914: : Namespace.EmptyNamespace.getSymbol(symbol.toString()
0915: .intern());
0916: return gnu.mapping.Location.make(sym);
0917: }
0918:
0919: /** Create a declaration corresponding to a static field.
0920: * @param cname name of class containing field
0921: * @param fname name of static field
0922: */
0923: public static Declaration getDeclarationFromStatic(String cname,
0924: String fname) {
0925: ClassType clas = ClassType.make(cname);
0926: Field fld = clas.getDeclaredField(fname);
0927: Declaration decl = new Declaration(fname, fld);
0928: decl.setFlag(Declaration.IS_CONSTANT
0929: | Declaration.STATIC_SPECIFIED);
0930: return decl;
0931: }
0932:
0933: /** Similar to {@code getDeclarationFromStatic},
0934: * but also do {@code noteValue} with the field's value.
0935: */
0936: public static Declaration getDeclarationValueFromStatic(
0937: String className, String fieldName, String name) {
0938: try {
0939: Class cls = Class.forName(className);
0940: java.lang.reflect.Field fld = cls
0941: .getDeclaredField(fieldName);
0942: Object value = fld.get(null);
0943:
0944: Declaration decl = new Declaration(name, ClassType.make(
0945: className).getDeclaredField(fieldName));
0946: decl.noteValue(new QuoteExp(value));
0947: decl.setFlag(Declaration.IS_CONSTANT
0948: | Declaration.STATIC_SPECIFIED);
0949: return decl;
0950: } catch (Exception ex) {
0951: throw new WrappedException(ex);
0952: }
0953: }
0954:
0955: public static Declaration getDeclaration(Named proc) {
0956: return getDeclaration(proc, proc.getName());
0957: }
0958:
0959: public static Declaration getDeclaration(Object proc, String name) {
0960: gnu.bytecode.Field procField = null;
0961: if (name != null) {
0962: /*
0963: // This is a way to map from the Procedure's name to a Field,
0964: // by assuming the name as the form "classname:fieldname".
0965: // It may be better to use names of the form "{classname}fieldname".
0966: // For now we don't need this feature.
0967: int colon = name.indexOf(':');
0968: if (colon > 0)
0969: {
0970: try
0971: {
0972: ClassType procType
0973: = (ClassType) ClassType.make(name.substring(0, colon));
0974: name = name.substring(colon+1);
0975: String fname = Compilation.mangleNameIfNeeded(name);
0976: procField = procType.getDeclaredField(fname);
0977: }
0978: catch (Throwable ex)
0979: {
0980: System.err.println("CAUGHT "+ex+" in getDeclaration for "+proc);
0981: return null;
0982: }
0983: }
0984: else
0985: */
0986: {
0987: Class procClass = PrimProcedure.getProcedureClass(proc);
0988: if (procClass != null) {
0989: ClassType procType = (ClassType) Type
0990: .make(procClass);
0991: String fname = Compilation.mangleNameIfNeeded(name);
0992: procField = procType.getDeclaredField(fname);
0993: }
0994: }
0995: }
0996: if (procField != null) {
0997: int fflags = procField.getModifiers();
0998: if ((fflags & Access.STATIC) != 0) {
0999: Declaration decl = new Declaration(name, procField);
1000: decl.noteValue(new QuoteExp(proc));
1001: if ((fflags & Access.FINAL) != 0)
1002: decl.setFlag(Declaration.IS_CONSTANT);
1003: return decl;
1004: }
1005: }
1006: return null;
1007: }
1008: }
|