001: package gnu.expr;
002:
003: import gnu.mapping.*;
004: import java.util.Vector;
005: import gnu.lists.*;
006:
007: /**
008: * This class represents a sequence of Expressions.
009: * The expressions are evaluated for their side-effects,
010: * and the value of the last Expression is the result.
011: * A BeginExp may optionally have "compilation options"
012: * which can be used to control various compile-time
013: * aspects of Kawa, such as warning messages.
014: * @author Per Bothner
015: */
016:
017: public class BeginExp extends Expression {
018: Expression[] exps;
019: int length;
020:
021: /** A Vector used to remember compile options.
022: * This is used to set/reset the options in Compilations's currentOptions.
023: * Each option consists of 3 elements of the Vector:
024: * A key String that names the option;
025: * a place to save the old value of the option;
026: * the value the value the option should have during traversal
027: * (using an ExpWalker or compilation) of this BeginExp.
028: * Note traversal is not thread-safe because the "old value" is saved
029: * in this same array. A cleaner (future) solution might be to use
030: * a stack in the Compilation. Since expressions (except for QuoteExp)
031: * are local to a specific Compilation, it doesn't matter.
032: */
033: Vector compileOptions;
034:
035: public BeginExp() {
036: }
037:
038: public BeginExp(Expression[] ex) {
039: exps = ex;
040: length = ex.length;
041: }
042:
043: public BeginExp(Expression exp0, Expression exp1) {
044: exps = new Expression[2];
045: exps[0] = exp0;
046: exps[1] = exp1;
047: length = 2;
048: }
049:
050: /** Simplifies BeginExp.
051: * (In the future, nested BeginExps may be "flattened" as well.)
052: */
053: public static final Expression canonicalize(Expression exp) {
054: if (exp instanceof BeginExp) {
055: BeginExp bexp = (BeginExp) exp;
056: if (bexp.compileOptions != null)
057: return exp;
058: int len = bexp.length;
059: if (len == 0)
060: return QuoteExp.voidExp;
061: if (len == 1)
062: return canonicalize(bexp.exps[0]);
063: }
064: return exp;
065: }
066:
067: public static final Expression canonicalize(Expression[] exps) {
068: int len = exps.length;
069: if (len == 0)
070: return QuoteExp.voidExp;
071: if (len == 1)
072: return canonicalize(exps[0]);
073: return new BeginExp(exps);
074: }
075:
076: public final void add(Expression exp) {
077: if (exps == null)
078: exps = new Expression[8];
079: if (length == exps.length) {
080: Expression[] ex = new Expression[2 * length];
081: System.arraycopy(exps, 0, ex, 0, length);
082: exps = ex;
083: }
084: exps[length++] = exp;
085: }
086:
087: public final Expression[] getExpressions() {
088: return exps;
089: }
090:
091: public final int getExpressionCount() {
092: return length;
093: }
094:
095: public final void setExpressions(Expression[] exps) {
096: this .exps = exps;
097: length = exps.length;
098: }
099:
100: public void setCompileOptions(Vector options) {
101: compileOptions = options;
102: }
103:
104: protected boolean mustCompile() {
105: return false;
106: }
107:
108: public void apply(CallContext ctx) throws Throwable {
109: int n = length;
110: int i;
111: Consumer consumerSave = ctx.consumer;
112: ctx.consumer = VoidConsumer.instance;
113: try {
114: for (i = 0; i < n - 1; i++)
115: exps[i].eval(ctx);
116: } finally {
117: ctx.consumer = consumerSave;
118: }
119: exps[i].apply(ctx);
120: }
121:
122: public void pushOptions(Compilation comp) {
123: if (compileOptions != null && comp != null)
124: comp.currentOptions.pushOptionValues(compileOptions);
125: }
126:
127: public void popOptions(Compilation comp) {
128: if (compileOptions != null && comp != null)
129: comp.currentOptions.popOptionValues(compileOptions);
130: }
131:
132: public void compile(Compilation comp, Target target) {
133: pushOptions(comp);
134: try {
135: int n = length, i;
136: for (i = 0; i < n - 1; i++)
137: exps[i].compileWithPosition(comp, Target.Ignore);
138: exps[i].compileWithPosition(comp, target);
139: } finally {
140: popOptions(comp);
141: }
142: }
143:
144: protected Expression walk(ExpWalker walker) {
145: return walker.walkBeginExp(this );
146: }
147:
148: protected void walkChildren(ExpWalker walker) {
149: pushOptions(walker.comp);
150: try {
151: exps = walker.walkExps(exps, length);
152: } finally {
153: popOptions(walker.comp);
154: }
155: }
156:
157: public void print(OutPort out) {
158: out.startLogicalBlock("(Begin", ")", 2);
159: out.writeSpaceFill();
160: printLineColumn(out);
161: if (compileOptions != null) {
162: out.writeSpaceFill();
163: out.startLogicalBlock("(CompileOptions", ")", 2);
164: int sizeOptions = compileOptions.size();
165: for (int i = 0; i < sizeOptions; i += 3) {
166: Object key = compileOptions.elementAt(i);
167: Object value = compileOptions.elementAt(i + 2);
168: out.writeSpaceFill();
169: out.startLogicalBlock("", "", 2);
170: out.print(key);
171: out.print(':');
172: out.writeSpaceLinear();
173: out.print(value);
174: out.endLogicalBlock("");
175: }
176: out.endLogicalBlock(")");
177: }
178: int n = length;
179: for (int i = 0; i < n; i++) {
180: out.writeSpaceLinear();
181: exps[i].print(out);
182: }
183: out.endLogicalBlock(")");
184: }
185:
186: public gnu.bytecode.Type getType() {
187: return exps[length - 1].getType();
188: }
189: }
|