}
@SuppressWarnings("fallthrough")
private AbstractExpression parseExpressionAtom() throws ParseException {
AbstractExpression e;
Mark m = tq.mark();
Token<JsTokenType> t = tq.pop();
typeswitch: switch (t.type) {
case STRING:
issueLintWarningsForProblematicEscapes(t, mq);
e = new StringLiteral(t.pos, t.text);
break;
case INTEGER:
if (integerPartIsOctal(t.text)) {
mq.addMessage(
MessageType.OCTAL_LITERAL, MessageLevel.LINT,
t.pos, MessagePart.Factory.valueOf(t.text));
}
e = toIntegerLiteral(t);
break;
case FLOAT:
if (integerPartIsOctal(t.text)) {
mq.addMessage(
MessageType.OCTAL_LITERAL, MessageLevel.ERROR,
t.pos, MessagePart.Factory.valueOf(t.text));
}
e = toNumberLiteral(t);
break;
case REGEXP:
{
e = new RegexpLiteral(t.pos, t.text);
// Check letters. Warn on s suffix character as non-FF.
String modifiers = t.text.substring(t.text.lastIndexOf("/") + 1);
if (!RegexpLiteral.areRegexpModifiersValid(modifiers)) {
mq.addMessage(
MessageType.UNRECOGNIZED_REGEX_MODIFIERS, t.pos,
MessagePart.Factory.valueOf(modifiers));
}
break;
}
case KEYWORD:
{
Keyword k = Keyword.fromString(t.text);
if (null != k) {
switch (k) {
case NULL:
e = new NullLiteral(t.pos);
break typeswitch;
case TRUE:
e = new BooleanLiteral(t.pos, true);
break typeswitch;
case FALSE:
e = new BooleanLiteral(t.pos, false);
break typeswitch;
case FUNCTION:
{
Identifier identifier = null;
if (!tq.isEmpty() && JsTokenType.WORD == tq.peek().type) {
identifier = parseIdentifierNode(false);
} else {
identifier = new Identifier(
FilePosition.endOf(tq.lastPosition()), null);
}
tq.expectToken(Punctuation.LPAREN);
FormalParamList params = parseFormalParams();
tq.expectToken(Punctuation.RPAREN);
Block body = parseFunctionBody();
e = new FunctionConstructor(
posFrom(m), identifier, params.params, body);
break typeswitch;
}
default:
break; // Will be handled by the word handler below
}
}
// fall through
}
case WORD:
{
String identifier;
if (Keyword.THIS.toString().equals(t.text)) {
// this is allowed, but not t\u0068is as per the grammar
identifier = Keyword.THIS.toString();
} else {
tq.rewind(m);
identifier = parseIdentifier(false);
}
Identifier idNode = new Identifier(posFrom(m), identifier);
finish(idNode, m);
e = new Reference(idNode);
break;
}
case PUNCTUATION:
switch (Punctuation.fromString(t.text)) {
case LPAREN:
e = parseExpressionInt(true);
tq.expectToken(Punctuation.RPAREN);
return e; // Don't pull comments outside parens inside
case LSQUARE:
{
List<Expression> elements = Lists.newArrayList();
if (!tq.checkToken(Punctuation.RSQUARE)) {
Mark comma = null;
do {
// Handle adjacent commas that specify undefined values.
// E.g. [1,,2]
for (Mark cm = tq.mark(); tq.checkToken(Punctuation.COMMA);
cm = tq.mark()) {
comma = cm;
Elision vl = new Elision(posFrom(cm));
finish(vl, cm);
elements.add(vl);
}
if (tq.lookaheadToken(Punctuation.RSQUARE)) { break; }
comma = null;
elements.add(parseExpressionPart(true));
} while (tq.checkToken(Punctuation.COMMA));
if (comma != null) {
// On IE, [1,] has length 2 unlike on other browsers.
mq.addMessage(MessageType.NOT_IE, comma.getFilePosition());
}
tq.expectToken(Punctuation.RSQUARE);
}
e = new ArrayConstructor(posFrom(m), elements);
break;
}
case LCURLY:
{
List<ObjProperty> properties = Lists.newArrayList();
if (!tq.checkToken(Punctuation.RCURLY)) {
boolean sawComma;
do {
Mark km = tq.mark();
Token<JsTokenType> keyToken = tq.peek();
String propertyType = null;
Mark beforeProperty = km;
if (keyToken.type == JsTokenType.WORD) {
if ("get".equals(keyToken.text)
|| "set".equals(keyToken.text)) {
tq.advance();
Mark afterWord = tq.mark();
if (!tq.checkToken(Punctuation.COLON)) {
propertyType = keyToken.text;
beforeProperty = afterWord;
keyToken = tq.peek();
}
tq.rewind(beforeProperty);
}
}
StringLiteral key;
switch (keyToken.type) {
case STRING:
tq.advance();
key = new StringLiteral(posFrom(km), keyToken.text);
break;
case FLOAT:
tq.advance();
key = StringLiteral.valueOf(
posFrom(km), floatToString(keyToken));
break;
case INTEGER:
tq.advance();
key = StringLiteral.valueOf(
posFrom(km), "" + toInteger(keyToken));
break;
default:
String ident = parseIdentifier(true);
key = new StringLiteral(posFrom(km), ident);
break;
}
finish(key, beforeProperty);
ObjProperty prop;
if (propertyType == null) {
tq.expectToken(Punctuation.COLON);
Expression value = parseExpressionPart(true);
prop = new ValueProperty(posFrom(km), key, value);
} else {
Mark beforeFormals = tq.mark();
Identifier ident = new Identifier(tq.currentPosition(), null);
tq.expectToken(Punctuation.LPAREN);
FormalParamList params = parseFormalParams();
tq.expectToken(Punctuation.RPAREN);
Block body = parseFunctionBody();
FunctionConstructor fn = new FunctionConstructor(
posFrom(beforeFormals), ident, params.params, body);
if ("get".equals(propertyType)) {
prop = new GetterProperty(posFrom(km), key, fn);
} else {
assert "set".equals(propertyType);
prop = new SetterProperty(posFrom(km), key, fn);
}
}
finish(prop, km);
properties.add(prop);
Mark cm = tq.mark();
sawComma = tq.checkToken(Punctuation.COMMA);
if (sawComma && tq.lookaheadToken(Punctuation.RCURLY)) {
tq.rewind(cm);
mq.addMessage(MessageType.NOT_IE, tq.currentPosition());
tq.advance();