001: // Copyright (c) 1999 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.expr;
005:
006: import gnu.bytecode.*;
007: import gnu.mapping.*;
008:
009: /**
010: * This class represents a variable reference (an identifier).
011: * @author Per Bothner
012: */
013:
014: public class ReferenceExp extends Expression {
015: Object symbol;
016: Declaration binding;
017:
018: public String string_name() {
019: return symbol.toString();
020: }
021:
022: public final String getName() {
023: return symbol.toString();
024: }
025:
026: public final Object getSymbol() {
027: return symbol;
028: }
029:
030: /** If non-null, the local Declaration this refers to. */
031: public final Declaration getBinding() {
032: return binding;
033: }
034:
035: public final void setBinding(Declaration decl) {
036: binding = decl;
037: }
038:
039: static int counter;
040: /** Unique id number, to ease print-outs and debugging. */
041: int id = ++counter;
042:
043: private static int DONT_DEREFERENCE = NEXT_AVAIL_FLAG;
044: private static int PROCEDURE_NAME = NEXT_AVAIL_FLAG << 1;
045: public static int PREFER_BINDING2 = NEXT_AVAIL_FLAG << 2;
046:
047: /* If true, must have binding.isBinding(). Don't dereference Binding. */
048: public final boolean getDontDereference() {
049: return (flags & DONT_DEREFERENCE) != 0;
050: }
051:
052: public final void setDontDereference(boolean setting) {
053: setFlag(setting, DONT_DEREFERENCE);
054: }
055:
056: /** True if this identifier appears in "function call position".
057: * If so, it should be interpreted as a function name, which makes a
058: * difference for languages (like Common Lisp) that have two name spaces. */
059: public final boolean isProcedureName() {
060: return (flags & PROCEDURE_NAME) != 0;
061: }
062:
063: /** Note if this identifier appears in "function call position". */
064: public final void setProcedureName(boolean setting) {
065: setFlag(setting, PROCEDURE_NAME);
066: }
067:
068: public ReferenceExp(Object symbol) {
069: this .symbol = symbol;
070: }
071:
072: public ReferenceExp(Object symbol, Declaration binding) {
073: this .symbol = symbol;
074: this .binding = binding;
075: }
076:
077: public ReferenceExp(Declaration binding) {
078: this .binding = binding;
079: this .symbol = binding.getName();
080: }
081:
082: public Object eval(Environment env) {
083: if (binding != null) {
084: if (binding.field != null && binding.field.getStaticFlag()) {
085: try {
086: Object value = binding.field.getReflectField().get(
087: null);
088: if (!(value instanceof Binding))
089: return value;
090: // otherwise not implemented!
091: } catch (Exception ex) {
092: }
093: }
094: if (!(binding.context instanceof ModuleExp && !binding
095: .isPrivate()))
096: throw new Error(
097: "internal error: ReferenceExp.eval on lexical binding");
098: }
099: if (getDontDereference())
100: return symbol instanceof Binding ? symbol : env
101: .getBinding(symbol.toString());
102: else if (getFlag(PREFER_BINDING2)) {
103: Binding bind = symbol instanceof Binding ? (Binding) symbol
104: : env.getBinding(symbol.toString());
105: return isProcedureName() ? bind.getFunctionValue() : bind
106: .get();
107: } else
108: return env.getChecked(symbol.toString());
109: }
110:
111: public void compile(Compilation comp, Target target) {
112: if (target instanceof IgnoreTarget)
113: return;
114: CodeAttr code = comp.getCode();
115: Declaration decl = Declaration.followAliases(binding);
116: decl.load(comp);
117: if (decl.isIndirectBinding() && !getDontDereference()) {
118: if (!isProcedureName())
119: code.emitInvokeVirtual(Compilation.getLocationMethod);
120: // else if (comp.getInterpreter().hasSeparateFunctionNamespace())
121: // code.emitGetField(Compilation.functionValueBinding2Field);
122: else
123: code
124: .emitInvokeVirtual(Compilation.getProcedureBindingMethod);
125: } else if (decl.isFluid() && decl.field == null)
126: code.emitGetField(FluidLetExp.valueField);
127: if (target instanceof SeriesTarget
128: && decl.getFlag(Declaration.IS_SINGLE_VALUE))
129: // A kludge until we get a better type system.
130: ((SeriesTarget) target).compileFromStackSimple(comp,
131: getType());
132: else
133: target.compileFromStack(comp, getType());
134: }
135:
136: protected Expression walk(ExpWalker walker) {
137: return walker.walkReferenceExp(this );
138: }
139:
140: public void print(OutPort ps) {
141: ps.print("(Ref/");
142: ps.print(id);
143: ps.print("/ ");
144: SFormat.print(symbol, ps);
145: ps.print(")");
146: }
147:
148: public gnu.bytecode.Type getType() {
149: return (binding == null || binding.isFluid()) ? Type.pointer_type
150: : getDontDereference() ? Compilation.typeLocation
151: : binding.getType();
152: }
153:
154: public String toString() {
155: return "RefExp/" + symbol + '/' + id + '/';
156: }
157: }
|