001: package gnu.expr;
002:
003: import gnu.bytecode.Type;
004: import gnu.mapping.*;
005:
006: /**
007: * Abstract class for syntactic forms that evaluate to a value.
008: * Scheme S-expressions get re-written to these before evaluation.
009: * @author Per Bothner
010: */
011:
012: public abstract class Expression implements Printable {
013: public Object eval(Environment env) throws Throwable {
014: throw new RuntimeException("internal error - " + getClass()
015: + ".eval called");
016: }
017:
018: public void eval(Environment env, CallContext ctx) throws Throwable {
019: Object val = eval(env);
020: ctx.writeValue(val);
021: }
022:
023: public final void print(java.io.PrintWriter ps) {
024: if (ps instanceof OutPort)
025: print((OutPort) ps);
026: else {
027: OutPort out = new OutPort(ps);
028: print(out);
029: out.flush();
030: }
031: }
032:
033: public abstract void print(OutPort ps);
034:
035: /**
036: * Print line and column number if specified.
037: * This is a helper routineintended for use by print(OutPort).
038: */
039: public void printLineColumn(OutPort out) {
040: int line = getLine();
041: if (line > 0) {
042: out.print("line:");
043: out.print(line);
044: int column = getColumn();
045: if (column != 0) {
046: out.print(':');
047: out.print(column);
048: }
049: out.writeSpaceFill();
050: }
051: }
052:
053: public abstract void compile(Compilation comp, Target target);
054:
055: /** Same as compile, but emit line number beforehard. */
056: public final void compileWithPosition(Compilation comp,
057: Target target) {
058: int line = getLine();
059: if (line > 0) {
060: comp.method.compile_linenumber(getFile(), line);
061: compileNotePosition(comp, target);
062: } else
063: compile(comp, target);
064: }
065:
066: /** Compile, but take note of line number. */
067: public final void compileNotePosition(Compilation comp,
068: Target target) {
069: String saveFilename = comp.filename;
070: int savePosition = comp.position;
071: comp.filename = filename;
072: comp.position = position;
073: compile(comp, target);
074: // This might logically belong in a `finally' clause.
075: // It is intentionally not so, so if there is an internal error causing
076: // an exception, we get the line number where the exception was thrown.
077: comp.filename = saveFilename;
078: comp.position = savePosition;
079: }
080:
081: public final void compile(Compilation comp, Type type) {
082: // Should we use Target.pushValue instead? FIXME.
083: compile(comp, StackTarget.getInstance(type));
084: }
085:
086: protected Expression walk(ExpWalker walker) {
087: return walker.walkExpression(this );
088: }
089:
090: protected void walkChildren(ExpWalker walker) {
091: }
092:
093: String filename;
094: int position;
095:
096: public static final Expression[] noExpressions = new Expression[0];
097:
098: /** Helper method to create a `while' statement. */
099: public static Expression makeWhile(Object cond, Object body,
100: Parser parser) {
101: Expression[] inits = new Expression[1];
102: LetExp let = new LetExp(inits);
103: String fname = "%do%loop";
104: Declaration fdecl = let.addDeclaration(fname);
105: Expression recurse = new ApplyExp(new ReferenceExp(fdecl),
106: noExpressions);
107: LambdaExp lexp = new LambdaExp();
108: parser.push(lexp);
109: lexp.body = new IfExp(parser.parse(cond), new BeginExp(parser
110: .parse(body), recurse), QuoteExp.voidExp);
111: lexp.setName(fname);
112: parser.pop(lexp);
113: inits[0] = lexp;
114: fdecl.noteValue(lexp);
115: let
116: .setBody(new ApplyExp(new ReferenceExp(fdecl),
117: noExpressions));
118: return let;
119: }
120:
121: public final Expression setLine(Expression old) {
122: this .filename = old.filename;
123: this .position = old.position;
124: return this ;
125: }
126:
127: public final void setFile(String filename) {
128: this .filename = filename;
129: }
130:
131: public final void setLine(int lineno, int colno) {
132: position = (lineno << 12) + colno;
133: }
134:
135: public final void setLine(int lineno) {
136: setLine(lineno, 0);
137: }
138:
139: public final String getFile() {
140: return filename;
141: }
142:
143: /** Get the line number of (the start of) this Expression.
144: * The "first" line is line 1. */
145: public final int getLine() {
146: return position >> 12;
147: }
148:
149: public final int getColumn() {
150: return position & ((1 << 12) - 1);
151: }
152:
153: public boolean hasLocation() {
154: return getFile() != null && position != 0;
155: }
156:
157: /** Return the Type used to represent the values of this Expression. */
158: public Type getType() {
159: return Type.pointer_type;
160: }
161:
162: protected int flags;
163: protected static final int NEXT_AVAIL_FLAG = 1;
164:
165: public void setFlag(boolean setting, int flag) {
166: if (setting)
167: flags |= flag;
168: else
169: flags &= ~flag;
170: }
171:
172: public void setFlag(int flag) {
173: flags |= flag;
174: }
175:
176: public int getFlags() {
177: return flags;
178: }
179:
180: public boolean getFlag(int flag) {
181: return (flags & flag) != 0;
182: }
183:
184: public Branchable getBranchable() {
185: if (this instanceof ApplyExp) {
186: Expression func = ((ApplyExp) this ).func;
187: if (func instanceof QuoteExp) {
188: Object proc = ((QuoteExp) func).getValue();
189: if (proc instanceof Branchable)
190: return (Branchable) proc;
191: }
192: }
193: return null;
194: }
195:
196: }
|