From 420df315b42d14a4a543cab1e9bdfbc317238e70 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Mon, 24 Mar 2014 06:45:54 +0400 Subject: [PATCH] JS parser: added NUMBER_INT token type --- .../src/com/google/gwt/dev/js/JsParser.java | 18 ++++- .../google/gwt/dev/js/rhino/IRFactory.java | 4 ++ .../src/com/google/gwt/dev/js/rhino/Node.java | 13 ++++ .../com/google/gwt/dev/js/rhino/Parser.java | 71 +++++++++++-------- .../google/gwt/dev/js/rhino/TokenStream.java | 13 +++- 5 files changed, 83 insertions(+), 36 deletions(-) diff --git a/js/js.parser/src/com/google/gwt/dev/js/JsParser.java b/js/js.parser/src/com/google/gwt/dev/js/JsParser.java index e18a238a2bd..b2ea66471d9 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/JsParser.java +++ b/js/js.parser/src/com/google/gwt/dev/js/JsParser.java @@ -182,8 +182,11 @@ public class JsParser { case TokenStream.STRING: return new JsStringLiteral(node.getString()); + case TokenStream.NUMBER_INT: + return mapIntNumber(node); + case TokenStream.NUMBER: - return mapNumber(node); + return mapDoubleNumber(node); case TokenStream.CALL: return mapCall(node); @@ -751,7 +754,11 @@ public class JsParser { return newExpr; } - private JsExpression mapNumber(Node numberNode) { + private JsExpression mapIntNumber(Node numberNode) { + return new JsNumberLiteral.JsIntLiteral((int) numberNode.getDouble()); + } + + private JsExpression mapDoubleNumber(Node numberNode) { return new JsNumberLiteral.JsDoubleLiteral(numberNode.getDouble()); } @@ -1111,7 +1118,7 @@ public class JsParser { return mapPrefixOperation(JsUnaryOperator.TYPEOF, unOp); case TokenStream.ADD: - if (unOp.getFirstChild().getType() != TokenStream.NUMBER) { + if (!isJsNumber(unOp.getFirstChild())) { return mapPrefixOperation(JsUnaryOperator.POS, unOp); } else { @@ -1171,4 +1178,9 @@ public class JsParser { private void pushScope(JsScope scope) { scopeStack.push(scope); } + + private boolean isJsNumber(Node jsNode) { + int type = jsNode.getType(); + return type == TokenStream.NUMBER || type == TokenStream.NUMBER; + } } diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java index 59be80b202b..2a97785d591 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java @@ -116,6 +116,10 @@ public class IRFactory { /** * Number (for literals) */ + public Object createNumber(int number) { + return Node.newNumber(number); + } + public Object createNumber(double number) { return Node.newNumber(number); } diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java index 1c279647753..970b9288143 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java @@ -49,6 +49,11 @@ public class Node implements Cloneable { private static class NumberNode extends Node { + NumberNode(int number) { + super(TokenStream.NUMBER_INT); + this.number = number; + } + NumberNode(double number) { super(TokenStream.NUMBER); this.number = number; @@ -184,6 +189,10 @@ public class Node implements Cloneable { intDatum = value; } + public static Node newNumber(int number) { + return new NumberNode(number); + } + public static Node newNumber(double number) { return new NumberNode(number); } @@ -599,6 +608,10 @@ public class Node implements Cloneable { sb.append(' '); sb.append(hashCode()); break; + case TokenStream.NUMBER_INT: + sb.append(' '); + sb.append((int) getDouble()); + break; case TokenStream.NUMBER: sb.append(' '); sb.append(getDouble()); diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java index 6d571da6afe..24238a609fc 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java @@ -1284,11 +1284,16 @@ public class Parser { sourceAddString(ts.NAME, s); property = nf.createString(ts.getString()); break; - case TokenStream.NUMBER: - double n = ts.getNumber(); + case TokenStream.NUMBER_INT: + int n = (int) ts.getNumber(); sourceAddNumber(n); property = nf.createNumber(n); break; + case TokenStream.NUMBER: + double d = ts.getNumber(); + sourceAddNumber(d); + property = nf.createNumber(d); + break; case TokenStream.RC: // trailing comma is OK. ts.ungetToken(tt); @@ -1332,11 +1337,16 @@ public class Parser { sourceAddString(ts.NAME, name); return nf.createName(name); - case TokenStream.NUMBER: - double n = ts.getNumber(); + case TokenStream.NUMBER_INT: + int n = (int)ts.getNumber(); sourceAddNumber(n); return nf.createNumber(n); + case TokenStream.NUMBER: + double d = ts.getNumber(); + sourceAddNumber(d); + return nf.createNumber(d); + case TokenStream.STRING: String s = ts.getString(); sourceAddString(ts.STRING, s); @@ -1449,34 +1459,33 @@ public class Parser { * could take up to 12 bytes. */ - long lbits = (long) n; - if (lbits != n) { - // if it's floating point, save as a Double bit pattern. - // (12/15/97 our scanner only returns Double for f.p.) - lbits = Double.doubleToLongBits(n); - sourceAdd('D'); - sourceAdd((char) (lbits >> 48)); - sourceAdd((char) (lbits >> 32)); - sourceAdd((char) (lbits >> 16)); - sourceAdd((char) lbits); - } else { - // we can ignore negative values, bc they're already prefixed - // by UNARYOP SUB - if (Context.check && lbits < 0) - Context.codeBug(); + long lbits = Double.doubleToLongBits(n); + sourceAdd('D'); + sourceAdd((char) (lbits >> 48)); + sourceAdd((char) (lbits >> 32)); + sourceAdd((char) (lbits >> 16)); + sourceAdd((char) lbits); + } - // will it fit in a char? - // this gives a short encoding for integer values up to 2^16. - if (lbits <= Character.MAX_VALUE) { - sourceAdd('S'); - sourceAdd((char) lbits); - } else { // Integral, but won't fit in a char. Store as a long. - sourceAdd('J'); - sourceAdd((char) (lbits >> 48)); - sourceAdd((char) (lbits >> 32)); - sourceAdd((char) (lbits >> 16)); - sourceAdd((char) lbits); - } + private void sourceAddNumber(int n) { + sourceAdd((char) TokenStream.NUMBER_INT); + + // we can ignore negative values, bc they're already prefixed + // by UNARYOP SUB + if (Context.check && (long) n < 0) + Context.codeBug(); + + // will it fit in a char? + // this gives a short encoding for integer values up to 2^16. + if ((long) n <= Character.MAX_VALUE) { + sourceAdd('S'); + sourceAdd((char) (long) n); + } else { // Integral, but won't fit in a char. Store as a long. + sourceAdd('J'); + sourceAdd((char) ((long) n >> 48)); + sourceAdd((char) ((long) n >> 32)); + sourceAdd((char) ((long) n >> 16)); + sourceAdd((char) (long) n); } } diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java index a677b31aa35..9cbfdfa4824 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java @@ -256,6 +256,7 @@ public class TokenStream { SCRIPT = 147, // top-level node for entire script LAST_TOKEN = 147, + NUMBER_INT = 148, // This value is only used as a return value for getTokenHelper, // which is only called from getToken and exists to avoid an excessive @@ -314,7 +315,8 @@ public class TokenStream { case SETELEM: return "setelem"; case CALL: return "call"; case NAME: return "name"; - case NUMBER: return "number"; + case NUMBER_INT: return "integer"; + case NUMBER: return "double"; case STRING: return "string"; case ZERO: return "zero"; case ONE: return "one"; @@ -444,6 +446,8 @@ public class TokenStream { case NAME: return name + " `" + this.string + "'"; + case NUMBER_INT: + return "NUMBER_INT " + (int) this.number; case NUMBER: return "NUMBER " + this.number; } @@ -684,7 +688,7 @@ public class TokenStream { this.pushbackToken = EOF; return result; } - + public static boolean isJSKeyword(String s) { return getKeywordId(s) != 0; } @@ -980,6 +984,11 @@ public class TokenStream { } this.number = dval; + + if (isInteger) { + return NUMBER_INT; + } + return NUMBER; }