001: // Copyright (c) 1999, 2005 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 AccessExp {
015: static int counter;
016: /** Unique id number, to ease print-outs and debugging. */
017: int id = ++counter;
018:
019: public static final int DONT_DEREFERENCE = NEXT_AVAIL_FLAG;
020: public static final int PROCEDURE_NAME = NEXT_AVAIL_FLAG << 1;
021: public static final int PREFER_BINDING2 = NEXT_AVAIL_FLAG << 2;
022: /** Create a FieldLocation referencing the binding. */
023: public static final int CREATE_FIELD_REFERENCE = NEXT_AVAIL_FLAG << 3;
024:
025: /* If true, must have binding.isIndirectBinding(). Don't dereference it. */
026: public final boolean getDontDereference() {
027: return (flags & DONT_DEREFERENCE) != 0;
028: }
029:
030: public final void setDontDereference(boolean setting) {
031: setFlag(setting, DONT_DEREFERENCE);
032: }
033:
034: public final boolean isUnknown() {
035: return Declaration.isUnknown(binding);
036: }
037:
038: /** True if this identifier appears in "function call position".
039: * If so, it should be interpreted as a function name, which makes a
040: * difference for languages (like Common Lisp) that have two name spaces. */
041: public final boolean isProcedureName() {
042: return (flags & PROCEDURE_NAME) != 0;
043: }
044:
045: /** Note if this identifier appears in "function call position". */
046: public final void setProcedureName(boolean setting) {
047: setFlag(setting, PROCEDURE_NAME);
048: }
049:
050: public ReferenceExp(Object symbol) {
051: this .symbol = symbol;
052: }
053:
054: public ReferenceExp(Object symbol, Declaration binding) {
055: this .symbol = symbol;
056: this .binding = binding;
057: }
058:
059: public ReferenceExp(Declaration binding) {
060: this (binding.getSymbol(), binding);
061: }
062:
063: protected boolean mustCompile() {
064: return false;
065: }
066:
067: public void apply(CallContext ctx) throws Throwable {
068: Object value;
069: if (binding != null && binding.isAlias()
070: && !getDontDereference()
071: && binding.value instanceof ReferenceExp) {
072: ReferenceExp rexp = (ReferenceExp) binding.value;
073: if (rexp.getDontDereference() && rexp.binding != null) {
074: Expression v = rexp.binding.getValue();
075: if (v instanceof QuoteExp || v instanceof ReferenceExp
076: || v instanceof LambdaExp) {
077: v.apply(ctx);
078: return;
079: }
080: }
081: value = binding.value.eval(ctx);
082: } else if (binding != null
083: && binding.field != null
084: && binding.field.getDeclaringClass().isExisting()
085: && (!getDontDereference() || binding
086: .isIndirectBinding())) {
087: try {
088: Object instance = binding.field.getStaticFlag() ? null
089: : contextDecl().getValue().eval(ctx);
090: value = binding.field.getReflectField().get(instance);
091: } catch (Exception ex) {
092: String msg = "exception evaluating " + symbol
093: + " from " + binding.field + " - " + ex;
094: // We abuse msg as a UnboundLocationException name.
095: throw new UnboundLocationException(msg, this );
096: }
097: }
098: // This isn't just an optimization - it's needed for evaluating procedural
099: // macros (e.g. syntax-case) defined in a not-yet-compiled module.
100: else if (binding != null
101: && (binding.value instanceof QuoteExp || binding.value instanceof LambdaExp)
102: && binding.value != QuoteExp.undefined_exp
103: && (!getDontDereference() || binding
104: .isIndirectBinding())) {
105: value = binding.value.eval(ctx);
106: } else if (binding == null
107: || (binding.context instanceof ModuleExp && !binding
108: .isPrivate())) {
109: Environment env = ctx.getEnvironment();
110: Symbol sym = symbol instanceof Symbol ? (Symbol) symbol
111: : env.getSymbol(symbol.toString());
112: Object property = getFlag(PREFER_BINDING2)
113: && isProcedureName() ? EnvironmentKey.FUNCTION
114: : null;
115: if (getDontDereference())
116: value = env.getLocation(sym, property);
117: else {
118: Object unb = gnu.mapping.Location.UNBOUND;
119: value = env.get(sym, property, unb);
120: if (value == unb)
121: throw new UnboundLocationException(sym, this );
122: }
123: ctx.writeValue(value);
124: return;
125: } else
126: value = ctx.evalFrames[ScopeExp.nesting(binding.context)][binding.evalIndex];
127: if (!getDontDereference() && binding.isIndirectBinding())
128: value = ((gnu.mapping.Location) value).get();
129: ctx.writeValue(value);
130: }
131:
132: public void compile(Compilation comp, Target target) {
133: if (!(target instanceof ConsumerTarget)
134: || !((ConsumerTarget) target).compileWrite(this , comp))
135: binding.load(this , flags, comp, target);
136: }
137:
138: protected Expression walk(ExpWalker walker) {
139: return walker.walkReferenceExp(this );
140: }
141:
142: public Expression inline(ApplyExp exp, InlineCalls walker,
143: Declaration decl) {
144: decl = this .binding; // We don't use the passed-in Declaration.
145: if (decl != null && !decl.getFlag(Declaration.IS_UNKNOWN)) {
146: decl = Declaration.followAliases(decl);
147: if (decl.isIndirectBinding())
148: return exp;
149: Expression dval = decl.getValue();
150: if (dval != null)
151: return dval.inline(exp, walker, decl);
152: } else if (getSymbol() instanceof Symbol) {
153: Symbol symbol = (Symbol) getSymbol();
154: Object fval = Environment.getCurrent().getFunction(symbol,
155: null);
156: if (fval instanceof Procedure)
157: return new QuoteExp(fval).inline(exp, walker, null);
158: }
159: return exp;
160: }
161:
162: public void print(OutPort ps) {
163: ps.print("(Ref/");
164: ps.print(id);
165: if (symbol != null
166: && (binding == null || symbol.toString() != binding
167: .getName())) {
168: ps.print('/');
169: ps.print(symbol);
170: }
171: if (binding != null) {
172: ps.print('/');
173: ps.print(binding);
174: }
175: ps.print(")");
176: }
177:
178: public gnu.bytecode.Type getType() {
179: Declaration decl = binding;
180: if (decl == null || decl.isFluid())
181: return Type.pointer_type;
182: if (getDontDereference())
183: return Compilation.typeLocation;
184: decl = Declaration.followAliases(decl);
185: Type type = decl.getType();
186: if (type == null || type == Type.pointer_type) {
187: Expression value = decl.getValue();
188: if (value != null) {
189: // Kludge to guard against cycles.
190: // Not verified if it is really needed, but just in case ...
191: Expression save = decl.value;
192: decl.value = null;
193: type = value.getType();
194: decl.value = save;
195: }
196: }
197: return type;
198: }
199:
200: public boolean side_effects() {
201: return binding == null || !binding.isLexical();
202: }
203:
204: public String toString() {
205: return "RefExp/" + symbol + '/' + id + '/';
206: }
207: }
|