001: // Copyright (c) 1999, 2001 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.mapping.*;
007: import gnu.bytecode.*;
008:
009: /** An Expression to set (bind) or define a new value to a named variable.
010: * @author Per Bothner
011: */
012:
013: public class SetExp extends Expression {
014: private int flags;
015:
016: /** The name of the variable to set. */
017: String name;
018: /** If non-null, the local Declaration this refers to. */
019: public Declaration binding;
020: /** The new value to assign to the variable. */
021: Expression new_value;
022:
023: public SetExp(String sym, Expression val) {
024: name = sym;
025: new_value = val;
026: }
027:
028: public final String getName() {
029: return name;
030: }
031:
032: /** Get the Expression for calculating the new ("right-hand") value. */
033: public final Expression getNewValue() {
034: return new_value;
035: }
036:
037: static private int DEFINING_FLAG = NEXT_AVAIL_FLAG;
038: static private int GLOBAL_FLAG = NEXT_AVAIL_FLAG << 1;
039: public static int PREFER_BINDING2 = NEXT_AVAIL_FLAG << 2;
040: static private int PROCEDURE = NEXT_AVAIL_FLAG << 3;
041: static private int SET_IF_UNBOUND = NEXT_AVAIL_FLAG << 4;
042: static private int HAS_VALUE = NEXT_AVAIL_FLAG << 5;
043:
044: public final boolean isDefining() {
045: return (flags & DEFINING_FLAG) != 0;
046: }
047:
048: public final void setDefining(boolean value) {
049: if (value)
050: flags |= DEFINING_FLAG;
051: else
052: flags &= ~DEFINING_FLAG;
053: }
054:
055: /** True if evaluating the SetExp yields the value of the RHS. */
056: public final boolean getHasValue() {
057: return (flags & HAS_VALUE) != 0;
058: }
059:
060: public final void setHasValue(boolean value) {
061: if (value)
062: flags |= HAS_VALUE;
063: else
064: flags &= ~HAS_VALUE;
065: }
066:
067: /** True if this is a functon definition ("defun"). */
068: public final boolean isFuncDef() {
069: return (flags & PROCEDURE) != 0;
070: }
071:
072: public final void setFuncDef(boolean value) {
073: if (value)
074: flags |= PROCEDURE;
075: else
076: flags &= ~PROCEDURE;
077: }
078:
079: public final boolean isSetIfUnbound() {
080: return (flags & SET_IF_UNBOUND) != 0;
081: }
082:
083: public final void setSetIfUnbound(boolean value) {
084: if (value)
085: flags |= SET_IF_UNBOUND;
086: else
087: flags &= ~SET_IF_UNBOUND;
088: }
089:
090: public SetExp(Declaration decl, Expression val) {
091: this .binding = decl;
092: name = decl.getName();
093: new_value = val;
094: }
095:
096: public Object eval(Environment env) throws Throwable {
097: if (isSetIfUnbound()) {
098: Binding binding = env.getBinding(name);
099: if (!binding.isBound())
100: binding.set(new_value.eval(env));
101: if (getHasValue())
102: return name;
103: else
104: return Interpreter.getInterpreter().noValue();
105: }
106:
107: Object new_val = new_value.eval(env);
108:
109: if (binding != null && !(binding.context instanceof ModuleExp))
110: throw new Error(
111: "internal error - SetExp.eval with lexical binding");
112: if (isDefining()) {
113: if (binding != null && binding.isAlias())
114: AliasConstraint.define(env.getBinding(name),
115: (gnu.mapping.Location) new_val);
116: else
117: env.define(name, new_val);
118: } else {
119: Binding bind = env.lookup(name);
120: if (bind != null)
121: env.put(name, new_val);
122: else
123: env.define(name, new_val);
124: // throw new UnboundSymbol (name);
125: }
126: return getHasValue() ? new_val : Interpreter.getInterpreter()
127: .noValue();
128: }
129:
130: static Method setMethod = null;
131:
132: public void compile(Compilation comp, Target target) {
133: if (new_value instanceof LambdaExp
134: && target instanceof IgnoreTarget
135: && ((LambdaExp) new_value).getInlineOnly())
136: return;
137: Type type;
138: gnu.bytecode.CodeAttr code = comp.getCode();
139: // FIXME - handle isSetIfUnbound
140: boolean needValue = getHasValue()
141: && !(target instanceof IgnoreTarget);
142:
143: // set the following to true if the value has been pushed.
144: // this is used to detect not implemented cases.
145: // when all cases are implemented, remove this.
146: boolean valuePushed = false;
147:
148: // This code is kind of kludgy, because it handles a number of
149: // different cases: assignments and definitions to both local and
150: // global variables. Some of the complication is because we want
151: // to generate fields for module-level definitions; this is how
152: // bindings are exported from modules.
153:
154: Object value;
155: Declaration decl = binding;
156: if (!decl.isPrivate() && decl.context instanceof ModuleExp
157: && decl.getValue() instanceof LambdaExp
158: && ((LambdaExp) decl.getValue()).getName() != null // FIXME
159: && decl.getValue() == new_value) {
160: ((LambdaExp) new_value).compileSetField(comp);
161: } else if (decl.context instanceof ModuleExp
162: && (new_value instanceof QuoteExp) && !decl.isPrivate()
163: && !comp.immediate && decl.getValue() != null) { // This is handled in ModuleExp's allocFields method.
164: }
165: /* NICE: remove spurious dependancy
166: else if (decl.getFlag(Declaration.IS_SYNTAX)
167: && decl.context instanceof ModuleExp
168: && (value = ((kawa.lang.Macro) decl.getConstantValue()).expander) instanceof LambdaExp
169: && ! decl.isPrivate())
170: {
171: LambdaExp expander = (LambdaExp) value;
172: expander.flags |= LambdaExp.NO_FIELD;
173: expander.compileAsMethod(comp);
174: comp.mainLambda.addApplyMethod(expander);
175: decl.makeField(comp, new_value);
176: }
177: */
178: else {
179: if (!isDefining())
180: decl = Declaration.followAliases(decl);
181: if (decl.ignorable())
182: new_value.compile(comp, Target.Ignore);
183: else if (decl.isAlias() && isDefining()) {
184: if (decl.isPublic()
185: || !(decl.getValue() instanceof ReferenceExp)) {
186: decl.load(comp);
187: new_value.compile(comp, Target.pushObject);
188: Method meth = ClassType.make(
189: "gnu.mapping.AliasConstraint")
190: .getDeclaredMethod("define", 2);
191: code.emitInvokeStatic(meth);
192: }
193: } else if (decl.isIndirectBinding()
194: && (!isDefining() || decl.isPublic())) {
195: decl.load(comp);
196: new_value.compile(comp, Target.pushObject);
197: if (needValue) {
198: code.emitDupX();
199: valuePushed = true;
200: }
201: if (setMethod == null)
202: setMethod = comp.typeLocation.addMethod("set",
203: Compilation.apply1args, Type.void_type,
204: Access.PUBLIC | Access.FINAL);
205: code.emitInvokeVirtual(setMethod);
206: } else if (decl.isFluid()) {
207: decl.load(comp);
208: new_value.compile(comp, Type.pointer_type);
209: code.emitPutField(FluidLetExp.valueField);
210: } else if (decl.isSimple()) {
211: type = decl.getType();
212: new_value.compile(comp, type);
213: if (needValue) {
214: code.emitDup(type); // dup or dup2
215: valuePushed = true;
216: }
217: Variable var = decl.getVariable();
218: if (var == null)
219: var = decl.allocateVariable(code);
220: code.emitStore(var);
221: } else if (decl.context instanceof ClassExp
222: && decl.field == null && !getFlag(PROCEDURE)
223: && ((ClassExp) decl.context).isMakingClassPair()) {
224: String setName = ClassExp.slotToMethodName("set", decl
225: .getName());
226: ClassExp cl = (ClassExp) decl.context;
227: Method setter = cl.type.getDeclaredMethod(setName, 1);
228: cl.loadHeapFrame(comp);
229: new_value.compile(comp, decl.getType());
230: if (needValue) {
231: code.emitDupX();
232: valuePushed = true;
233: }
234: code.emitInvoke(setter);
235: } else {
236: Field field = decl.field;
237: if (!field.getStaticFlag())
238: decl.loadOwningObject(comp);
239: type = field.getType();
240: new_value.compile(comp, type);
241: if (field.getStaticFlag()) {
242: if (needValue) {
243: code.emitDup(type);
244: valuePushed = true;
245: }
246: code.emitPutStatic(field);
247: } else {
248: if (needValue) {
249: code.emitDupX();
250: valuePushed = true;
251: }
252: code.emitPutField(field);
253: }
254: }
255: }
256:
257: if (needValue && !valuePushed)
258: throw new Error(
259: "SetExp.compile: not implemented - return value");
260:
261: if (needValue)
262: target.compileFromStack(comp, getType());
263: else
264: comp.compileConstant(Values.empty, target);
265: }
266:
267: public final gnu.bytecode.Type getType() {
268: return !getHasValue() ? Type.void_type
269: : binding == null ? Type.pointer_type : binding
270: .getType();
271: }
272:
273: protected Expression walk(ExpWalker walker) {
274: return walker.walkSetExp(this );
275: }
276:
277: protected void walkChildren(ExpWalker walker) {
278: new_value = (Expression) new_value.walk(walker);
279: }
280:
281: public void print(OutPort out) {
282: out
283: .startLogicalBlock(isDefining() ? "(Define" : "(Set",
284: ")", 2);
285: out.writeSpaceFill();
286: printLineColumn(out);
287: SFormat.print(name, out); // FIXME
288: out.writeSpaceLinear();
289: new_value.print(out);
290: out.endLogicalBlock(")");
291: }
292: }
|