
org.sonar.javascript.parser.EcmaScriptGrammarImpl Maven / Gradle / Ivy
/*
* Sonar JavaScript Plugin
* Copyright (C) 2011 Eriks Nukis and SonarSource
* [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.javascript.parser;
import org.sonar.javascript.api.EcmaScriptGrammar;
import static com.sonar.sslr.api.GenericTokenType.EOF;
import static com.sonar.sslr.api.GenericTokenType.IDENTIFIER;
import static com.sonar.sslr.api.GenericTokenType.LITERAL;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Predicate.next;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Predicate.not;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.and;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.o2n;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.one2n;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.opt;
import static com.sonar.sslr.impl.matcher.GrammarFunctions.Standard.or;
import static org.sonar.javascript.api.EcmaScriptKeyword.BREAK;
import static org.sonar.javascript.api.EcmaScriptKeyword.CASE;
import static org.sonar.javascript.api.EcmaScriptKeyword.CATCH;
import static org.sonar.javascript.api.EcmaScriptKeyword.CONTINUE;
import static org.sonar.javascript.api.EcmaScriptKeyword.DEBUGGER;
import static org.sonar.javascript.api.EcmaScriptKeyword.DEFAULT;
import static org.sonar.javascript.api.EcmaScriptKeyword.DELETE;
import static org.sonar.javascript.api.EcmaScriptKeyword.DO;
import static org.sonar.javascript.api.EcmaScriptKeyword.ELSE;
import static org.sonar.javascript.api.EcmaScriptKeyword.FALSE;
import static org.sonar.javascript.api.EcmaScriptKeyword.FINALLY;
import static org.sonar.javascript.api.EcmaScriptKeyword.FOR;
import static org.sonar.javascript.api.EcmaScriptKeyword.FUNCTION;
import static org.sonar.javascript.api.EcmaScriptKeyword.IF;
import static org.sonar.javascript.api.EcmaScriptKeyword.IN;
import static org.sonar.javascript.api.EcmaScriptKeyword.INSTANCEOF;
import static org.sonar.javascript.api.EcmaScriptKeyword.NEW;
import static org.sonar.javascript.api.EcmaScriptKeyword.NULL;
import static org.sonar.javascript.api.EcmaScriptKeyword.RETURN;
import static org.sonar.javascript.api.EcmaScriptKeyword.SWITCH;
import static org.sonar.javascript.api.EcmaScriptKeyword.THIS;
import static org.sonar.javascript.api.EcmaScriptKeyword.THROW;
import static org.sonar.javascript.api.EcmaScriptKeyword.TRUE;
import static org.sonar.javascript.api.EcmaScriptKeyword.TRY;
import static org.sonar.javascript.api.EcmaScriptKeyword.TYPEOF;
import static org.sonar.javascript.api.EcmaScriptKeyword.VAR;
import static org.sonar.javascript.api.EcmaScriptKeyword.VOID;
import static org.sonar.javascript.api.EcmaScriptKeyword.WHILE;
import static org.sonar.javascript.api.EcmaScriptKeyword.WITH;
import static org.sonar.javascript.api.EcmaScriptPunctuator.AND;
import static org.sonar.javascript.api.EcmaScriptPunctuator.ANDAND;
import static org.sonar.javascript.api.EcmaScriptPunctuator.AND_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.BANG;
import static org.sonar.javascript.api.EcmaScriptPunctuator.COLON;
import static org.sonar.javascript.api.EcmaScriptPunctuator.COMMA;
import static org.sonar.javascript.api.EcmaScriptPunctuator.DEC;
import static org.sonar.javascript.api.EcmaScriptPunctuator.DIV;
import static org.sonar.javascript.api.EcmaScriptPunctuator.DIV_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.DOT;
import static org.sonar.javascript.api.EcmaScriptPunctuator.EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.EQUAL;
import static org.sonar.javascript.api.EcmaScriptPunctuator.EQUAL2;
import static org.sonar.javascript.api.EcmaScriptPunctuator.GE;
import static org.sonar.javascript.api.EcmaScriptPunctuator.GT;
import static org.sonar.javascript.api.EcmaScriptPunctuator.INC;
import static org.sonar.javascript.api.EcmaScriptPunctuator.LBRACKET;
import static org.sonar.javascript.api.EcmaScriptPunctuator.LCURLYBRACE;
import static org.sonar.javascript.api.EcmaScriptPunctuator.LE;
import static org.sonar.javascript.api.EcmaScriptPunctuator.LPARENTHESIS;
import static org.sonar.javascript.api.EcmaScriptPunctuator.LT;
import static org.sonar.javascript.api.EcmaScriptPunctuator.MINUS;
import static org.sonar.javascript.api.EcmaScriptPunctuator.MINUS_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.MOD;
import static org.sonar.javascript.api.EcmaScriptPunctuator.MOD_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.NOTEQUAL;
import static org.sonar.javascript.api.EcmaScriptPunctuator.NOTEQUAL2;
import static org.sonar.javascript.api.EcmaScriptPunctuator.OR;
import static org.sonar.javascript.api.EcmaScriptPunctuator.OROR;
import static org.sonar.javascript.api.EcmaScriptPunctuator.OR_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.PLUS;
import static org.sonar.javascript.api.EcmaScriptPunctuator.PLUS_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.QUERY;
import static org.sonar.javascript.api.EcmaScriptPunctuator.RBRACKET;
import static org.sonar.javascript.api.EcmaScriptPunctuator.RCURLYBRACE;
import static org.sonar.javascript.api.EcmaScriptPunctuator.RPARENTHESIS;
import static org.sonar.javascript.api.EcmaScriptPunctuator.SEMI;
import static org.sonar.javascript.api.EcmaScriptPunctuator.SL;
import static org.sonar.javascript.api.EcmaScriptPunctuator.SL_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.SR;
import static org.sonar.javascript.api.EcmaScriptPunctuator.SR2;
import static org.sonar.javascript.api.EcmaScriptPunctuator.SR_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.SR_EQU2;
import static org.sonar.javascript.api.EcmaScriptPunctuator.STAR;
import static org.sonar.javascript.api.EcmaScriptPunctuator.STAR_EQU;
import static org.sonar.javascript.api.EcmaScriptPunctuator.TILDA;
import static org.sonar.javascript.api.EcmaScriptPunctuator.XOR;
import static org.sonar.javascript.api.EcmaScriptPunctuator.XOR_EQU;
import static org.sonar.javascript.api.EcmaScriptTokenType.NUMERIC_LITERAL;
import static org.sonar.javascript.api.EcmaScriptTokenType.REGULAR_EXPRESSION_LITERAL;
/**
* Grammar for ECMAScript.
* Based on ECMA-262
* edition 5.1 (June 2011).
*/
public class EcmaScriptGrammarImpl extends EcmaScriptGrammar {
public EcmaScriptGrammarImpl() {
eos.is(or(
opt(SEMI),
next(RCURLYBRACE),
next(EOF)));
eosNoLb.is(or(
opt(SEMI),
next(RCURLYBRACE),
next(EOF)));
identifierName.is(IDENTIFIER);
literal.is(or(
nullLiteral,
booleanLiteral,
NUMERIC_LITERAL,
stringLiteral,
regularExpressionLiteral));
nullLiteral.is(NULL);
booleanLiteral.is(or(
TRUE,
FALSE));
stringLiteral.is(LITERAL);
regularExpressionLiteral.is(REGULAR_EXPRESSION_LITERAL);
expressions();
statements();
functionsAndPrograms();
}
/**
* A.3 Expressions
*/
private void expressions() {
primaryExpression.is(or(
THIS,
IDENTIFIER,
literal,
arrayLiteral,
objectLiteral,
and(LPARENTHESIS, expression, RPARENTHESIS)));
arrayLiteral.is(or(
and(LBRACKET, opt(elision), RBRACKET),
and(LBRACKET, elementList, RBRACKET),
and(LBRACKET, elementList, COMMA, opt(elision), RBRACKET)));
elementList.is(and(opt(elision), assignmentExpression), o2n(COMMA, opt(elision), assignmentExpression));
elision.is(one2n(COMMA));
objectLiteral.is(or(
and(LCURLYBRACE, RCURLYBRACE),
and(LCURLYBRACE, propertyNameAndValueList, RCURLYBRACE),
and(LCURLYBRACE, propertyNameAndValueList, COMMA, RCURLYBRACE)));
propertyNameAndValueList.is(propertyAssignment, o2n(COMMA, propertyAssignment));
propertyAssignment.is(or(
and(propertyName, COLON, assignmentExpression),
and("get", propertyName, LPARENTHESIS, RPARENTHESIS, LCURLYBRACE, functionBody, RCURLYBRACE),
and("set", propertyName, LPARENTHESIS, propertySetParameterList, RPARENTHESIS, LCURLYBRACE, functionBody, RCURLYBRACE)));
propertyName.is(or(
identifierName,
stringLiteral,
NUMERIC_LITERAL));
propertySetParameterList.is(IDENTIFIER);
memberExpression.is(
or(
primaryExpression,
functionExpression,
and(NEW, memberExpression, arguments)),
o2n(or(
and(LBRACKET, expression, RBRACKET),
and(DOT, identifierName))));
newExpression.is(or(
memberExpression,
and(NEW, newExpression)));
callExpression.is(
and(memberExpression, arguments),
o2n(or(
arguments,
and(LBRACKET, expression, RBRACKET),
and(DOT, identifierName))));
arguments.is(or(
and(LPARENTHESIS, argumentList, RPARENTHESIS),
and(LPARENTHESIS, RPARENTHESIS)));
argumentList.is(assignmentExpression, o2n(COMMA, assignmentExpression));
leftHandSideExpression.is(or(
callExpression,
newExpression));
postfixExpression.is(leftHandSideExpression, opt(/* no line terminator here */or(INC, DEC)));
unaryExpression.is(or(
postfixExpression,
and(DELETE, unaryExpression),
and(VOID, unaryExpression),
and(TYPEOF, unaryExpression),
and(INC, unaryExpression),
and(DEC, unaryExpression),
and(PLUS, unaryExpression),
and(MINUS, unaryExpression),
and(TILDA, unaryExpression),
and(BANG, unaryExpression)));
multiplicativeExpression.is(unaryExpression, opt(or(STAR, DIV, MOD), multiplicativeExpression)).skipIfOneChild();
additiveExpression.is(multiplicativeExpression, opt(or(PLUS, MINUS), additiveExpression)).skipIfOneChild();
shiftExpression.is(additiveExpression, opt(or(SL, SR, SR2), shiftExpression)).skipIfOneChild();
relationalExpression.is(shiftExpression, opt(or(LT, GT, LE, GE, INSTANCEOF, IN), relationalExpression)).skipIfOneChild();
relationalExpressionNoIn.is(shiftExpression, opt(or(LT, GT, LE, GE, INSTANCEOF), relationalExpression)).skipIfOneChild();
equalityExpression.is(relationalExpression, opt(or(EQUAL, NOTEQUAL, EQUAL2, NOTEQUAL2), equalityExpression)).skipIfOneChild();
equalityExpressionNoIn.is(relationalExpressionNoIn, opt(or(EQUAL, NOTEQUAL, EQUAL2, NOTEQUAL2), equalityExpressionNoIn)).skipIfOneChild();
bitwiseAndExpression.is(equalityExpression, opt(AND, bitwiseAndExpression)).skipIfOneChild();
bitwiseAndExpressionNoIn.is(equalityExpressionNoIn, opt(AND, bitwiseAndExpressionNoIn)).skipIfOneChild();
bitwiseXorExpression.is(bitwiseAndExpression, opt(XOR, bitwiseXorExpression)).skipIfOneChild();
bitwiseXorExpressionNoIn.is(bitwiseAndExpressionNoIn, opt(XOR, bitwiseXorExpressionNoIn)).skipIfOneChild();
bitwiseOrExpression.is(bitwiseXorExpression, opt(OR, bitwiseOrExpression)).skipIfOneChild();
bitwiseOrExpressionNoIn.is(bitwiseXorExpressionNoIn, opt(OR, bitwiseOrExpressionNoIn)).skipIfOneChild();
logicalAndExpression.is(bitwiseOrExpression, opt(ANDAND, logicalAndExpression)).skipIfOneChild();
logicalAndExpressionNoIn.is(bitwiseOrExpressionNoIn, opt(ANDAND, logicalAndExpressionNoIn)).skipIfOneChild();
logicalOrExpression.is(logicalAndExpression, opt(OROR, logicalOrExpression)).skipIfOneChild();
logicalOrExpressionNoIn.is(logicalAndExpressionNoIn, opt(OROR, logicalOrExpressionNoIn)).skipIfOneChild();
conditionalExpression.is(logicalOrExpression, opt(QUERY, assignmentExpression, COLON, assignmentExpression)).skipIfOneChild();
conditionalExpressionNoIn.is(logicalOrExpressionNoIn, opt(QUERY, assignmentExpression, COLON, assignmentExpressionNoIn)).skipIfOneChild();
assignmentExpression.is(or(
and(leftHandSideExpression, EQU, assignmentExpression),
and(leftHandSideExpression, assignmentOperator, assignmentExpression),
conditionalExpression)).skipIfOneChild();
assignmentExpressionNoIn.is(or(
and(leftHandSideExpression, EQU, assignmentExpressionNoIn),
and(leftHandSideExpression, assignmentOperator, assignmentExpressionNoIn),
conditionalExpressionNoIn)).skipIfOneChild();
assignmentOperator.is(or(
STAR_EQU,
DIV_EQU,
MOD_EQU,
PLUS_EQU,
MINUS_EQU,
SL_EQU,
SR_EQU,
SR_EQU2,
AND_EQU,
XOR_EQU,
OR_EQU));
expression.is(assignmentExpression, o2n(COMMA, assignmentExpression));
expressionNoIn.is(assignmentExpressionNoIn, o2n(COMMA, assignmentExpressionNoIn));
}
/**
* A.4 Statement
*/
private void statements() {
statement.is(or(
block,
variableStatement,
emptyStatement,
labelledStatement,
expressionStatement,
ifStatement,
iterationStatement,
continueStatement,
breakStatement,
returnStatement,
withStatement,
switchStatement,
throwStatement,
tryStatement,
debuggerStatement));
block.is(LCURLYBRACE, opt(statementList), RCURLYBRACE);
statementList.is(one2n(or(statement, permissive(functionDeclaration))));
variableStatement.is(VAR, variableDeclarationList, eos);
variableDeclarationList.is(variableDeclaration, o2n(COMMA, variableDeclaration));
variableDeclarationListNoIn.is(variableDeclarationNoIn, o2n(COMMA, variableDeclarationNoIn));
variableDeclaration.is(IDENTIFIER, opt(initialiser));
variableDeclarationNoIn.is(IDENTIFIER, opt(initialiserNoIn));
initialiser.is(EQU, assignmentExpression);
initialiserNoIn.is(EQU, assignmentExpressionNoIn);
emptyStatement.is(SEMI);
expressionStatement.is(not(or(LCURLYBRACE, FUNCTION)), expression, eos);
condition.is(expression);
ifStatement.is(or(
and(IF, LPARENTHESIS, condition, RPARENTHESIS, statement, opt(ELSE, statement)),
and(IF, LPARENTHESIS, condition, RPARENTHESIS, statement)));
iterationStatement.is(or(
doWhileStatement,
whileStatement,
forInStatement,
forStatement));
doWhileStatement.is(DO, statement, WHILE, LPARENTHESIS, condition, RPARENTHESIS, eos);
whileStatement.is(WHILE, LPARENTHESIS, condition, RPARENTHESIS, statement);
forInStatement.is(or(
and(FOR, LPARENTHESIS, leftHandSideExpression, IN, expression, RPARENTHESIS, statement),
and(FOR, LPARENTHESIS, VAR, variableDeclarationListNoIn, IN, expression, RPARENTHESIS, statement)));
forStatement.is(or(
and(FOR, LPARENTHESIS, opt(expressionNoIn), SEMI, opt(condition), SEMI, opt(expression), RPARENTHESIS, statement),
and(FOR, LPARENTHESIS, VAR, variableDeclarationListNoIn, SEMI, opt(condition), SEMI, opt(expression), RPARENTHESIS, statement)));
continueStatement.is(or(
and(CONTINUE, /* TODO no line terminator here */IDENTIFIER, eos),
and(CONTINUE, eosNoLb)));
breakStatement.is(or(
and(BREAK, /* TODO no line terminator here */IDENTIFIER, eos),
and(BREAK, eosNoLb)));
returnStatement.is(or(
and(RETURN, /* TODO no line terminator here */expression, eos),
and(RETURN, eosNoLb)));
withStatement.is(WITH, LPARENTHESIS, expression, RPARENTHESIS, statement);
switchStatement.is(SWITCH, LPARENTHESIS, expression, RPARENTHESIS, caseBlock);
caseBlock.is(or(
and(LCURLYBRACE, opt(caseClauses), RCURLYBRACE),
and(LCURLYBRACE, opt(caseClauses), defaultClause, opt(caseClauses), RCURLYBRACE)));
caseClauses.is(one2n(caseClause));
caseClause.is(CASE, expression, COLON, opt(statementList));
defaultClause.is(DEFAULT, COLON, opt(statementList));
labelledStatement.is(IDENTIFIER, COLON, statement);
throwStatement.is(THROW, /* TODO no line terminator here */expression, eos);
tryStatement.is(TRY, block, or(and(catch_, opt(finally_)), finally_));
catch_.is(CATCH, LPARENTHESIS, IDENTIFIER, RPARENTHESIS, block);
finally_.is(FINALLY, block);
debuggerStatement.is(DEBUGGER, eos);
}
/**
* A.5 Functions and Programs
*/
private void functionsAndPrograms() {
functionDeclaration.is(FUNCTION, IDENTIFIER, LPARENTHESIS, opt(formalParameterList), RPARENTHESIS, LCURLYBRACE, functionBody, RCURLYBRACE);
functionExpression.is(FUNCTION, opt(IDENTIFIER), LPARENTHESIS, opt(formalParameterList), RPARENTHESIS, LCURLYBRACE, functionBody, RCURLYBRACE);
formalParameterList.is(IDENTIFIER, o2n(COMMA, IDENTIFIER));
functionBody.is(opt(sourceElements));
program.is(opt(sourceElements), EOF);
sourceElements.is(one2n(sourceElement));
sourceElement.is(or(
statement,
functionDeclaration));
}
/**
* Declares some constructs, which ES5 grammar does not support, but script engines support.
* For example prototype.js version 1.7 has a function declaration in a block, which is invalid under both ES3 and ES5.
*/
private static Object permissive(Object object) {
return object;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy