t.push(isPrefix ? val : num);
break;
}
+
+
+ case ADD: {
+ int count = ((Number)arg[pc]).intValue();
+ if(count < 2) throw new Error("this should never happen");
+ if(count == 2) {
+ // common case
+ Object right = t.pop();
+ Object left = t.pop();
+ if(left instanceof String || right instanceof String) t.push(JS.toString(left).concat(JS.toString(right)));
+ else t.push(new Double(JS.toDouble(left) + JS.toDouble(right)));
+ break;
+ }
+ Object[] args = new Object[count];
+ while(--count >= 0) args[count] = t.pop();
+ if(args[0] instanceof String) {
+ StringBuffer sb = new StringBuffer(64);
+ for(int i=0;i<args.length;i++) sb.append(JS.toString(args[i]));
+ t.push(sb.toString());
+ } else {
+ int numStrings = 0;
+ for(int i=0;i<args.length;i++) if(args[i] instanceof String) numStrings++;
+ if(numStrings == 0) {
+ double d = 0.0;
+ for(int i=0;i<args.length;i++) d += JS.toDouble(args[i]);
+ t.push(new Double(d));
+ } else {
+ double d=0.0;
+ int i=0;
+ do {
+ d += JS.toDouble(args[i++]);
+ } while(!(args[i] instanceof String));
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(JS.toString(new Double(d)));
+ while(i < args.length) sb.append(JS.toString(args[i++]));
+ t.push(sb.toString());
+ }
+ }
+ break;
+ }
default: {
Object right = t.pop();
Object left = t.pop();
switch(op[pc]) {
-
- case 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 BITOR: t.push(new Long(JS.toLong(left) | JS.toLong(right))); break;
case BITXOR: t.push(new Long(JS.toLong(left) ^ JS.toLong(right))); break;
throw new Error("toNumber() got object of type " + o.getClass().getName() + " which we don't know how to handle");
}
+ /** coerce an object to a String */
+ public static String toString(Object o) {
+ if(o == null) return "null";
+ if(o instanceof String) return (String) o;
+ if(o instanceof Integer || o instanceof Long || o instanceof Boolean) return o.toString();
+ if(o instanceof JS) return ((JS)o).coerceToString();
+ if(o instanceof Double || o instanceof Float) {
+ double d = ((Number)o).doubleValue();
+ if((int)d == d) return Integer.toString((int)d);
+ return o.toString();
+ }
+ return o.toString();
+ }
+
// Instance Methods ////////////////////////////////////////////////////////////////////
public abstract Object get(Object key) throws JS.Exn;
public abstract Object[] keys();
public abstract Object callMethod(Object method, JS.Array args, boolean justChecking);
- public Number coerceToNumber() { throw new Error("you cannot coerce a " + this.getClass().getName() + " into a Number"); }
- public String coerceToString() { throw new Error("you cannot coerce a " + this.getClass().getName() + " into a String"); }
- public boolean coerceToBoolean() { throw new Error("you cannot coerce a " + this.getClass().getName() + " into a Boolean"); }
+ public Number coerceToNumber() { return new Integer(0); }
+ public String coerceToString() { return toString(); }
+ public boolean coerceToBoolean() { return true; }
public String typeName() { return "object"; }
case ASSIGN_ADD: case ASSIGN_SUB: case ASSIGN_MUL: case ASSIGN_DIV: case ASSIGN_MOD: {
b.add(parserLine, GET_PRESERVE);
startExpr(b, -1);
- b.add(parserLine, tok - 1);
+ // tok-1 is always s/^ASSIGN_// (0 is BITOR, 1 is ASSIGN_BITOR, etc)
+ b.add(parserLine, tok - 1, tok-1==ADD ? new Integer(2) : null);
b.add(parserLine, PUT);
b.add(parserLine, SWAP);
b.add(parserLine, POP);
break;
}
case INC: case DEC: { // postfix
- b.add(parserLine, GET_PRESERVE);
- b.add(parserLine, LITERAL, new Integer(1));
- b.add(parserLine, tok == INC ? ADD : SUB);
- b.add(parserLine, PUT);
- b.add(parserLine, SWAP);
- b.add(parserLine, POP);
- b.add(parserLine, LITERAL, new Integer(1));
- b.add(parserLine, tok == INC ? SUB : ADD);
+ b.add(parserLine, tok, Boolean.FALSE);
break;
}
case ASSIGN: {
break;
}
case BITOR: case BITXOR: case BITAND: case SHEQ: case SHNE: case LSH:
- case RSH: case URSH: case ADD: case MUL: case DIV: case MOD:
+ case RSH: case URSH: case MUL: case DIV: case MOD:
case GT: case GE: case EQ: case NE: case LT: case LE: case SUB: {
startExpr(b, precedence[tok]);
b.add(parserLine, tok);
break;
}
+ case ADD: {
+ int count=1;
+ int nextTok;
+ do {
+ startExpr(b,precedence[tok]);
+ count++;
+ nextTok = getToken();
+ } while(nextTok == tok);
+ pushBackToken();
+ b.add(parserLine, tok, new Integer(count));
+ break;
+ }
case OR: case AND: {
b.add(parserLine, tok == AND ? b.JF : b.JT, new Integer(0)); // test to see if we can short-circuit
int size = b.size();