001: package gnu.expr;
002:
003: import gnu.bytecode.*;
004: import gnu.mapping.*;
005:
006: /**
007: * Class used to implement "let" syntax (and variants) for Scheme.
008: * @author Per Bothner
009: */
010:
011: public class LetExp extends ScopeExp {
012: public Expression[] inits;
013: public Expression body;
014:
015: public LetExp(Expression[] i) {
016: inits = i;
017: }
018:
019: public Expression getBody() {
020: return body;
021: }
022:
023: public void setBody(Expression body) {
024: this .body = body;
025: }
026:
027: protected boolean mustCompile() {
028: return false;
029: }
030:
031: public void apply(CallContext ctx) throws Throwable {
032: setIndexes();
033: int level = ScopeExp.nesting(this );
034: int i = frameSize;
035:
036: Object[] evalFrame = new Object[i];
037: Object[][] evalFrames = ctx.evalFrames;
038: if (evalFrames == null) {
039: evalFrames = new Object[level + 10][];
040: ctx.evalFrames = evalFrames;
041: } else if (level >= evalFrames.length) {
042: Object[][] newFrames = new Object[level + 10][];
043: System.arraycopy(evalFrames, 0, newFrames, 0,
044: evalFrames.length);
045: ctx.evalFrames = evalFrames = newFrames;
046: }
047: evalFrames[level] = evalFrame;
048:
049: try {
050: i = 0;
051: for (Declaration decl = firstDecl(); decl != null; decl = decl
052: .nextDecl(), i++) {
053: Expression init = inits[i];
054: if (init == QuoteExp.undefined_exp)
055: continue;
056: Object value = init.eval(ctx);
057: Type type = decl.type;
058: if (type != null && type != Type.pointer_type)
059: value = type.coerceFromObject(value);
060: if (decl.isIndirectBinding()) {
061: gnu.mapping.Location loc = decl
062: .makeIndirectLocationFor();
063: loc.set(value);
064: value = loc;
065: }
066: evalFrame[i] = value;
067: }
068: body.apply(ctx);
069: } finally {
070: evalFrames[level] = null;
071: }
072: }
073:
074: /* CPS:
075: * Need to ensure that ctx.pc is 0 before the this is called
076: * the first time. This is currently done by match0.
077: * Need to define concention so ReferenceExp can find appropriate binding.
078: * Need to define convention for what gets copied, if anything,
079: * when a continuation is created. (Note problem below if a half-initialized
080: * frame gets captuerd. Then multiple cals to the same continuation
081: * could clobber the frame, unless it has been copied. But copying the
082: * frame is tricky if we want to avoid copying the whole stack, plus we
083: * have to correctly handle set! to a local/
084: public void apply (CallContext ctx) throws Throwable
085: {
086: CallFrame fr;
087: if (ctx.pc == 0)
088: {
089: fr = new gnu.mapping.CallFrame();
090: fr.previous = ctx.frame;
091: fr.saveVstackLen = ctx.startFromContext();
092: ctx.frame = fr;
093: }
094: else
095: fr = ctx.frame;
096: int i = ctx.pc;
097: if (i == inits.length + 1)
098: {
099: // pop
100: ctx.frame = fr.previous;
101: return;
102: }
103: if (i > 0)
104: fr.values[i-1] = ctx.getFromContext(fr.saveVstackLen);
105: ctx.pc++;
106: if (i == inits.length)
107: {
108: body.match0(ctx);
109: return;
110: }
111: fr.saveVstackLen = ctx.startFromContext();
112: inits[i].match0(ctx);
113: }
114: */
115:
116: /* Recursive helper routine, to store the values on the stack
117: * into the variables in vars, in reverse order. */
118: void store_rest(Compilation comp, int i, Declaration decl) {
119: if (decl != null) {
120: store_rest(comp, i + 1, decl.nextDecl());
121: if (decl.needsInit()) {
122: if (decl.isIndirectBinding()) {
123: CodeAttr code = comp.getCode();
124: if (inits[i] == QuoteExp.undefined_exp) {
125: Object name = decl.getSymbol();
126: comp.compileConstant(name, Target.pushObject);
127: code.emitInvokeStatic(BindingInitializer
128: .makeLocationMethod(name));
129: } else {
130: decl.pushIndirectBinding(comp);
131: }
132: }
133: decl.compileStore(comp);
134: }
135: }
136: }
137:
138: public void compile(Compilation comp, Target target) {
139: gnu.bytecode.CodeAttr code = comp.getCode();
140:
141: /*
142: if (comp.usingCPStyle())
143: {
144: for (Declartion decl = firstDecl(); decl != null; decl = decl.nextDecl())
145: {
146: decl.assignField(comp);
147: }
148: }
149: */
150:
151: /* Compile all the initializations, leaving the results
152: on the stack (in reverse order). */
153: Declaration decl = firstDecl();
154: for (int i = 0; i < inits.length; i++, decl = decl.nextDecl()) {
155: Target varTarget;
156: Expression init = inits[i];
157: boolean needsInit = decl.needsInit();
158: if (needsInit)
159: decl.allocateVariable(code);
160: if (!needsInit
161: || (decl.isIndirectBinding() && init == QuoteExp.undefined_exp))
162: varTarget = Target.Ignore;
163: else {
164: Type varType = decl.getType();
165: varTarget = CheckedTarget.getInstance(varType);
166: if (init == QuoteExp.undefined_exp) {
167: // Typically created by letrec.
168: if (varType instanceof PrimType)
169: init = new QuoteExp(new Byte((byte) 0));
170: else if (varType != null
171: && varType != Type.pointer_type)
172: init = QuoteExp.nullExp;
173: }
174: }
175: init.compile(comp, varTarget);
176: }
177:
178: code.enterScope(getVarScope());
179:
180: /* Assign the initial values to the proper variables, in reverse order. */
181: store_rest(comp, 0, firstDecl());
182:
183: body.compileWithPosition(comp, target);
184: popScope(code);
185: }
186:
187: public final gnu.bytecode.Type getType() {
188: return body.getType();
189: }
190:
191: protected Expression walk(ExpWalker walker) {
192: return walker.walkLetExp(this );
193: }
194:
195: public void walkInitializers(ExpWalker walker) {
196: Declaration decl = firstDecl();
197: for (int i = 0; i < inits.length; i++, decl = decl.nextDecl()) {
198: Expression init0 = inits[i];
199: Expression init = walker.walk(init0);
200: inits[i] = init;
201: if (decl.value == init0)
202: decl.value = init;
203: }
204: }
205:
206: protected void walkChildren(ExpWalker walker) {
207: walkInitializers(walker);
208: if (walker.exitValue == null)
209: body = (Expression) walker.walk(body);
210: }
211:
212: public void print(OutPort out) {
213: print(out, "(Let", ")");
214: }
215:
216: public void print(OutPort out, String startTag, String endTag) {
217: out.startLogicalBlock(startTag + "#" + id, endTag, 2);
218: out.writeSpaceFill();
219: printLineColumn(out);
220: out.startLogicalBlock("(", false, ")");
221: Declaration decl = firstDecl();
222: int i = 0;
223:
224: for (; decl != null; decl = decl.nextDecl()) {
225: if (i > 0)
226: out.writeSpaceFill();
227: out.startLogicalBlock("(", false, ")");
228: decl.printInfo(out);
229: if (inits != null) {
230: out.writeSpaceFill();
231: out.print('=');
232: out.writeSpaceFill();
233: //if (decl.isArtificial ())
234: //out.print ("<artificial>");
235: //else
236: {
237: if (i >= inits.length)
238: out.print("<missing init>");
239: else if (inits[i] == null)
240: out.print("<null>");
241: else
242: inits[i].print(out);
243: i++;
244: }
245: }
246: out.endLogicalBlock(")");
247: }
248: out.endLogicalBlock(")");
249: out.writeSpaceLinear();
250: if (body == null)
251: out.print("<null body>");
252: else
253: body.print(out);
254: out.endLogicalBlock(endTag);
255: }
256: }
|