1 package gnu.expr;
2 import gnu.mapping.*;
3 import gnu.lists.*;
4 import gnu.bytecode.CodeAttr;
5 import gnu.kawa.io.OutPort;
6 import java.util.Vector;
7 
8 /**
9  * This class represents a sequence of Expressions.
10  * The expressions are evaluated for their side-effects,
11  * and the value of the last Expression is the result.
12  * A BeginExp may optionally have "compilation options"
13  * which can be used to control various compile-time
14  * aspects of Kawa, such as warning messages.
15  * @author	Per Bothner
16  */
17 
18 public class BeginExp extends Expression
19 {
20   Expression[] exps;
21   int length;
22 
23   /** A Vector used to remember compile options.
24    * This is used to set/reset the options in Compilations's currentOptions.
25    * Each option consists of 3 elements of the Vector:
26    * A key String that names the option;
27    * a place to save the old value of the option;
28    * the value the value the option should have during traversal
29    * (using an ExpVisitor or compilation) of this BeginExp.
30    * Note traversal is not thread-safe because the "old value" is saved
31    * in this same array.  A cleaner (future) solution might be to use
32    * a stack in the Compilation.  Since expressions (except for QuoteExp)
33    * are local to a specific Compilation, it doesn't matter.
34    */
35   Vector compileOptions;
36 
BeginExp()37   public BeginExp () { }
38 
BeginExp(Expression[] ex)39   public BeginExp (Expression[] ex) { exps = ex;  length = ex.length; }
40 
BeginExp(Expression exp0, Expression exp1)41   public BeginExp(Expression exp0, Expression exp1)
42   {
43     exps = new Expression[2];
44     exps[0] = exp0;
45     exps[1] = exp1;
46     length = 2;
47   }
48 
49   /** Simplifies BeginExp.
50    * (In the future, nested BeginExps may be "flattened" as well.)
51    */
canonicalize(Expression exp)52   public static final Expression canonicalize(Expression exp)
53   {
54     if (exp instanceof BeginExp)
55       {
56         BeginExp bexp = (BeginExp) exp;
57 	if (bexp.compileOptions != null)
58 	  return exp;
59         int len = bexp.length;
60         if (len == 0)
61           return QuoteExp.voidExp;
62         if (len == 1)
63           return canonicalize(bexp.exps[0]);
64       }
65     return exp;
66   }
67 
canonicalize(Expression[] exps)68   public static final Expression canonicalize(Expression[] exps)
69   {
70     int len = exps.length;
71     if (len == 0)
72       return QuoteExp.voidExp;
73     if (len == 1)
74       return canonicalize(exps[0]);
75     return new BeginExp(exps);
76   }
77 
add(Expression exp)78   public final void add(Expression exp)
79   {
80     if (exps == null)
81       exps = new Expression[8];
82     if (length == exps.length)
83       {
84         Expression[] ex = new Expression[2 * length];
85         System.arraycopy(exps, 0, ex, 0, length);
86         exps = ex;
87       }
88     exps[length++] = exp;
89   }
90 
getExpressions()91   public final Expression[] getExpressions() { return exps; }
getExpressionCount()92   public final int getExpressionCount() { return length; }
93 
setExpressions(Expression[] exps)94   public final void setExpressions(Expression[] exps)
95   {
96     this.exps = exps;
97     length = exps.length;
98   }
99 
setCompileOptions(Vector options)100   public void setCompileOptions (Vector options)
101   {
102     compileOptions = options;
103   }
104 
mustCompile()105   protected boolean mustCompile () { return false; }
106 
107   @Override
apply(CallContext ctx)108   public void apply (CallContext ctx) throws Throwable
109   {
110     int n = length;
111     int i;
112     Consumer consumerSave = ctx.consumer;
113     ctx.consumer = VoidConsumer.instance;
114     try
115       {
116 	for (i = 0; i < n - 1; i++)
117 	  exps[i].eval(ctx);
118       }
119     finally
120       {
121 	ctx.consumer = consumerSave;
122       }
123     exps[i].apply(ctx);
124   }
125 
pushOptions(Compilation comp)126   public void pushOptions (Compilation comp)
127   {
128     if (compileOptions != null && comp != null)
129       comp.currentOptions.pushOptionValues(compileOptions);
130   }
131 
popOptions(Compilation comp)132   public void popOptions (Compilation comp)
133   {
134     if (compileOptions != null && comp != null)
135       comp.currentOptions.popOptionValues(compileOptions);
136   }
137 
compile(Compilation comp, Target target)138   public void compile (Compilation comp, Target target)
139   {
140     pushOptions(comp);
141     try
142       {
143 	int n = length, i;
144         CodeAttr code = comp.getCode();
145 	for (i = 0; i < n - 1; i++)
146           {
147             exps[i].compileWithPosition(comp, Target.Ignore);
148             if (! code.reachableHere())
149               {
150                 if (comp.warnUnreachable())
151                   comp.error('w', "unreachable code", exps[i+1]);
152                 return;
153               }
154           }
155 	exps[i].compileWithPosition(comp, target);
156       }
157     finally
158       {
159 	popOptions(comp);
160       }
161   }
162 
visit(ExpVisitor<R,D> visitor, D d)163   protected <R,D> R visit (ExpVisitor<R,D> visitor, D d)
164   {
165     pushOptions(visitor.comp);
166     try
167       {
168         return visitor.visitBeginExp(this, d);
169       }
170     finally
171       {
172 	popOptions(visitor.comp);
173       }
174   }
175 
visitChildren(ExpVisitor<R,D> visitor, D d)176   protected <R,D> void visitChildren (ExpVisitor<R,D> visitor, D d)
177   {
178     exps = visitor.visitExps(exps, length, d);
179   }
180 
print(OutPort out)181   public void print (OutPort out)
182   {
183     out.startLogicalBlock("(Begin", ")", 2);
184     out.writeSpaceFill();
185     printLineColumn(out);
186     out.writeShowHideButton(true);
187     out.startHiderSection(true);
188     if (compileOptions != null)
189       {
190 	out.writeSpaceFill();
191 	out.startLogicalBlock("(CompileOptions", ")", 2);
192 	int sizeOptions = compileOptions.size();
193 	for (int i = 0;  i < sizeOptions;  i += 3)
194 	  {
195 	    Object key = compileOptions.elementAt(i);
196 	    Object value = compileOptions.elementAt(i+2);
197 	    out.writeSpaceFill();
198 	    out.startLogicalBlock("", "", 2);
199 	    out.print(key);  out.print(':');
200 	    out.writeSpaceLinear();
201 	    out.print(value);
202 	    out.endLogicalBlock("");
203 	  }
204 	out.endLogicalBlock(")");
205       }
206     int n = length;
207     for (int i = 0; i < n; i++)
208       {
209 	out.writeSpaceLinear();
210 	exps[i].print(out);
211       }
212     out.endHiderSection();
213     out.endLogicalBlock(")");
214   }
215 
calculateType()216   protected gnu.bytecode.Type calculateType()
217   {
218     return exps[length - 1].getType();
219   }
220 
221     /* DEBUGGING:
222     private static int counter; int id = ++counter;
223     public String toString() { return "BeginExp#"+id+"[len:"+length+"]"; }
224     END DEBUGGING */
225 }
226