875 }
876
877 /**
878 * @param topLevel does this statement occur at the "top level" of a script or a function?
879 * @param allowPropertyFunction allow property "get" and "set" functions?
880 * @param singleStatement are we in a single statement context?
881 */
882 private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) {
883 if (type == FUNCTION) {
884 // As per spec (ECMA section 12), function declarations as arbitrary statement
885 // is not "portable". Implementation can issue a warning or disallow the same.
886 functionExpression(true, topLevel);
887 return;
888 }
889
890 switch (type) {
891 case LBRACE:
892 block();
893 break;
894 case VAR:
895 variableStatement(type, true);
896 break;
897 case SEMICOLON:
898 emptyStatement();
899 break;
900 case IF:
901 ifStatement();
902 break;
903 case FOR:
904 forStatement();
905 break;
906 case WHILE:
907 whileStatement();
908 break;
909 case DO:
910 doStatement();
911 break;
912 case CONTINUE:
913 continueStatement();
914 break;
915 case BREAK:
929 break;
930 case THROW:
931 throwStatement();
932 break;
933 case TRY:
934 tryStatement();
935 break;
936 case DEBUGGER:
937 debuggerStatement();
938 break;
939 case RPAREN:
940 case RBRACKET:
941 case EOF:
942 expect(SEMICOLON);
943 break;
944 default:
945 if (useBlockScope() && (type == LET || type == CONST)) {
946 if (singleStatement) {
947 throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
948 }
949 variableStatement(type, true);
950 break;
951 }
952 if (env._const_as_var && type == CONST) {
953 variableStatement(TokenType.VAR, true);
954 break;
955 }
956
957 if (type == IDENT || isNonStrictModeIdent()) {
958 if (T(k + 1) == COLON) {
959 labelStatement();
960 return;
961 }
962 if(allowPropertyFunction) {
963 final String ident = (String)getValue();
964 final long propertyToken = token;
965 final int propertyLine = line;
966 if("get".equals(ident)) {
967 next();
968 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine));
969 return;
970 } else if("set".equals(ident)) {
971 next();
972 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine));
973 return;
1030 *
1031 * @param ident Identifier that is verified
1032 * @param contextString String used in error message to give context to the user
1033 */
1034 private void verifyStrictIdent(final IdentNode ident, final String contextString) {
1035 if (isStrictMode) {
1036 switch (ident.getName()) {
1037 case "eval":
1038 case "arguments":
1039 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1040 default:
1041 break;
1042 }
1043
1044 if (ident.isFutureStrictName()) {
1045 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1046 }
1047 }
1048 }
1049
1050 /**
1051 * VariableStatement :
1052 * var VariableDeclarationList ;
1053 *
1054 * VariableDeclarationList :
1055 * VariableDeclaration
1056 * VariableDeclarationList , VariableDeclaration
1057 *
1058 * VariableDeclaration :
1059 * Identifier Initializer?
1060 *
1061 * Initializer :
1062 * = AssignmentExpression
1063 *
1064 * See 12.2
1065 *
1066 * Parse a VAR statement.
1067 * @param isStatement True if a statement (not used in a FOR.)
1068 */
1069 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) {
1070 return variableStatement(varType, isStatement, -1);
1071 }
1072
1073 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement, final int sourceOrder) {
1074 // VAR tested in caller.
1075 next();
1076
1077 final List<VarNode> vars = new ArrayList<>();
1078 int varFlags = 0;
1079 if (varType == LET) {
1080 varFlags |= VarNode.IS_LET;
1081 } else if (varType == CONST) {
1082 varFlags |= VarNode.IS_CONST;
1083 }
1084
1085 while (true) {
1086 // Get starting token.
1087 final int varLine = line;
1088 final long varToken = token;
1089 // Get name of var.
1090 final IdentNode name = getIdent();
1198 if (type == ELSE) {
1199 next();
1200 fail = getStatement();
1201 }
1202
1203 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
1204 }
1205
1206 /**
1207 * ... IterationStatement:
1208 * ...
1209 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement
1210 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement
1211 * for ( LeftHandSideExpression in Expression ) Statement
1212 * for ( var VariableDeclaration[NoIn] in Expression ) Statement
1213 *
1214 * See 12.6
1215 *
1216 * Parse a FOR statement.
1217 */
1218 private void forStatement() {
1219 final long forToken = token;
1220 final int forLine = line;
1221 // start position of this for statement. This is used
1222 // for sort order for variables declared in the initializer
1223 // part of this 'for' statement (if any).
1224 final int forStart = Token.descPosition(forToken);
1225 // When ES6 for-let is enabled we create a container block to capture the LET.
1226 final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
1227
1228 // Create FOR node, capturing FOR token.
1229 final ParserContextLoopNode forNode = new ParserContextLoopNode();
1230 lc.push(forNode);
1231 Block body = null;
1232 List<VarNode> vars = null;
1233 Expression init = null;
1234 JoinPredecessorExpression test = null;
1235 JoinPredecessorExpression modify = null;
1236
1237 int flags = 0;
1238
1239 try {
1240 // FOR tested in caller.
1241 next();
1242
1243 // Nashorn extension: for each expression.
1244 // iterate property values rather than property names.
1245 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
1246 flags |= ForNode.IS_FOR_EACH;
1247 next();
1248 }
1249
1250 expect(LPAREN);
1251
1252 switch (type) {
1253 case VAR:
1254 // Var declaration captured in for outer block.
1255 vars = variableStatement(type, false, forStart);
1256 break;
1257 case SEMICOLON:
1275
1276 switch (type) {
1277 case SEMICOLON:
1278 // for (init; test; modify)
1279
1280 // for each (init; test; modify) is invalid
1281 if ((flags & ForNode.IS_FOR_EACH) != 0) {
1282 throw error(AbstractParser.message("for.each.without.in"), token);
1283 }
1284
1285 expect(SEMICOLON);
1286 if (type != SEMICOLON) {
1287 test = joinPredecessorExpression();
1288 }
1289 expect(SEMICOLON);
1290 if (type != RPAREN) {
1291 modify = joinPredecessorExpression();
1292 }
1293 break;
1294
1295 case IN:
1296 flags |= ForNode.IS_FOR_IN;
1297 test = new JoinPredecessorExpression();
1298 if (vars != null) {
1299 // for (var i in obj)
1300 if (vars.size() == 1) {
1301 init = new IdentNode(vars.get(0).getName());
1302 } else {
1303 // for (var i, j in obj) is invalid
1304 throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
1305 }
1306
1307 } else {
1308 // for (expr in obj)
1309 assert init != null : "for..in init expression can not be null here";
1310
1311 // check if initial expression is a valid L-value
1312 if (!(init instanceof AccessNode ||
1313 init instanceof IndexNode ||
1314 init instanceof IdentNode)) {
1315 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1316 }
1317
1318 if (init instanceof IdentNode) {
1319 if (!checkIdentLValue((IdentNode)init)) {
1320 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1321 }
1322 verifyStrictIdent((IdentNode)init, "for-in iterator");
1323 }
1324 }
1325
1326 next();
1327
1328 // Get the collection expression.
1329 modify = joinPredecessorExpression();
1330 break;
1331
1332 default:
1333 expect(SEMICOLON);
1334 break;
1335 }
1336
1337 expect(RPAREN);
1338
1339 // Set the for body.
1340 body = getStatement();
1341 } finally {
1342 lc.pop(forNode);
1343
1344 if (vars != null) {
1345 for (final VarNode var : vars) {
1346 appendStatement(var);
1347 }
1348 }
1349 if (body != null) {
|
875 }
876
877 /**
878 * @param topLevel does this statement occur at the "top level" of a script or a function?
879 * @param allowPropertyFunction allow property "get" and "set" functions?
880 * @param singleStatement are we in a single statement context?
881 */
882 private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) {
883 if (type == FUNCTION) {
884 // As per spec (ECMA section 12), function declarations as arbitrary statement
885 // is not "portable". Implementation can issue a warning or disallow the same.
886 functionExpression(true, topLevel);
887 return;
888 }
889
890 switch (type) {
891 case LBRACE:
892 block();
893 break;
894 case VAR:
895 variableStatement(type);
896 break;
897 case SEMICOLON:
898 emptyStatement();
899 break;
900 case IF:
901 ifStatement();
902 break;
903 case FOR:
904 forStatement();
905 break;
906 case WHILE:
907 whileStatement();
908 break;
909 case DO:
910 doStatement();
911 break;
912 case CONTINUE:
913 continueStatement();
914 break;
915 case BREAK:
929 break;
930 case THROW:
931 throwStatement();
932 break;
933 case TRY:
934 tryStatement();
935 break;
936 case DEBUGGER:
937 debuggerStatement();
938 break;
939 case RPAREN:
940 case RBRACKET:
941 case EOF:
942 expect(SEMICOLON);
943 break;
944 default:
945 if (useBlockScope() && (type == LET || type == CONST)) {
946 if (singleStatement) {
947 throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
948 }
949 variableStatement(type);
950 break;
951 }
952 if (env._const_as_var && type == CONST) {
953 variableStatement(TokenType.VAR);
954 break;
955 }
956
957 if (type == IDENT || isNonStrictModeIdent()) {
958 if (T(k + 1) == COLON) {
959 labelStatement();
960 return;
961 }
962 if(allowPropertyFunction) {
963 final String ident = (String)getValue();
964 final long propertyToken = token;
965 final int propertyLine = line;
966 if("get".equals(ident)) {
967 next();
968 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine));
969 return;
970 } else if("set".equals(ident)) {
971 next();
972 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine));
973 return;
1030 *
1031 * @param ident Identifier that is verified
1032 * @param contextString String used in error message to give context to the user
1033 */
1034 private void verifyStrictIdent(final IdentNode ident, final String contextString) {
1035 if (isStrictMode) {
1036 switch (ident.getName()) {
1037 case "eval":
1038 case "arguments":
1039 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1040 default:
1041 break;
1042 }
1043
1044 if (ident.isFutureStrictName()) {
1045 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1046 }
1047 }
1048 }
1049
1050 /*
1051 * VariableStatement :
1052 * var VariableDeclarationList ;
1053 *
1054 * VariableDeclarationList :
1055 * VariableDeclaration
1056 * VariableDeclarationList , VariableDeclaration
1057 *
1058 * VariableDeclaration :
1059 * Identifier Initializer?
1060 *
1061 * Initializer :
1062 * = AssignmentExpression
1063 *
1064 * See 12.2
1065 *
1066 * Parse a VAR statement.
1067 * @param isStatement True if a statement (not used in a FOR.)
1068 */
1069 private List<VarNode> variableStatement(final TokenType varType) {
1070 return variableStatement(varType, true, -1);
1071 }
1072
1073 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement, final int sourceOrder) {
1074 // VAR tested in caller.
1075 next();
1076
1077 final List<VarNode> vars = new ArrayList<>();
1078 int varFlags = 0;
1079 if (varType == LET) {
1080 varFlags |= VarNode.IS_LET;
1081 } else if (varType == CONST) {
1082 varFlags |= VarNode.IS_CONST;
1083 }
1084
1085 while (true) {
1086 // Get starting token.
1087 final int varLine = line;
1088 final long varToken = token;
1089 // Get name of var.
1090 final IdentNode name = getIdent();
1198 if (type == ELSE) {
1199 next();
1200 fail = getStatement();
1201 }
1202
1203 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
1204 }
1205
1206 /**
1207 * ... IterationStatement:
1208 * ...
1209 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement
1210 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement
1211 * for ( LeftHandSideExpression in Expression ) Statement
1212 * for ( var VariableDeclaration[NoIn] in Expression ) Statement
1213 *
1214 * See 12.6
1215 *
1216 * Parse a FOR statement.
1217 */
1218 @SuppressWarnings("fallthrough")
1219 private void forStatement() {
1220 final long forToken = token;
1221 final int forLine = line;
1222 // start position of this for statement. This is used
1223 // for sort order for variables declared in the initializer
1224 // part of this 'for' statement (if any).
1225 final int forStart = Token.descPosition(forToken);
1226 // When ES6 for-let is enabled we create a container block to capture the LET.
1227 final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
1228
1229 // Create FOR node, capturing FOR token.
1230 final ParserContextLoopNode forNode = new ParserContextLoopNode();
1231 lc.push(forNode);
1232 Block body = null;
1233 List<VarNode> vars = null;
1234 Expression init = null;
1235 JoinPredecessorExpression test = null;
1236 JoinPredecessorExpression modify = null;
1237
1238 int flags = 0;
1239 boolean isForOf = false;
1240
1241 try {
1242 // FOR tested in caller.
1243 next();
1244
1245 // Nashorn extension: for each expression.
1246 // iterate property values rather than property names.
1247 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
1248 flags |= ForNode.IS_FOR_EACH;
1249 next();
1250 }
1251
1252 expect(LPAREN);
1253
1254 switch (type) {
1255 case VAR:
1256 // Var declaration captured in for outer block.
1257 vars = variableStatement(type, false, forStart);
1258 break;
1259 case SEMICOLON:
1277
1278 switch (type) {
1279 case SEMICOLON:
1280 // for (init; test; modify)
1281
1282 // for each (init; test; modify) is invalid
1283 if ((flags & ForNode.IS_FOR_EACH) != 0) {
1284 throw error(AbstractParser.message("for.each.without.in"), token);
1285 }
1286
1287 expect(SEMICOLON);
1288 if (type != SEMICOLON) {
1289 test = joinPredecessorExpression();
1290 }
1291 expect(SEMICOLON);
1292 if (type != RPAREN) {
1293 modify = joinPredecessorExpression();
1294 }
1295 break;
1296
1297 case IDENT:
1298 if (env._es6 && "of".equals(getValue())) {
1299 isForOf = true;
1300 // fall through
1301 } else {
1302 expect(SEMICOLON); // fail with expected message
1303 break;
1304 }
1305 case IN:
1306
1307 flags |= isForOf ? ForNode.IS_FOR_OF : ForNode.IS_FOR_IN;
1308 test = new JoinPredecessorExpression();
1309 if (vars != null) {
1310 // for (var i in obj)
1311 if (vars.size() == 1) {
1312 init = new IdentNode(vars.get(0).getName());
1313 } else {
1314 // for (var i, j in obj) is invalid
1315 throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), vars.get(1).getToken());
1316 }
1317 } else {
1318 // for (expr in obj)
1319 assert init != null : "for..in/of init expression can not be null here";
1320
1321 // check if initial expression is a valid L-value
1322 if (!(init instanceof AccessNode ||
1323 init instanceof IndexNode ||
1324 init instanceof IdentNode)) {
1325 throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken());
1326 }
1327
1328 if (init instanceof IdentNode) {
1329 if (!checkIdentLValue((IdentNode)init)) {
1330 throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken());
1331 }
1332 verifyStrictIdent((IdentNode)init, isForOf ? "for-of iterator" : "for-in iterator");
1333 }
1334 }
1335
1336 next();
1337
1338 // For-of only allows AssignmentExpression.
1339 modify = isForOf ? new JoinPredecessorExpression(assignmentExpression(false)) : joinPredecessorExpression();
1340 break;
1341
1342 default:
1343 expect(SEMICOLON);
1344 break;
1345 }
1346
1347 expect(RPAREN);
1348
1349 // Set the for body.
1350 body = getStatement();
1351 } finally {
1352 lc.pop(forNode);
1353
1354 if (vars != null) {
1355 for (final VarNode var : vars) {
1356 appendStatement(var);
1357 }
1358 }
1359 if (body != null) {
|