JS parser: added NUMBER_INT token type

This commit is contained in:
Alexey Tsvetkov
2014-03-24 06:45:54 +04:00
parent 570010ed5c
commit 420df315b4
5 changed files with 83 additions and 36 deletions
@@ -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;
}
}
@@ -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);
}
@@ -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());
@@ -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);
}
}
@@ -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;
}