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: case TokenStream.STRING:
return new JsStringLiteral(node.getString()); return new JsStringLiteral(node.getString());
case TokenStream.NUMBER_INT:
return mapIntNumber(node);
case TokenStream.NUMBER: case TokenStream.NUMBER:
return mapNumber(node); return mapDoubleNumber(node);
case TokenStream.CALL: case TokenStream.CALL:
return mapCall(node); return mapCall(node);
@@ -751,7 +754,11 @@ public class JsParser {
return newExpr; 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()); return new JsNumberLiteral.JsDoubleLiteral(numberNode.getDouble());
} }
@@ -1111,7 +1118,7 @@ public class JsParser {
return mapPrefixOperation(JsUnaryOperator.TYPEOF, unOp); return mapPrefixOperation(JsUnaryOperator.TYPEOF, unOp);
case TokenStream.ADD: case TokenStream.ADD:
if (unOp.getFirstChild().getType() != TokenStream.NUMBER) { if (!isJsNumber(unOp.getFirstChild())) {
return mapPrefixOperation(JsUnaryOperator.POS, unOp); return mapPrefixOperation(JsUnaryOperator.POS, unOp);
} }
else { else {
@@ -1171,4 +1178,9 @@ public class JsParser {
private void pushScope(JsScope scope) { private void pushScope(JsScope scope) {
scopeStack.push(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) * Number (for literals)
*/ */
public Object createNumber(int number) {
return Node.newNumber(number);
}
public Object createNumber(double number) { public Object createNumber(double number) {
return Node.newNumber(number); return Node.newNumber(number);
} }
@@ -49,6 +49,11 @@ public class Node implements Cloneable {
private static class NumberNode extends Node { private static class NumberNode extends Node {
NumberNode(int number) {
super(TokenStream.NUMBER_INT);
this.number = number;
}
NumberNode(double number) { NumberNode(double number) {
super(TokenStream.NUMBER); super(TokenStream.NUMBER);
this.number = number; this.number = number;
@@ -184,6 +189,10 @@ public class Node implements Cloneable {
intDatum = value; intDatum = value;
} }
public static Node newNumber(int number) {
return new NumberNode(number);
}
public static Node newNumber(double number) { public static Node newNumber(double number) {
return new NumberNode(number); return new NumberNode(number);
} }
@@ -599,6 +608,10 @@ public class Node implements Cloneable {
sb.append(' '); sb.append(' ');
sb.append(hashCode()); sb.append(hashCode());
break; break;
case TokenStream.NUMBER_INT:
sb.append(' ');
sb.append((int) getDouble());
break;
case TokenStream.NUMBER: case TokenStream.NUMBER:
sb.append(' '); sb.append(' ');
sb.append(getDouble()); sb.append(getDouble());
@@ -1284,11 +1284,16 @@ public class Parser {
sourceAddString(ts.NAME, s); sourceAddString(ts.NAME, s);
property = nf.createString(ts.getString()); property = nf.createString(ts.getString());
break; break;
case TokenStream.NUMBER: case TokenStream.NUMBER_INT:
double n = ts.getNumber(); int n = (int) ts.getNumber();
sourceAddNumber(n); sourceAddNumber(n);
property = nf.createNumber(n); property = nf.createNumber(n);
break; break;
case TokenStream.NUMBER:
double d = ts.getNumber();
sourceAddNumber(d);
property = nf.createNumber(d);
break;
case TokenStream.RC: case TokenStream.RC:
// trailing comma is OK. // trailing comma is OK.
ts.ungetToken(tt); ts.ungetToken(tt);
@@ -1332,11 +1337,16 @@ public class Parser {
sourceAddString(ts.NAME, name); sourceAddString(ts.NAME, name);
return nf.createName(name); return nf.createName(name);
case TokenStream.NUMBER: case TokenStream.NUMBER_INT:
double n = ts.getNumber(); int n = (int)ts.getNumber();
sourceAddNumber(n); sourceAddNumber(n);
return nf.createNumber(n); return nf.createNumber(n);
case TokenStream.NUMBER:
double d = ts.getNumber();
sourceAddNumber(d);
return nf.createNumber(d);
case TokenStream.STRING: case TokenStream.STRING:
String s = ts.getString(); String s = ts.getString();
sourceAddString(ts.STRING, s); sourceAddString(ts.STRING, s);
@@ -1449,34 +1459,33 @@ public class Parser {
* could take up to 12 bytes. * could take up to 12 bytes.
*/ */
long lbits = (long) n; long lbits = Double.doubleToLongBits(n);
if (lbits != n) { sourceAdd('D');
// if it's floating point, save as a Double bit pattern. sourceAdd((char) (lbits >> 48));
// (12/15/97 our scanner only returns Double for f.p.) sourceAdd((char) (lbits >> 32));
lbits = Double.doubleToLongBits(n); sourceAdd((char) (lbits >> 16));
sourceAdd('D'); sourceAdd((char) lbits);
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();
// will it fit in a char? private void sourceAddNumber(int n) {
// this gives a short encoding for integer values up to 2^16. sourceAdd((char) TokenStream.NUMBER_INT);
if (lbits <= Character.MAX_VALUE) {
sourceAdd('S'); // we can ignore negative values, bc they're already prefixed
sourceAdd((char) lbits); // by UNARYOP SUB
} else { // Integral, but won't fit in a char. Store as a long. if (Context.check && (long) n < 0)
sourceAdd('J'); Context.codeBug();
sourceAdd((char) (lbits >> 48));
sourceAdd((char) (lbits >> 32)); // will it fit in a char?
sourceAdd((char) (lbits >> 16)); // this gives a short encoding for integer values up to 2^16.
sourceAdd((char) lbits); 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 SCRIPT = 147, // top-level node for entire script
LAST_TOKEN = 147, LAST_TOKEN = 147,
NUMBER_INT = 148,
// This value is only used as a return value for getTokenHelper, // This value is only used as a return value for getTokenHelper,
// which is only called from getToken and exists to avoid an excessive // which is only called from getToken and exists to avoid an excessive
@@ -314,7 +315,8 @@ public class TokenStream {
case SETELEM: return "setelem"; case SETELEM: return "setelem";
case CALL: return "call"; case CALL: return "call";
case NAME: return "name"; case NAME: return "name";
case NUMBER: return "number"; case NUMBER_INT: return "integer";
case NUMBER: return "double";
case STRING: return "string"; case STRING: return "string";
case ZERO: return "zero"; case ZERO: return "zero";
case ONE: return "one"; case ONE: return "one";
@@ -444,6 +446,8 @@ public class TokenStream {
case NAME: case NAME:
return name + " `" + this.string + "'"; return name + " `" + this.string + "'";
case NUMBER_INT:
return "NUMBER_INT " + (int) this.number;
case NUMBER: case NUMBER:
return "NUMBER " + this.number; return "NUMBER " + this.number;
} }
@@ -684,7 +688,7 @@ public class TokenStream {
this.pushbackToken = EOF; this.pushbackToken = EOF;
return result; return result;
} }
public static boolean isJSKeyword(String s) { public static boolean isJSKeyword(String s) {
return getKeywordId(s) != 0; return getKeywordId(s) != 0;
} }
@@ -980,6 +984,11 @@ public class TokenStream {
} }
this.number = dval; this.number = dval;
if (isInteger) {
return NUMBER_INT;
}
return NUMBER; return NUMBER;
} }