Revision: 4150 http://vexi.svn.sourceforge.net/vexi/?rev=4150&view=rev Author: mkpg2 Date: 2011-05-22 15:54:08 +0000 (Sun, 22 May 2011)
Log Message: ----------- Refactor. Improve implementation of boolean and truthiness. Modified Paths: -------------- trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSNumber.java trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSPojoWrapper.java trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSString.java trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/Interpreter.jpp trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSArray.jpp trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSPrimitive.jpp trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSU.jpp trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/XMLRPC.jpp trunk/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp Added Paths: ----------- trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSBoolean.java Added: trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSBoolean.java =================================================================== --- trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSBoolean.java (rev 0) +++ trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSBoolean.java 2011-05-22 15:54:08 UTC (rev 4150) @@ -0,0 +1,53 @@ +package org.ibex.js; +final public class JSBoolean extends JSPrimitive { + static final public JSBoolean TRUE = new JSBoolean(true); + static final public JSBoolean FALSE = new JSBoolean(false); + + static public JS Constructor = new JS.Constructor("Boolean"); + final public boolean b; + private JSBoolean(boolean b) { this.b = b; } + + int toInt(){ return b?1:0; } + long toLong() { return toInt(); } + double toDouble() { return toLong(); } + + + public String coerceToString() { return b ? "true" : "false"; } + public JS type() { return SC_boolean; } + public boolean isTruthy(){ return b; } + public boolean instanceOf(JS constructor) { return constructor==Constructor; } + public JS get(JS key) throws JSExn { + //#noswitch - leave, needed for jsdoc + /*@PAGE(varname=Boolean,humanname=Booleans) + * + * <p>A simple <code>true</code> or <code>false</code> value.</p> + * + * <p>A boolean is a primitive, so all <a href="vexi.js.String.html">string</a> functions are valid.</p> + * + * <p>The following values equate to <b><code>false</code></b> when used in boolean operations:<p> + * + * <ul><li><code>null</code></li> + * <li><code>0</code></li> + * <li><code>""</code></li></ul> + * + * <p>The following values equate to <b><code>true</code></b> when used in boolean operations:<p> + * + * <ul><li>Any non-<code>null</code> object</li> + * <li>Any non-<code>0</code> number</li> + * <li>Any non-empty string</li></ul> + * + * <p>Consider:</p> + * + * <pre> 0 == false; + * "0" == true; + * 1 == true; + * -1 == true; + * null == false; + * "null" == true; + * {} == true;</pre> + * + * */ + //#end + return super.get(key); + } +} \ No newline at end of file Property changes on: trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSBoolean.java ___________________________________________________________________ Added: svn:mime-type + text/plain Modified: trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSNumber.java =================================================================== --- trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSNumber.java 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSNumber.java 2011-05-22 15:54:08 UTC (rev 4150) @@ -6,6 +6,8 @@ public abstract class JSNumber extends JSPrimitive { static public JS Constructor = new JS.Constructor("Number"); + + public boolean equals(Object o) { if (o == this) { return true; @@ -17,17 +19,6 @@ } return n.toLong() == toLong(); } - if (o instanceof JSString) { - String s = ((JSString)o).s.trim(); - try { - if (this instanceof D || s.indexOf('.') != -1) { - return Double.parseDouble(s) == toDouble(); - } - return Long.parseLong(s) == toLong(); - } catch (NumberFormatException e) { - return false; - } - } return false; } @@ -53,12 +44,16 @@ abstract int toInt(); boolean isFraction(){ return false; } long toLong() { return toInt(); } - boolean toBoolean() { return toInt() != 0; } double toDouble() { return toLong(); } - float toFloat() { return (float) toDouble(); } - final static class I extends JSNumber { - final int i; + + public JS type() { return SC_number; } + public boolean isTruthy(){ return toInt()!=0; } + public boolean instanceOf(JS constructor) { return constructor==Constructor; } + + + final static public class I extends JSNumber { + final public int i; I(int i) { this.i = i; } int toInt() { return i; } public String coerceToString() { return Integer.toString(i); } @@ -80,55 +75,10 @@ int toInt() { return (int) d; } long toLong() { return (long) d; } double toDouble() { return d; } - boolean toBoolean() { return d == d && d != 0.0; } + public boolean isTruthy() { return d == d && d != 0.0; } public String coerceToString() { return d == (long) d ? Long.toString((long)d) : Double.toString(d); } } - final static public class B extends JSNumber { - static public JS Constructor = new JS.Constructor("Boolean"); - private final boolean b; - B(boolean b) { this.b = b; } - int toInt() { return b ? 1 : 0; } - public String coerceToString() { return b ? "true" : "false"; } - public JS type() { return SC_boolean; } - public boolean instanceOf(JS constructor) { return constructor==Constructor; } - public JS get(JS key) throws JSExn { - //#noswitch - leave, needed for jsdoc - /*@PAGE(varname=Boolean,humanname=Booleans) - * - * <p>A simple <code>true</code> or <code>false</code> value.</p> - * - * <p>A boolean is a primitive, so all <a href="vexi.js.String.html">string</a> functions are valid.</p> - * - * <p>The following values equate to <b><code>false</code></b> when used in boolean operations:<p> - * - * <ul><li><code>null</code></li> - * <li><code>0</code></li> - * <li><code>""</code></li></ul> - * - * <p>The following values equate to <b><code>true</code></b> when used in boolean operations:<p> - * - * <ul><li>Any non-<code>null</code> object</li> - * <li>Any non-<code>0</code> number</li> - * <li>Any non-empty string</li></ul> - * - * <p>Consider:</p> - * - * <pre> 0 == false; - * "0" == true; - * 1 == true; - * -1 == true; - * null == false; - * "null" == true; - * {} == true;</pre> - * - * */ - //#end - return super.get(key); - } - } - public JS type() { return SC_number; } - public boolean instanceOf(JS constructor) { return constructor==Constructor; } } Modified: trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSPojoWrapper.java =================================================================== --- trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSPojoWrapper.java 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSPojoWrapper.java 2011-05-22 15:54:08 UTC (rev 4150) @@ -105,12 +105,10 @@ return new Long(JSU.toLong(js)); if(js instanceof JSNumber.I) return new Integer(JSU.toInt(js)); - if(js instanceof JSNumber.B) - return Boolean.valueOf(JSU.toBoolean(js)); - } - - if(js instanceof JSArray){ + } if(js instanceof JSBoolean) { + return ((JSBoolean)js).b; + } if(js instanceof JSArray){ JSArray js_ = (JSArray)js; Object[] r = new Object[js_.size()]; for(int i=0; i<r.length; i++){ Modified: trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSString.java =================================================================== --- trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSString.java 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/java/org/ibex/js/JSString.java 2011-05-22 15:54:08 UTC (rev 4150) @@ -21,6 +21,8 @@ public JSString(String s) { this.s = s; } public int hashCode() { return s.hashCode(); } public JS type() { return SC_string; } + public boolean isTruthy(){ return !"".equals(s); } + public boolean equals(Object o) { if (o == this) { @@ -29,9 +31,6 @@ if (o instanceof JSString) { return ((JSString)o).s.equals(s); } - if (o instanceof JSNumber) { - return o.equals(this); - } return false; } Modified: trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/Interpreter.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/Interpreter.jpp 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/Interpreter.jpp 2011-05-22 15:54:08 UTC (rev 4150) @@ -189,8 +189,8 @@ case OBJECT: stack.push(new JS.Obj()); break; case ARRAY: stack.push(new JSArray(JSU.toInt((JS)arg))); break; //case DECLARE: scope.declare((JS)(arg==null ? stack.peek() : arg)); if(arg != null) stack.push((JS)arg); break; - case JT: if (JSU.toBoolean((JS)stack.pop())) jump(JSU.toInt((JS)arg) - 1); break; - case JF: if (!JSU.toBoolean((JS)stack.pop())) jump(JSU.toInt((JS)arg) - 1); break; + case JT: if (JSU.isTruthy((JS)stack.pop())) jump(JSU.toInt((JS)arg) - 1); break; + case JF: if (!JSU.isTruthy((JS)stack.pop())) jump(JSU.toInt((JS)arg) - 1); break; case JMP: jump(JSU.toInt((JS)arg) - 1); break; case POP: stack.pop(); break; case SWAP: stack.swap(); break; @@ -212,9 +212,9 @@ if (val != null && val instanceof JS[]) val = new JSArgs((JS[])val, null, null); scope.put((JS)arg, (JS)val); break; } - case ASSERT: if (!JSU.toBoolean((JS)stack.pop())) throw je("ibex.assertion.failed"); break; + case ASSERT: if (!JSU.isTruthy((JS)stack.pop())) throw je("ibex.assertion.failed"); break; case BITNOT: stack.push(JSU.N(~JSU.toLong((JS)stack.pop()))); break; - case BANG: stack.push(JSU.B(!JSU.toBoolean((JS)stack.pop()))); break; + case BANG: stack.push(JSU.B(!JSU.isTruthy((JS)stack.pop()))); break; case NEWFUNCTION: stack.push(JSU.cloneWithNewParentScope((Function)arg, scope)); break; case LABEL: break; @@ -321,7 +321,7 @@ } case CASCADE: { - boolean write = JSU.toBoolean((JS)arg); + boolean write = JSU.T==arg; JS val = write ? (JS)stack.pop() : null; CallMarker o = stack.findCall(); if(!(o instanceof TrapMarker)) throw new JSExn("Tried to 'cascade' while not in a trap"); @@ -611,13 +611,6 @@ boolean ret; if(left == null && right == null) ret = true; else if(left == null || right == null) ret = false; - //This objects aren't === unless they are of the same JS type - //recognising 4 types, JSString, JSBoolean, JSNumber and all the rest - // #repeat JSString/JSNumber.B/JSNumber - else if(( left instanceof JSString && !(right instanceof JSString)) || right instanceof JSString && !(left instanceof JSString)) ret = false; - else if(( left instanceof JSNumber.B && !(right instanceof JSNumber.B)) || right instanceof JSNumber.B && !(left instanceof JSNumber.B)) ret = false; - else if(( left instanceof JSNumber && !(right instanceof JSNumber)) || right instanceof JSNumber && !(left instanceof JSNumber)) ret = false; - // #end else ret = left.equals(right); stack.push(JSU.B(op == SHEQ ? ret : !ret)); break; @@ -625,11 +618,7 @@ case EQ: case NE: { - boolean ret; - if(left == null && right == null) ret = true; - else if(left == null || right == null) ret = false; - else if(left == right) ret = true; // optimisation - else ret = left.equals(right); + boolean ret = JSU.coerceEquals(left, right); stack.push(JSU.B(op == EQ ? ret : !ret)); break; } Modified: trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JS.jpp 2011-05-22 15:54:08 UTC (rev 4150) @@ -263,6 +263,7 @@ /** Value returned from typeof */ public JS type(); + public boolean isTruthy(); // FEATURE: consider renaming/removing these public JS unclone(); @@ -275,7 +276,7 @@ * exceptions on every mutable operation. */ public static class Immutable implements JS { public JS unclone() { return this; } - public JS type() { return SC_immutable; } + public Keys keys() throws JSExn { throw new JSExn(type()+" has no key set"); } public Set keySet() throws JSExn { throw new JSExn(type()+" has no key set"); } public JS get(JS key) throws JSExn { @@ -320,6 +321,8 @@ } public Trap getTrap(JS key) { return null; } + public JS type() { return SC_immutable; } + public boolean isTruthy(){ return true; } public boolean instanceOf(JS constructor){ return false; } public void addConstructor(JS constructor) throws JSExn { throw new JSExn("Attemted to add constructor to immutable"); @@ -561,6 +564,7 @@ }; } public JS type() { return SC_object; } + public boolean isTruthy(){ return true; } /** Fetches any value stored against the given key. */ public JS get(JS key) throws JSExn { Modified: trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSArray.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSArray.jpp 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSArray.jpp 2011-05-22 15:54:08 UTC (rev 4150) @@ -26,6 +26,7 @@ public JS unclone() { return this; } public JS.Keys keys() throws JSExn { return new JSArrayLike.Keys(this); } public Set keySet() throws JSExn { throw new RuntimeException("!"); } + public boolean isTruthy(){ return true; } public JS get(JS key) throws JSExn { if (key == null || !JSU.isInt(key)) { Modified: trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSPrimitive.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSPrimitive.jpp 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSPrimitive.jpp 2011-05-22 15:54:08 UTC (rev 4150) @@ -82,10 +82,11 @@ if (a > b) { int tmp = a; a = b; b = tmp; } return JSU.S(s.substring(a,b)); } - case "toExponential": throw new JSExn("toExponential() not implemented"); - case "toFixed": throw new JSExn("toFixed() not implemented"); +// case "toExponential": throw new JSExn("toExponential() not implemented"); +// case "toFixed": throw new JSExn("toFixed() not implemented"); +// case "toPrecision": throw new JSExn("toPrecision() not implemented"); + case "toLowerCase": return JSU.S(s.toLowerCase()); - case "toPrecision": throw new JSExn("toPrecision() not implemented"); case "toString": { if (this instanceof JSString) return this; if (JSU.isInt(this) && args.length == 1) @@ -229,24 +230,24 @@ * @return(String) * */ case "substring": return METHOD; - /* <p>TODO</p> - * - * @method - * @return(String) - * */ - case "toExponential": if (this instanceof JSNumber) return METHOD; - /* <p>TODO</p> - * - * @method - * @return(String) - * */ - case "toPrecision": if (this instanceof JSNumber) return METHOD; - /* <p>TODO</p> - * - * @method - * @return(String) - * */ - case "toFixed": if (this instanceof JSNumber) return METHOD; +// /* <p>TODO</p> +// * +// * @method +// * @return(String) +// * */ +// case "toExponential": if (this instanceof JSNumber) return METHOD; +// /* <p>TODO</p> +// * +// * @method +// * @return(String) +// * */ +// case "toPrecision": if (this instanceof JSNumber) return METHOD; +// /* <p>TODO</p> +// * +// * @method +// * @return(String) +// * */ +// case "toFixed": if (this instanceof JSNumber) return METHOD; /* Returns the lower-case equivalent of the current string * @return(String) */ case "toLowerCase": return METHOD; Modified: trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSU.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSU.jpp 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/JSU.jpp 2011-05-22 15:54:08 UTC (rev 4150) @@ -82,14 +82,9 @@ } /** Coerce a JS object into a boolean. */ - public static boolean toBoolean(JS o) { - if(o == null) return false; - if(o instanceof JSNumber) return ((JSNumber)o).toBoolean(); - if(o instanceof JSString) return ((JSString)o).s.length() != 0; - return true; - } + public static boolean toBoolean(JS o) { return isTruthy(o); } - //#repeat long/int/double/float toLong/toInt/toDouble/toFloat Long/Integer/Double/Float parseLong/parseInt/parseDouble/parseFloat + //#repeat long/int/double toLong/toInt/toDouble Long/Integer/Double parseLong/parseInt/parseDouble /** Coerce a JS object to a long. */ public static long toLong(JS o) throws JSExn { if(o == null) return 0; @@ -101,6 +96,8 @@ throw new JSExn("This string is not a number: \""+o.coerceToString()+'"'); } } +// if(o instanceof JSDecimal) return ((JSDecimal)o).toLong(); + if(o instanceof JSBoolean) return ((JSBoolean)o).toLong(); throw new JSExn("Can not coerce a " + o.getClass().getName() + " to a number"); } //#end @@ -120,7 +117,6 @@ public static boolean isInt(JS o) { if(o == null) return true; if(o instanceof JSNumber.I) return true; - if(o instanceof JSNumber.B) return false; if(o instanceof JSNumber) { JSNumber n = (JSNumber) o; return n.toInt() == n.toDouble(); @@ -161,8 +157,8 @@ //public final static JS GLOBAL = new Scope.Global(); // TODO - move to Constants - public static final JS T = new JSNumber.B(true); - public static final JS F = new JSNumber.B(false); + public static final JS T = JSBoolean.TRUE; + public static final JS F = JSBoolean.FALSE; public static final JS B(boolean b) { return b ? T : F; } public static final JS B(int i) { return i==0 ? F : T; } @@ -298,5 +294,64 @@ static public Basket.List backtrace(){ return new JSExn("").backtrace; } - + + static private boolean xor(boolean a, boolean b){ + return a && !b || !a && b; + } + + static private boolean isPrimitive(JS a){ + return a==null || a instanceof JSPrimitive; + } + static public boolean isTruthy(JS o){ + if(o==null) return false; + return o.isTruthy(); + } + + + static public boolean coerceEquals(JS a, JS b){ + if(a==b) return true; + if(a==null || b==null) return false; + + if(isPrimitive(a) && isPrimitive(b)){ + + boolean numA = a instanceof JSNumber; + boolean numB = b instanceof JSNumber; + if (xor(numA,numB)){ + if(numB){ + JS s = a; + a = b; + b = s; + } + JSNumber n = (JSNumber)a; + if(b instanceof JSBoolean) + return n.toInt()==((JSBoolean)b).toInt(); + // string + String s = ((JSString)b).toString(); + try { + if (n instanceof JSNumber.D || s.indexOf('.') != -1) { + return Double.parseDouble(s) == n.toDouble(); + } + return Long.parseLong(s) == n.toLong(); + } catch (NumberFormatException e) { + return false; + } + } + +// boolean boolA = a instanceof JSBoolean; +// boolean boolB = b instanceof JSBoolean; +// if (xor(boolA,boolB)){ +// if(boolB){ +// JS s = a; +// a = b; +// b = s; +// } +// boolean bool = ((JSBoolean)a).b; +// if(!bool){ +// return "".equals(((JSString)b).s); +// } +// return false; +// } + } + return a.equals(b); + } } Modified: trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/XMLRPC.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/XMLRPC.jpp 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/jpp/org/ibex/js/XMLRPC.jpp 2011-05-22 15:54:08 UTC (rev 4150) @@ -233,9 +233,9 @@ sb.append(" <value><i4>"); sb.append(((JSNumber)o).toInt()); sb.append("</i4></value>\n"); - } else if (o instanceof JSNumber.B) { + } else if (o instanceof JSBoolean) { sb.append(" <value><boolean>"); - sb.append(((JSNumber)o).toBoolean() ? "1" : "0"); + sb.append(((JSBoolean)o).b ? "1" : "0"); sb.append("</boolean></value>\n"); } else { sb.append(" <value><double>"); Modified: trunk/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp =================================================================== --- trunk/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp 2011-05-22 15:43:13 UTC (rev 4149) +++ trunk/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp 2011-05-22 15:54:08 UTC (rev 4150) @@ -524,7 +524,7 @@ * * @param(name=size,optional=true)*/ case "Array": return org.ibex.js.JSArray.Constructor; - case "Boolean": return org.ibex.js.JSNumber.B.Constructor; + case "Boolean": return org.ibex.js.JSBoolean.Constructor; case "Date": return org.ibex.js.JSDate.Constructor; case "Decimal": return org.ibex.js.JSDecimal.Constructor; case "Exception": return org.ibex.js.JSExn.Constructor; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ What Every C/C++ and Fortran developer Should Know! Read this article and learn how Intel has extended the reach of its next-generation tools to help Windows* and Linux* C/C++ and Fortran developers boost performance applications - including clusters. http://p.sf.net/sfu/intel-dev2devmay _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn