From 3ab44d1c726c06f8843dee1601b0142fe94c3478 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:00:45 +0000 Subject: [PATCH] 2003/06/05 00:12:17 darcs-hash:20040130070045-2ba56-bc5514d5eb76cbc958938f3b8975243110481c98.gz --- src/org/xwt/js/ForthBlock.java | 531 +++++++++++++++++++--------------------- src/org/xwt/js/OpCodes.java | 71 ++++++ src/org/xwt/js/Parser.java | 82 +++---- 3 files changed, 362 insertions(+), 322 deletions(-) create mode 100644 src/org/xwt/js/OpCodes.java diff --git a/src/org/xwt/js/ForthBlock.java b/src/org/xwt/js/ForthBlock.java index 6946258..43607be 100644 --- a/src/org/xwt/js/ForthBlock.java +++ b/src/org/xwt/js/ForthBlock.java @@ -5,318 +5,287 @@ import org.xwt.util.*; import java.io.*; /** a block of Forth bytecode */ -class ForthBlock implements Tokens { +class ForthBlock implements OpCodes, Tokens { - /* - * Each instruction is an opcode and an optional literal literal. - */ + int line; + String sourceName; + int[] op = new int[10]; + Object[] arg = new Object[10]; + int size = 0; - // opcodes: - public static final byte arithmetic = -1; // -- arithmetic operators from parser - public static final byte LITERAL = -2; // < String | Number | null > -- push a literal onto the stack - public static final byte ARRAY = -3; // < size > -- create a new array of size - public static final byte OBJECT = -4; // -- push an empty object onto the stack - public static final byte FUNCTION = -5; // < bytecode_block > -- push a new instance of a function with the given bytecode - public static final byte DECLARE = -6; // < name > -- declare in the current scope - public static final byte THIS = -7; // -- push the topmost non-transparent scope onto the stack - public static final byte GET = -8; // -- get stack[0] from stack[1] - public static final byte GET_PRESERVE = -80; // -- get stack[0] from stack[1] - public static final byte PUT = -9; // -- put stack[1] to key stack[0] on stack[2]; leaves object on the stack - public static final byte JT = -13; // < relative_address > -- pop the stack; if true, jump to - public static final byte JF = -21; // < relative_address > -- pop the stack; if false, jump to - public static final byte JMP = -22; // < relative_address > -- jump to - static public final byte POP = -14; // -- discard the top element on the stack + public ForthBlock(int line, String sourceName) { this.line = line; this.sourceName = sourceName; } + public ForthBlock(int line, String sourceName, int op_, Object arg_) { this(line, sourceName); add(op_, arg_); } - public static final byte CALL = -15; // < numargs > -- call stack[0] with the topmost values as arguments - - public static final byte PUSHKEYS = -19; // -- ?? - public static final byte EXPR = -20; // -- transitional - public static final byte SWAP = -23; // -- transitional - public static final byte SCOPE = -30; // -- transitional - public static final byte LOOP = -40; // -- transitional - public static final byte DUP = -50; // -- transitional - public static final byte LABEL = -60; // -- transitional - - int line; - String sourceName; - int[] op = new int[10]; - Object[] arg = new Object[10]; - int size = 0; - - public ForthBlock(int line, String sourceName) { this.line = line; this.sourceName = sourceName; } - public ForthBlock(int line, String sourceName, int op_, Object arg_) { this(line, sourceName); add(op_, arg_); } - - public int size() { return size; } - public void set(int pos, int op_, Object arg_) { op[pos] = op_; arg[pos] = arg_; } - public ForthBlock add(int op_) { return add(op_, null); } - public ForthBlock add(int op_, Object arg_) { - if (size == op.length - 1) { - int[] op2 = new int[op.length * 2]; System.arraycopy(op, 0, op2, 0, op.length); op = op2; - Object[] arg2 = new Object[op.length * 2]; System.arraycopy(arg, 0, arg2, 0, arg.length); arg = arg2; - } - op[size] = op_; - arg[size] = arg_; - size++; - return this; + public int size() { return size; } + public void set(int pos, int op_, Object arg_) { op[pos] = op_; arg[pos] = arg_; } + public ForthBlock add(int op_) { return add(op_, null); } + public ForthBlock add(int op_, Object arg_) { + if (size == op.length - 1) { + int[] op2 = new int[op.length * 2]; System.arraycopy(op, 0, op2, 0, op.length); op = op2; + Object[] arg2 = new Object[op.length * 2]; System.arraycopy(arg, 0, arg2, 0, arg.length); arg = arg2; } + op[size] = op_; + arg[size] = arg_; + size++; + return this; + } - public Object eval(final JS.Scope s) throws ControlTransferException, JS.Exn { - return eval(s, new Stack()); - } - public Object eval(final JS.Scope s, Stack t) throws ControlTransferException { - for(int i=0; i= 0; j--) arguments.setElementAt(t.pop(), j); - JS.Function f = (JS.Function)t.pop(); - if (f == null) throw new JS.Exn(new EvaluatorException(line, sourceName, "attempted to call null")); - t.push(f.call(arguments)); - break; - } + case CALL: { + JS.Array arguments = new JS.Array(); + int numArgs = JS.toNumber(arg[i]).intValue(); + arguments.setSize(numArgs); + for(int j=numArgs - 1; j >= 0; j--) arguments.setElementAt(t.pop(), j); + JS.Function f = (JS.Function)t.pop(); + if (f == null) throw new JS.Exn(new EvaluatorException(line, sourceName, "attempted to call null")); + t.push(f.call(arguments)); + break; + } - case FUNCTION: { - final ForthBlock myBytes = (ForthBlock)arg[i]; - t.push(new JS.Function() { - public String toString() { return sourceName + ":" + line; } - public String getSourceName() throws JS.Exn { return sourceName; } - public Object _call(final JS.Array args) throws JS.Exn { - Function save = JS.getCurrentFunction(); - JS.currentFunction.put(java.lang.Thread.currentThread(), this); - JS.Scope scope = new JS.Scope(s) { - // FIXME - public String getSourceName() { return sourceName; } - public Object get(Object key) throws JS.Exn { - if (key.equals("trapee")) return org.xwt.Trap.currentTrapee(); - else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction; - return super.get(key); - } - }; - Stack t0 = new Stack(); - t0.push(args); - try { - return myBytes.eval(scope, t0); - } catch (ReturnException r) { - return r.retval; - } catch (ControlTransferException c) { - throw new EvaluatorException(line, sourceName, "error, ControlTransferException tried to leave a function: " + c); - } finally { - if (save == null) JS.currentFunction.remove(java.lang.Thread.currentThread()); - else JS.currentFunction.put(java.lang.Thread.currentThread(), save); - } + case OpCodes.FUNCTION: { + final ForthBlock myBytes = (ForthBlock)arg[i]; + t.push(new JS.Function() { + public String toString() { return sourceName + ":" + line; } + public String getSourceName() throws JS.Exn { return sourceName; } + public Object _call(final JS.Array args) throws JS.Exn { + Function save = JS.getCurrentFunction(); + JS.currentFunction.put(java.lang.Thread.currentThread(), this); + JS.Scope scope = new JS.Scope(s) { + // FIXME + public String getSourceName() { return sourceName; } + public Object get(Object key) throws JS.Exn { + if (key.equals("trapee")) return org.xwt.Trap.currentTrapee(); + else if (key.equals("cascade")) return org.xwt.Trap.cascadeFunction; + return super.get(key); + } + }; + Stack t0 = new Stack(); + t0.push(args); + try { + return myBytes.eval(scope, t0); + } catch (ReturnException r) { + return r.retval; + } catch (ControlTransferException c) { + throw new EvaluatorException(line, sourceName, "error, ControlTransferException tried to leave a function: " + c); + } finally { + if (save == null) JS.currentFunction.remove(java.lang.Thread.currentThread()); + else JS.currentFunction.put(java.lang.Thread.currentThread(), save); } - }); - break; - } + } + }); + break; + } - case Lexer.INC: case Lexer.DEC: { - boolean isPrefix = JS.toBoolean(arg[i]); - Object key = t.pop(); - JS obj = (JS)t.pop(); - Number num = JS.toNumber(obj.get(key)); - Number val = new Double(op[i] == Lexer.INC ? num.doubleValue() + 1.0 : num.doubleValue() - 1.0); - obj.put(key, val); - t.push(isPrefix ? val : num); - break; - } + case Lexer.INC: case Lexer.DEC: { + boolean isPrefix = JS.toBoolean(arg[i]); + Object key = t.pop(); + JS obj = (JS)t.pop(); + Number num = JS.toNumber(obj.get(key)); + Number val = new Double(op[i] == Lexer.INC ? num.doubleValue() + 1.0 : num.doubleValue() - 1.0); + obj.put(key, val); + t.push(isPrefix ? val : num); + break; + } - default: { - Object right = t.pop(); - Object left = t.pop(); - switch(op[i]) { + default: { + Object right = t.pop(); + Object left = t.pop(); + switch(op[i]) { - case Lexer.BITOR: t.push(new Long(JS.toLong(left) | JS.toLong(right))); break; - case Lexer.BITXOR: t.push(new Long(JS.toLong(left) ^ JS.toLong(right))); break; - case Lexer.BITAND: t.push(new Long(JS.toLong(left) & JS.toLong(right))); break; + case Lexer.BITOR: t.push(new Long(JS.toLong(left) | JS.toLong(right))); break; + case Lexer.BITXOR: t.push(new Long(JS.toLong(left) ^ JS.toLong(right))); break; + case Lexer.BITAND: t.push(new Long(JS.toLong(left) & JS.toLong(right))); break; - case Lexer.ADD: { - Object l = left; - Object r = right; - if (l instanceof String || r instanceof String) { - if (l == null) l = "null"; - if (r == null) r = "null"; - if (l instanceof Number && ((Number)l).doubleValue() == ((Number)l).longValue()) - l = new Long(((Number)l).longValue()); - if (r instanceof Number && ((Number)r).doubleValue() == ((Number)r).longValue()) - r = new Long(((Number)r).longValue()); - t.push(l.toString() + r.toString()); break; - } - t.push(new Double(JS.toDouble(l) + JS.toDouble(r))); break; + case Lexer.ADD: { + Object l = left; + Object r = right; + if (l instanceof String || r instanceof String) { + if (l == null) l = "null"; + if (r == null) r = "null"; + if (l instanceof Number && ((Number)l).doubleValue() == ((Number)l).longValue()) + l = new Long(((Number)l).longValue()); + if (r instanceof Number && ((Number)r).doubleValue() == ((Number)r).longValue()) + r = new Long(((Number)r).longValue()); + t.push(l.toString() + r.toString()); break; } + t.push(new Double(JS.toDouble(l) + JS.toDouble(r))); break; + } - case Lexer.SUB: t.push(new Double(JS.toDouble(left) - JS.toDouble(right))); break; - case Lexer.MUL: t.push(new Double(JS.toDouble(left) * JS.toDouble(right))); break; - case Lexer.DIV: t.push(new Double(JS.toDouble(left) / JS.toDouble(right))); break; - case Lexer.MOD: t.push(new Double(JS.toDouble(left) % JS.toDouble(right))); break; + case Lexer.SUB: t.push(new Double(JS.toDouble(left) - JS.toDouble(right))); break; + case Lexer.MUL: t.push(new Double(JS.toDouble(left) * JS.toDouble(right))); break; + case Lexer.DIV: t.push(new Double(JS.toDouble(left) / JS.toDouble(right))); break; + case Lexer.MOD: t.push(new Double(JS.toDouble(left) % JS.toDouble(right))); break; - case Lexer.LSH: t.push(new Long(JS.toLong(left) << JS.toLong(right))); break; - case Lexer.RSH: t.push(new Long(JS.toLong(left) >> JS.toLong(right))); break; - case Lexer.URSH: t.push(new Long(JS.toLong(left) >>> JS.toLong(right))); break; + case Lexer.LSH: t.push(new Long(JS.toLong(left) << JS.toLong(right))); break; + case Lexer.RSH: t.push(new Long(JS.toLong(left) >> JS.toLong(right))); break; + case Lexer.URSH: t.push(new Long(JS.toLong(left) >>> JS.toLong(right))); break; - // FIXME: these need to work on strings - case Lexer.LT: t.push(JS.toDouble(left) < JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - case Lexer.LE: t.push(JS.toDouble(left) <= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - case Lexer.GT: t.push(JS.toDouble(left) > JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - case Lexer.GE: t.push(JS.toDouble(left) >= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + // FIXME: these need to work on strings + case Lexer.LT: t.push(JS.toDouble(left) < JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + case Lexer.LE: t.push(JS.toDouble(left) <= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + case Lexer.GT: t.push(JS.toDouble(left) > JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; + case Lexer.GE: t.push(JS.toDouble(left) >= JS.toDouble(right) ? Boolean.TRUE : Boolean.FALSE); break; - case Lexer.EQ: - case Lexer.NE: { - // FIXME: should use Javascript coercion-equality rules - Object l = left; - Object r = right; - boolean ret; - if (l == null) { Object tmp = r; r = l; l = tmp; } - if (l == null && r == null) ret = true; - else if (l instanceof Boolean) ret = new Boolean(JS.toBoolean(r)).equals(l); - else if (l instanceof Number) ret = JS.toNumber(r).doubleValue() == JS.toNumber(l).doubleValue(); - else if (l instanceof String) ret = r != null && l.equals(r.toString()); - else ret = l.equals(r); - t.push(new Boolean(op[i] == Lexer.EQ ? ret : !ret)); break; - } - - default: throw new Error("unknown opcode " + op[i]); - } } + case Lexer.EQ: + case Lexer.NE: { + // FIXME: should use Javascript coercion-equality rules + Object l = left; + Object r = right; + boolean ret; + if (l == null) { Object tmp = r; r = l; l = tmp; } + if (l == null && r == null) ret = true; + else if (l instanceof Boolean) ret = new Boolean(JS.toBoolean(r)).equals(l); + else if (l instanceof Number) ret = JS.toNumber(r).doubleValue() == JS.toNumber(l).doubleValue(); + else if (l instanceof String) ret = r != null && l.equals(r.toString()); + else ret = l.equals(r); + t.push(new Boolean(op[i] == Lexer.EQ ? ret : !ret)); break; } - if (t.size() != 1) { - throw new EvaluatorException(line, sourceName, "eval() terminated with " + t.size() + " elements on the stack; one expected"); + + default: throw new Error("unknown opcode " + op[i]); + } } } - return t.pop(); + if (t.size() != 1) { + throw new EvaluatorException(line, sourceName, "eval() terminated with " + t.size() + " elements on the stack; one expected"); } + return t.pop(); + } - public Object doGet(final Object o, final Object v) { - if (o == null) throw new EvaluatorException(line, sourceName, "tried to get property \"" + v + "\" from the null value"); - if (o instanceof String) { - if (v.equals("length")) return new Integer(((String)o).length()); - else if (v.equals("substring")) return new JS.Function() { - public Object _call(JS.Array args) { - if (args.length() == 1) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue()); - else if (args.length() == 2) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue(), - JS.toNumber(args.elementAt(1)).intValue()); - else throw new Error("String.substring() can only take one or two arguments"); - } - }; - else if (v.equals("toLowerCase")) return new JS.Function() { - public Object _call(JS.Array args) { - return ((String)o).toLowerCase(); - } }; - else if (v.equals("toUpperCase")) return new JS.Function() { - public Object _call(JS.Array args) { - return ((String)o).toString().toUpperCase(); - } }; - else if (v.equals("charAt")) return new JS.Function() { - public Object _call(JS.Array args) { - return ((String)o).charAt(JS.toNumber(args.elementAt(0)).intValue()) + ""; - } }; - else if (v.equals("lastIndexOf")) return new JS.Function() { - public Object _call(JS.Array args) { - if (args.length() != 1) return null; - return new Integer(((String)o).lastIndexOf(args.elementAt(0).toString())); - } }; - else if (v.equals("indexOf")) return new JS.Function() { - public Object _call(JS.Array args) { - if (args.length() != 1) return null; - return new Integer(((String)o).indexOf(args.elementAt(0).toString())); - } }; - throw new Error("Not Implemented: propery " + v + " on String objects"); - } else if (o instanceof Boolean) { - throw new Error("Not Implemented: properties on Boolean objects"); - } else if (o instanceof Number) { - Log.log(this, "Not Implemented: properties on Number objects"); - return null; - //throw new Error("Not Implemented: properties on Number objects"); - } else if (o instanceof JS) { - return ((JS)o).get(v); - } + public Object doGet(final Object o, final Object v) { + if (o == null) throw new EvaluatorException(line, sourceName, "tried to get property \"" + v + "\" from the null value"); + if (o instanceof String) { + if (v.equals("length")) return new Integer(((String)o).length()); + else if (v.equals("substring")) return new JS.Function() { + public Object _call(JS.Array args) { + if (args.length() == 1) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue()); + else if (args.length() == 2) return ((String)o).substring(JS.toNumber(args.elementAt(0)).intValue(), + JS.toNumber(args.elementAt(1)).intValue()); + else throw new Error("String.substring() can only take one or two arguments"); + } + }; + else if (v.equals("toLowerCase")) return new JS.Function() { + public Object _call(JS.Array args) { + return ((String)o).toLowerCase(); + } }; + else if (v.equals("toUpperCase")) return new JS.Function() { + public Object _call(JS.Array args) { + return ((String)o).toString().toUpperCase(); + } }; + else if (v.equals("charAt")) return new JS.Function() { + public Object _call(JS.Array args) { + return ((String)o).charAt(JS.toNumber(args.elementAt(0)).intValue()) + ""; + } }; + else if (v.equals("lastIndexOf")) return new JS.Function() { + public Object _call(JS.Array args) { + if (args.length() != 1) return null; + return new Integer(((String)o).lastIndexOf(args.elementAt(0).toString())); + } }; + else if (v.equals("indexOf")) return new JS.Function() { + public Object _call(JS.Array args) { + if (args.length() != 1) return null; + return new Integer(((String)o).indexOf(args.elementAt(0).toString())); + } }; + throw new Error("Not Implemented: propery " + v + " on String objects"); + } else if (o instanceof Boolean) { + throw new Error("Not Implemented: properties on Boolean objects"); + } else if (o instanceof Number) { + Log.log(this, "Not Implemented: properties on Number objects"); return null; + //throw new Error("Not Implemented: properties on Number objects"); + } else if (o instanceof JS) { + return ((JS)o).get(v); } + return null; + } static class Stack { public Object[] os = new Object[256]; diff --git a/src/org/xwt/js/OpCodes.java b/src/org/xwt/js/OpCodes.java new file mode 100644 index 0000000..a2a24e7 --- /dev/null +++ b/src/org/xwt/js/OpCodes.java @@ -0,0 +1,71 @@ +// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +package org.xwt.js; + +/** each instruction is an opcode and an optional literal literal. */ +public interface OpCodes { + + /** push the literal onto the stack */ + public static final byte LITERAL = -2; + + /** push a new array onto the stack with length equal to the literal */ + public static final byte ARRAY = -3; + + /** push an empty object onto the stack */ + public static final byte OBJECT = -4; + + /** create a new instance; literal is a reference to the corresponding ForthBlock */ + public static final byte FUNCTION = -5; + + /** pop a string off the stack and declare it in the current scope */ + public static final byte DECLARE = -6; + + /** push a reference to the current scope onto the stack */ + public static final byte THIS = -7; + + /** pop two elements off the stack; push stack[-1].get(stack[top]) */ + public static final byte GET = -8; + + /** push stack[-1].get(stack[top]) */ + public static final byte GET_PRESERVE = -80; + + /** pop two elements off the stack; stack[-2].put(stack[-1], stack[top]); push stack[top] */ + public static final byte PUT = -9; + + /** literal is a relative address; pop stacktop and jump if the value is true */ + public static final byte JT = -13; + + /** literal is a relative address; pop stacktop and jump if the value is false */ + public static final byte JF = -21; + + /** literal is a relative address; jump to it */ + public static final byte JMP = -22; + + /** discard the top stack element */ + static public final byte POP = -14; + + /** pop two elements; call stack[-1](stack[top]) where stacktop is a JS.Array */ + public static final byte CALL = -15; + + /** pop an element; push a JS.Array containing the keys of the popped element */ + public static final byte PUSHKEYS = -19; + + /** FIXME: execute the ForthBlock pointed to by the literal */ + public static final byte EXPR = -20; + + /** swap the top two elements on the stack */ + public static final byte SWAP = -23; + + /** execute the ForthBlock pointed to by the literal in a fresh scope with parentScope==THIS */ + public static final byte SCOPE = -30; + + /** push a copy of the top stack element */ + public static final byte DUP = -50; + + /** declare a label */ + public static final byte LABEL = -60; + + /** execute the ForthBlock pointed to by the literal until BREAK encountered; push TRUE onto the stack for the first iteration + * and FALSE for all subsequent iterations */ + public static final byte LOOP = -40; + +} diff --git a/src/org/xwt/js/Parser.java b/src/org/xwt/js/Parser.java index 0a8fa22..67cb0a1 100644 --- a/src/org/xwt/js/Parser.java +++ b/src/org/xwt/js/Parser.java @@ -5,7 +5,7 @@ import org.xwt.util.*; import java.io.*; /** parses a stream of lexed tokens into ForthBlock's */ -public class Parser extends Lexer { +public class Parser extends Lexer implements OpCodes { // Constructors ////////////////////////////////////////////////////// @@ -91,7 +91,7 @@ public class Parser extends Lexer { case VAR: { if (prefix != null) { pushBackToken(); return prefix; } ForthBlock b = new ForthBlock(curLine, sourceName); - b.add(b.THIS); + b.add(OpCodes.THIS); while(true) { consume(NAME); String name = string; @@ -107,7 +107,7 @@ public class Parser extends Lexer { if (peekToken() != COMMA) break; consume(COMMA); } - return b; + return parseSingleForthBlock(b, minPrecedence); } case IN: pushBackToken(); return prefix; @@ -121,10 +121,10 @@ public class Parser extends Lexer { b.add(b.JF, new Integer(3)); b.add(b.EXPR, parseStatement(false)); b.add(b.JMP, new Integer(2)); - if (peekToken() != ELSE) return b.add(b.LITERAL, null); + if (peekToken() != ELSE) return parseSingleForthBlock(b.add(b.LITERAL, null), minPrecedence); consume(ELSE); b.add(b.EXPR, parseStatement(false)); - return b; + return parseSingleForthBlock(b, minPrecedence); } // FIXME: ugly hack!! @@ -147,7 +147,7 @@ public class Parser extends Lexer { b.add(b.PUT); b.add(b.SWAP); b.add(b.POP); - return b; + return parseSingleForthBlock(b, minPrecedence); } case INC: case DEC: @@ -155,19 +155,19 @@ public class Parser extends Lexer { // prefix ForthBlock b = (ForthBlock)parseMaximalForthBlock(null, precedence[tok]); b.set(b.size() - 1, tok, new Boolean(true)); - return b; + return parseSingleForthBlock(b, minPrecedence); } else { // postfix ForthBlock b = (ForthBlock)prefix; b.set(b.size() - 1, tok, new Boolean(false)); - return b; + return parseSingleForthBlock(b, minPrecedence); } case LP: if (prefix == null) { // grouping ForthBlock b = new ForthBlock(curLine, sourceName, ForthBlock.EXPR, parseMaximalForthBlock()); consume(RP); - return b; + return parseSingleForthBlock(b, minPrecedence); } else { // invocation ForthBlock b = new ForthBlock(curLine, sourceName); @@ -181,7 +181,7 @@ public class Parser extends Lexer { } consume(RP); b.add(b.CALL, new Integer(i)); - return b; + return parseSingleForthBlock(b, minPrecedence); } case BANG: case BITNOT: case INSTANCEOF: case TYPEOF: { @@ -189,13 +189,13 @@ public class Parser extends Lexer { ForthBlock b = new ForthBlock(curLine, sourceName); b.add(b.EXPR, parseMaximalForthBlock(null, precedence[tok])); b.add(tok); - return b; + return parseSingleForthBlock(b, minPrecedence); } case SUB: if (prefix == null && peekToken() == NUMBER) { getToken(); - return new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, new Double(number.doubleValue() * -1)); + return parseSingleForthBlock(new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, new Double(number.doubleValue() * -1)), minPrecedence); } // else fall through case BITOR: case BITXOR: case BITAND: case SHEQ: case SHNE: case LSH: case RSH: case URSH: case ADD: case MUL: case DIV: case MOD: @@ -205,7 +205,7 @@ public class Parser extends Lexer { b.add(b.EXPR, prefix); b.add(b.EXPR, parseMaximalForthBlock(null, precedence[tok])); b.add(tok); - return b; + return parseSingleForthBlock(b, minPrecedence); } // includes short-circuit logic @@ -217,7 +217,7 @@ public class Parser extends Lexer { b.add(tok == AND ? b.JF : b.JT, new Integer(3)); b.add(b.POP); b.add(b.EXPR, parseMaximalForthBlock(null, precedence[tok])); - return b; + return parseSingleForthBlock(b, minPrecedence); } case WITH: throw new ParserException("XWT does not allow the WITH keyword"); @@ -225,21 +225,21 @@ public class Parser extends Lexer { case NUMBER: if (prefix != null) { pushBackToken(); return prefix; } - return new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, number); + return parseSingleForthBlock(new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, number), minPrecedence); case STRING: if (prefix != null) { pushBackToken(); return prefix; } - return new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, string); + return parseSingleForthBlock(new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, string), minPrecedence); case NULL: case TRUE: case FALSE: case NOP: if (prefix != null) { pushBackToken(); return prefix; } - return new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, (tok == NULL || tok == NOP) ? null : new Boolean(tok == TRUE)); + return parseSingleForthBlock(new ForthBlock(curLine, sourceName, ForthBlock.LITERAL, (tok == NULL || tok == NOP) ? null : new Boolean(tok == TRUE)), minPrecedence); case COMMA: pushBackToken(); return prefix; - case THIS: + case Tokens.THIS: if (prefix != null) { pushBackToken(); return prefix; } - return new ForthBlock(curLine, sourceName, ForthBlock.THIS, null); + return parseSingleForthBlock(new ForthBlock(curLine, sourceName, OpCodes.THIS, null), minPrecedence); case NAME: { if (prefix != null) { pushBackToken(); return prefix; } @@ -247,18 +247,18 @@ public class Parser extends Lexer { ForthBlock b = new ForthBlock(curLine, sourceName); if (peekToken() == ASSIGN) { consume(ASSIGN); - b.add(ForthBlock.THIS); + b.add(OpCodes.THIS); b.add(ForthBlock.LITERAL, name); b.add(ForthBlock.EXPR, parseMaximalForthBlock(null, minPrecedence)); b.add(ForthBlock.PUT); b.add(ForthBlock.SWAP); b.add(ForthBlock.POP); - return b; + return parseSingleForthBlock(b, minPrecedence); } else { - b.add(ForthBlock.THIS); + b.add(OpCodes.THIS); b.add(ForthBlock.LITERAL, name); b.add(ForthBlock.GET); - return parseMaximalForthBlock(b, minPrecedence); + return parseSingleForthBlock(parseMaximalForthBlock(b, minPrecedence), minPrecedence); } } @@ -279,7 +279,7 @@ public class Parser extends Lexer { b.add(b.LITERAL, target); b.add(b.GET); } - return b; + return parseSingleForthBlock(b, minPrecedence); } case LB: { @@ -289,13 +289,13 @@ public class Parser extends Lexer { int i = 0; while(true) { ForthBlock e = parseMaximalForthBlock(); - if (e == null && peekToken() == RB) { consume(RB); return b; } + if (e == null && peekToken() == RB) { consume(RB); return parseSingleForthBlock(b, minPrecedence); } b.add(b.LITERAL, new Integer(i++)); if (e == null) b.add(b.LITERAL, null); else b.add(b.EXPR, e); b.add(b.PUT); b.add(b.POP); - if (peekToken() == RB) { consume(RB); return b; } + if (peekToken() == RB) { consume(RB); return parseSingleForthBlock(b, minPrecedence); } consume(COMMA); } } else { @@ -311,7 +311,7 @@ public class Parser extends Lexer { } else { b.add(b.GET); } - return b; + return parseSingleForthBlock(b, minPrecedence); } } @@ -319,7 +319,7 @@ public class Parser extends Lexer { if (prefix != null) { pushBackToken(); return prefix; } ForthBlock b = new ForthBlock(curLine, sourceName); b.add(b.OBJECT, null); - if (peekToken() == RC) { consume(RC); return b; } + if (peekToken() == RC) { consume(RC); return parseSingleForthBlock(b, minPrecedence); } while(true) { if (peekToken() != NAME && peekToken() != STRING) throw new Error("expected NAME or STRING"); getToken(); @@ -328,9 +328,9 @@ public class Parser extends Lexer { b.add(b.EXPR, parseMaximalForthBlock()); b.add(b.PUT); b.add(b.POP); - if (peekToken() == RC) { consume(RC); return b; } + if (peekToken() == RC) { consume(RC); return parseSingleForthBlock(b, minPrecedence); } consume(COMMA); - if (peekToken() == RC) { consume(RC); return b; } + if (peekToken() == RC) { consume(RC); return parseSingleForthBlock(b, minPrecedence); } } } @@ -342,15 +342,15 @@ public class Parser extends Lexer { b.add(b.JMP, new Integer(2)); consume(COLON); b.add(b.EXPR, parseMaximalForthBlock()); - return b; + return parseSingleForthBlock(b, minPrecedence); } - case FUNCTION: { + case Tokens.FUNCTION: { if (prefix != null) { pushBackToken(); return prefix; } consume(LP); ForthBlock b = new ForthBlock(curLine, sourceName); int numArgs = 0; - b.add(b.THIS); + b.add(OpCodes.THIS); b.add(b.SWAP); b.add(b.LITERAL, "arguments"); b.add(b.LITERAL, "arguments"); @@ -377,7 +377,7 @@ public class Parser extends Lexer { b.add(b.POP); // put it to the current scope - b.add(b.THIS); + b.add(OpCodes.THIS); b.add(b.SWAP); b.add(b.LITERAL, string); b.add(b.SWAP); @@ -395,7 +395,7 @@ public class Parser extends Lexer { // pop off the arguments array b.add(b.POP); parseStatement(true, b); - return new ForthBlock(curLine, sourceName, b.FUNCTION, b); + return parseSingleForthBlock(new ForthBlock(curLine, sourceName, OpCodes.FUNCTION, b), minPrecedence); } case WHILE: { @@ -414,7 +414,7 @@ public class Parser extends Lexer { // if we fall out of the end, definately continue loop.add(CONTINUE); - return r; + return parseSingleForthBlock(r, minPrecedence); } case SWITCH: { @@ -446,7 +446,7 @@ public class Parser extends Lexer { if (peekToken() == RC) { consume(RC); r.add(BREAK); - return r; + return parseSingleForthBlock(r, minPrecedence); } } } @@ -467,7 +467,7 @@ public class Parser extends Lexer { loop.add(Lexer.CONTINUE); consume(RP); consume(SEMI); - return r; + return parseSingleForthBlock(r, minPrecedence); } case TRY: { @@ -486,7 +486,7 @@ public class Parser extends Lexer { } if (tok == FINALLY) getToken(); - return tryBlock; + return parseSingleForthBlock(tryBlock, minPrecedence); } case FOR: { @@ -523,7 +523,7 @@ public class Parser extends Lexer { b2.add(b.PUT); b2.add(b.EXPR, parseStatement(false)); b2.add(b.LITERAL, null); - return b; + return parseSingleForthBlock(b, minPrecedence); } else { ForthBlock b2 = new ForthBlock(curLine, sourceName); @@ -553,7 +553,7 @@ public class Parser extends Lexer { b3.add(b.JT, new Integer(2)); b3.add(BREAK); parseStatement(false, b3); - return b; + return parseSingleForthBlock(b, minPrecedence); } } -- 1.7.10.4