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