1 package gnu.expr; 2 import gnu.bytecode.*; 3 import gnu.kawa.io.OutPort; 4 import gnu.mapping.*; 5 6 /** 7 * Class used to implement "let" syntax (and variants) for Scheme. 8 * @author Per Bothner 9 */ 10 11 public class LetExp extends ScopeExp 12 { 13 Expression body; 14 15 public static final int IS_BODY_SCOPE = 2; 16 LetExp()17 public LetExp () { } 18 getBody()19 public Expression getBody() { return body; } setBody(Expression body)20 public void setBody(Expression body) { this.body = body; } 21 mustCompile()22 protected boolean mustCompile () { return false; } 23 evalVariable(Declaration decl, CallContext ctx)24 protected Object evalVariable (Declaration decl, CallContext ctx) throws Throwable 25 { 26 return decl.getInitValue().eval(ctx); 27 } 28 29 @Override apply(CallContext ctx)30 public void apply (CallContext ctx) throws Throwable 31 { 32 setIndexes(); 33 int level = ScopeExp.nesting(this); 34 int i = frameSize; 35 36 Object[] evalFrame = new Object[i]; 37 Object[][] evalFrames = ctx.evalFrames; 38 if (evalFrames == null) 39 { 40 evalFrames = new Object[level+10][]; 41 ctx.evalFrames = evalFrames; 42 } 43 else if (level >= evalFrames.length) 44 { 45 Object[][] newFrames = new Object[level+10][]; 46 System.arraycopy(evalFrames, 0, newFrames, 0, evalFrames.length); 47 ctx.evalFrames = evalFrames = newFrames; 48 } 49 Object[] oldFrame = evalFrames[level]; // usually null 50 evalFrames[level] = evalFrame; 51 52 try 53 { 54 i = 0; 55 for (Declaration decl = firstDecl(); decl != null; 56 decl = decl.nextDecl(), i++) 57 { 58 if (decl.getInitValue() == QuoteExp.undefined_exp) 59 continue; 60 Object value = evalVariable(decl, ctx); 61 Type type = decl.type; 62 if (type != null && type != Type.pointer_type) 63 value = type.coerceFromObject(value); 64 if (decl.isIndirectBinding()) 65 { 66 gnu.mapping.Location loc = decl.makeIndirectLocationFor(); 67 loc.set(value); 68 value = loc; 69 } 70 evalFrame[i] = value; 71 } 72 body.apply(ctx); 73 } 74 finally 75 { 76 evalFrames[level] = oldFrame; 77 } 78 } 79 80 /* CPS: 81 * Need to ensure that ctx.pc is 0 before the this is called 82 * the first time. This is currently done by match0. 83 * Need to define concention so ReferenceExp can find appropriate binding. 84 * Need to define convention for what gets copied, if anything, 85 * when a continuation is created. (Note problem below if a half-initialized 86 * frame gets captuerd. Then multiple cals to the same continuation 87 * could clobber the frame, unless it has been copied. But copying the 88 * frame is tricky if we want to avoid copying the whole stack, plus we 89 * have to correctly handle set! to a local/ 90 public void apply (CallContext ctx) throws Throwable 91 { 92 CallFrame fr; 93 if (ctx.pc == 0) 94 { 95 fr = new gnu.mapping.CallFrame(); 96 fr.previous = ctx.frame; 97 fr.saveVstackLen = ctx.startFromContext(); 98 ctx.frame = fr; 99 } 100 else 101 fr = ctx.frame; 102 int i = ctx.pc; 103 if (i == inits.length + 1) 104 { 105 // pop 106 ctx.frame = fr.previous; 107 return; 108 } 109 if (i > 0) 110 fr.values[i-1] = ctx.getFromContext(fr.saveVstackLen); 111 ctx.pc++; 112 if (i == inits.length) 113 { 114 body.match0(ctx); 115 return; 116 } 117 fr.saveVstackLen = ctx.startFromContext(); 118 inits[i].match0(ctx); 119 } 120 */ 121 compile(Compilation comp, Target target)122 public void compile (Compilation comp, Target target) 123 { 124 gnu.bytecode.CodeAttr code = comp.getCode(); 125 126 /* 127 if (comp.usingCPStyle()) 128 { 129 for (Declartion decl = firstDecl(); decl != null; decl = decl.nextDecl()) 130 { 131 decl.assignField(comp); 132 } 133 } 134 */ 135 136 /* Compile all the initializations, leaving the results 137 on the stack (in reverse order). */ 138 for (Declaration decl = firstDecl(); decl != null; decl = decl.nextDecl()) 139 { 140 Target varTarget; 141 Expression init = decl.getInitValue(); 142 boolean initialized = init != QuoteExp.undefined_exp; 143 // Does this variable need to be initialized or is the default ok? 144 boolean needsInit = ! decl.ignorable() 145 && (initialized || decl.mayBeAccessedUninitialized()); 146 147 if (needsInit && decl.isSimple()) 148 decl.allocateVariable(code); 149 150 if (! needsInit 151 || (! initialized 152 && (decl.isIndirectBinding() || ! decl.mayBeAccessedUninitialized()))) 153 varTarget = Target.Ignore; 154 else 155 { 156 Type varType = decl.getType(); 157 varTarget = CheckedTarget.getInstance(decl); 158 if (init == QuoteExp.undefined_exp) 159 { 160 // Typically created by letrec. 161 if (varType instanceof PrimType) 162 init = new QuoteExp(new Byte((byte) 0)); 163 else if (varType != null && varType != Type.pointer_type) 164 init = QuoteExp.nullExp; 165 } 166 } 167 init.compileWithPosition (comp, varTarget); 168 169 if (needsInit) 170 { 171 if (decl.isIndirectBinding()) 172 { 173 if (! initialized) 174 { 175 Object name = decl.getSymbol(); 176 comp.compileConstant(name, Target.pushObject); 177 code.emitInvokeStatic(BindingInitializer.makeLocationMethod(name)); 178 } 179 else 180 { 181 decl.pushIndirectBinding(comp); 182 } 183 } 184 if (decl.getFlag(Declaration.ALLOCATE_ON_STACK)) 185 { 186 decl.evalIndex = code.getSP(); 187 } 188 else if (initialized 189 || decl.isIndirectBinding() 190 || decl.mayBeAccessedUninitialized()) 191 decl.compileStore(comp); 192 } 193 } 194 195 code.enterScope(getVarScope()); 196 197 body.compileWithPosition(comp, target); 198 popScope(code); 199 } 200 calculateType()201 protected final gnu.bytecode.Type calculateType() 202 { 203 return body.getType(); 204 } 205 visit(ExpVisitor<R,D> visitor, D d)206 protected <R,D> R visit (ExpVisitor<R,D> visitor, D d) 207 { 208 return visitor.visitLetExp(this, d); 209 } 210 visitInitializers(ExpVisitor<R,D> visitor, D d)211 public <R,D> void visitInitializers (ExpVisitor<R,D> visitor, D d) 212 { 213 for (Declaration decl = firstDecl(); decl != null; decl = decl.nextDecl()) 214 { 215 decl.setInitValue(visitor.visitAndUpdate(decl.getInitValue(), d)); 216 } 217 } 218 visitChildren(ExpVisitor<R,D> visitor, D d)219 protected <R,D> void visitChildren (ExpVisitor<R,D> visitor, D d) 220 { 221 visitInitializers(visitor, d); 222 if (visitor.exitValue == null) 223 body = visitor.visitAndUpdate(body, d); 224 } 225 print(OutPort out)226 public void print (OutPort out) 227 { 228 print(out, "(Let", ")"); 229 } 230 print(OutPort out, String startTag, String endTag)231 public void print (OutPort out, String startTag, String endTag) 232 { 233 out.startLogicalBlock(startTag+"#"+id, endTag, 2); 234 out.writeSpaceFill(); 235 printLineColumn(out); 236 out.startLogicalBlock("(", false, ")"); 237 Declaration decl = firstDecl(); 238 int i = 0; 239 240 for (; decl != null; decl = decl.nextDecl()) 241 { 242 if (i > 0) 243 out.writeSpaceFill(); 244 out.startLogicalBlock("(", false, ")"); 245 decl.printInfo(out); 246 Expression init = decl.getInitValue(); 247 if (init != null) 248 { 249 out.writeSpaceFill(); 250 out.print('='); 251 out.writeSpaceFill(); 252 //if (decl.isArtificial ()) 253 //out.print ("<artificial>"); 254 //else 255 { 256 if (init == null) 257 out.print("<null>"); 258 else 259 init.print(out); // 260 i++; 261 } 262 } 263 out.endLogicalBlock(")"); 264 } 265 out.endLogicalBlock(")"); 266 out.writeSpaceLinear(); 267 if (body == null) 268 out.print("<null body>"); 269 else 270 body.print (out); 271 out.endLogicalBlock(endTag); 272 } 273 } 274