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