26 package jdk.nashorn.internal.parser; |
26 package jdk.nashorn.internal.parser; |
27 |
27 |
28 import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX; |
28 import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX; |
29 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL; |
29 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL; |
30 import static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM; |
30 import static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM; |
|
31 import static jdk.nashorn.internal.parser.TokenType.ARROW; |
31 import static jdk.nashorn.internal.parser.TokenType.ASSIGN; |
32 import static jdk.nashorn.internal.parser.TokenType.ASSIGN; |
32 import static jdk.nashorn.internal.parser.TokenType.CASE; |
33 import static jdk.nashorn.internal.parser.TokenType.CASE; |
33 import static jdk.nashorn.internal.parser.TokenType.CATCH; |
34 import static jdk.nashorn.internal.parser.TokenType.CATCH; |
|
35 import static jdk.nashorn.internal.parser.TokenType.CLASS; |
34 import static jdk.nashorn.internal.parser.TokenType.COLON; |
36 import static jdk.nashorn.internal.parser.TokenType.COLON; |
35 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT; |
37 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT; |
|
38 import static jdk.nashorn.internal.parser.TokenType.COMMENT; |
36 import static jdk.nashorn.internal.parser.TokenType.CONST; |
39 import static jdk.nashorn.internal.parser.TokenType.CONST; |
37 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; |
40 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; |
38 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX; |
41 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX; |
|
42 import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS; |
39 import static jdk.nashorn.internal.parser.TokenType.ELSE; |
43 import static jdk.nashorn.internal.parser.TokenType.ELSE; |
40 import static jdk.nashorn.internal.parser.TokenType.EOF; |
44 import static jdk.nashorn.internal.parser.TokenType.EOF; |
41 import static jdk.nashorn.internal.parser.TokenType.EOL; |
45 import static jdk.nashorn.internal.parser.TokenType.EOL; |
|
46 import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT; |
|
47 import static jdk.nashorn.internal.parser.TokenType.ESCSTRING; |
|
48 import static jdk.nashorn.internal.parser.TokenType.EXPORT; |
|
49 import static jdk.nashorn.internal.parser.TokenType.EXTENDS; |
42 import static jdk.nashorn.internal.parser.TokenType.FINALLY; |
50 import static jdk.nashorn.internal.parser.TokenType.FINALLY; |
43 import static jdk.nashorn.internal.parser.TokenType.FUNCTION; |
51 import static jdk.nashorn.internal.parser.TokenType.FUNCTION; |
44 import static jdk.nashorn.internal.parser.TokenType.IDENT; |
52 import static jdk.nashorn.internal.parser.TokenType.IDENT; |
45 import static jdk.nashorn.internal.parser.TokenType.IF; |
53 import static jdk.nashorn.internal.parser.TokenType.IF; |
|
54 import static jdk.nashorn.internal.parser.TokenType.IMPORT; |
46 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; |
55 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; |
47 import static jdk.nashorn.internal.parser.TokenType.LBRACE; |
56 import static jdk.nashorn.internal.parser.TokenType.LBRACE; |
|
57 import static jdk.nashorn.internal.parser.TokenType.LBRACKET; |
48 import static jdk.nashorn.internal.parser.TokenType.LET; |
58 import static jdk.nashorn.internal.parser.TokenType.LET; |
49 import static jdk.nashorn.internal.parser.TokenType.LPAREN; |
59 import static jdk.nashorn.internal.parser.TokenType.LPAREN; |
|
60 import static jdk.nashorn.internal.parser.TokenType.MUL; |
|
61 import static jdk.nashorn.internal.parser.TokenType.PERIOD; |
50 import static jdk.nashorn.internal.parser.TokenType.RBRACE; |
62 import static jdk.nashorn.internal.parser.TokenType.RBRACE; |
51 import static jdk.nashorn.internal.parser.TokenType.RBRACKET; |
63 import static jdk.nashorn.internal.parser.TokenType.RBRACKET; |
52 import static jdk.nashorn.internal.parser.TokenType.RPAREN; |
64 import static jdk.nashorn.internal.parser.TokenType.RPAREN; |
53 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; |
65 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; |
|
66 import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY; |
|
67 import static jdk.nashorn.internal.parser.TokenType.STATIC; |
|
68 import static jdk.nashorn.internal.parser.TokenType.STRING; |
|
69 import static jdk.nashorn.internal.parser.TokenType.SUPER; |
54 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE; |
70 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE; |
55 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD; |
71 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD; |
56 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE; |
72 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE; |
57 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL; |
73 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL; |
58 import static jdk.nashorn.internal.parser.TokenType.TERNARY; |
74 import static jdk.nashorn.internal.parser.TokenType.TERNARY; |
|
75 import static jdk.nashorn.internal.parser.TokenType.VAR; |
|
76 import static jdk.nashorn.internal.parser.TokenType.VOID; |
59 import static jdk.nashorn.internal.parser.TokenType.WHILE; |
77 import static jdk.nashorn.internal.parser.TokenType.WHILE; |
|
78 import static jdk.nashorn.internal.parser.TokenType.YIELD; |
|
79 import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR; |
60 |
80 |
61 import java.io.Serializable; |
81 import java.io.Serializable; |
62 import java.util.ArrayDeque; |
82 import java.util.ArrayDeque; |
63 import java.util.ArrayList; |
83 import java.util.ArrayList; |
64 import java.util.Collections; |
84 import java.util.Collections; |
77 import jdk.nashorn.internal.ir.BlockStatement; |
99 import jdk.nashorn.internal.ir.BlockStatement; |
78 import jdk.nashorn.internal.ir.BreakNode; |
100 import jdk.nashorn.internal.ir.BreakNode; |
79 import jdk.nashorn.internal.ir.CallNode; |
101 import jdk.nashorn.internal.ir.CallNode; |
80 import jdk.nashorn.internal.ir.CaseNode; |
102 import jdk.nashorn.internal.ir.CaseNode; |
81 import jdk.nashorn.internal.ir.CatchNode; |
103 import jdk.nashorn.internal.ir.CatchNode; |
|
104 import jdk.nashorn.internal.ir.ClassNode; |
82 import jdk.nashorn.internal.ir.ContinueNode; |
105 import jdk.nashorn.internal.ir.ContinueNode; |
83 import jdk.nashorn.internal.ir.DebuggerNode; |
106 import jdk.nashorn.internal.ir.DebuggerNode; |
84 import jdk.nashorn.internal.ir.EmptyNode; |
107 import jdk.nashorn.internal.ir.EmptyNode; |
85 import jdk.nashorn.internal.ir.ErrorNode; |
108 import jdk.nashorn.internal.ir.ErrorNode; |
86 import jdk.nashorn.internal.ir.Expression; |
109 import jdk.nashorn.internal.ir.Expression; |
|
110 import jdk.nashorn.internal.ir.ExpressionList; |
87 import jdk.nashorn.internal.ir.ExpressionStatement; |
111 import jdk.nashorn.internal.ir.ExpressionStatement; |
88 import jdk.nashorn.internal.ir.ForNode; |
112 import jdk.nashorn.internal.ir.ForNode; |
89 import jdk.nashorn.internal.ir.FunctionNode; |
113 import jdk.nashorn.internal.ir.FunctionNode; |
90 import jdk.nashorn.internal.ir.IdentNode; |
114 import jdk.nashorn.internal.ir.IdentNode; |
91 import jdk.nashorn.internal.ir.IfNode; |
115 import jdk.nashorn.internal.ir.IfNode; |
92 import jdk.nashorn.internal.ir.IndexNode; |
116 import jdk.nashorn.internal.ir.IndexNode; |
93 import jdk.nashorn.internal.ir.JoinPredecessorExpression; |
117 import jdk.nashorn.internal.ir.JoinPredecessorExpression; |
94 import jdk.nashorn.internal.ir.LabelNode; |
118 import jdk.nashorn.internal.ir.LabelNode; |
|
119 import jdk.nashorn.internal.ir.LexicalContext; |
95 import jdk.nashorn.internal.ir.LiteralNode; |
120 import jdk.nashorn.internal.ir.LiteralNode; |
|
121 import jdk.nashorn.internal.ir.Module; |
96 import jdk.nashorn.internal.ir.Node; |
122 import jdk.nashorn.internal.ir.Node; |
97 import jdk.nashorn.internal.ir.ObjectNode; |
123 import jdk.nashorn.internal.ir.ObjectNode; |
98 import jdk.nashorn.internal.ir.PropertyKey; |
124 import jdk.nashorn.internal.ir.PropertyKey; |
99 import jdk.nashorn.internal.ir.PropertyNode; |
125 import jdk.nashorn.internal.ir.PropertyNode; |
100 import jdk.nashorn.internal.ir.ReturnNode; |
126 import jdk.nashorn.internal.ir.ReturnNode; |
632 case ASSIGN_MUL: |
726 case ASSIGN_MUL: |
633 case ASSIGN_SAR: |
727 case ASSIGN_SAR: |
634 case ASSIGN_SHL: |
728 case ASSIGN_SHL: |
635 case ASSIGN_SHR: |
729 case ASSIGN_SHR: |
636 case ASSIGN_SUB: |
730 case ASSIGN_SUB: |
637 if (!(lhs instanceof AccessNode || |
|
638 lhs instanceof IndexNode || |
|
639 lhs instanceof IdentNode)) { |
|
640 return referenceError(lhs, rhs, env._early_lvalue_error); |
|
641 } |
|
642 |
|
643 if (lhs instanceof IdentNode) { |
731 if (lhs instanceof IdentNode) { |
644 if (!checkIdentLValue((IdentNode)lhs)) { |
732 if (!checkIdentLValue((IdentNode)lhs)) { |
645 return referenceError(lhs, rhs, false); |
733 return referenceError(lhs, rhs, false); |
646 } |
734 } |
647 verifyStrictIdent((IdentNode)lhs, "assignment"); |
735 verifyIdent((IdentNode)lhs, "assignment"); |
648 } |
736 break; |
649 break; |
737 } else if (lhs instanceof AccessNode || lhs instanceof IndexNode) { |
650 |
738 break; |
|
739 } else if (opType == ASSIGN && isDestructuringLhs(lhs)) { |
|
740 verifyDestructuringAssignmentPattern(lhs, "assignment"); |
|
741 break; |
|
742 } else { |
|
743 return referenceError(lhs, rhs, env._early_lvalue_error); |
|
744 } |
651 default: |
745 default: |
652 break; |
746 break; |
653 } |
747 } |
654 |
748 |
655 // Build up node. |
749 // Build up node. |
656 if(BinaryNode.isLogical(opType)) { |
750 if(BinaryNode.isLogical(opType)) { |
|
751 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); |
|
752 } |
|
753 return new BinaryNode(op, lhs, rhs); |
|
754 } |
|
755 |
|
756 private boolean isDestructuringLhs(Expression lhs) { |
|
757 if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) { |
|
758 return isES6(); |
|
759 } |
|
760 return false; |
|
761 } |
|
762 |
|
763 private void verifyDestructuringAssignmentPattern(Expression pattern, String contextString) { |
|
764 assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; |
|
765 pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
|
766 @Override |
|
767 public boolean enterLiteralNode(LiteralNode<?> literalNode) { |
|
768 if (literalNode.isArray()) { |
|
769 boolean restElement = false; |
|
770 for (Expression element : literalNode.getElementExpressions()) { |
|
771 if (element != null) { |
|
772 if (restElement) { |
|
773 throw error(String.format("Unexpected element after rest element"), element.getToken()); |
|
774 } |
|
775 if (element.isTokenType(SPREAD_ARRAY)) { |
|
776 restElement = true; |
|
777 Expression lvalue = ((UnaryNode) element).getExpression(); |
|
778 if (!checkValidLValue(lvalue, contextString)) { |
|
779 throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken()); |
|
780 } |
|
781 } |
|
782 element.accept(this); |
|
783 } |
|
784 } |
|
785 return false; |
|
786 } else { |
|
787 return enterDefault(literalNode); |
|
788 } |
|
789 } |
|
790 |
|
791 @Override |
|
792 public boolean enterObjectNode(ObjectNode objectNode) { |
|
793 return true; |
|
794 } |
|
795 |
|
796 @Override |
|
797 public boolean enterPropertyNode(PropertyNode propertyNode) { |
|
798 if (propertyNode.getValue() != null) { |
|
799 propertyNode.getValue().accept(this); |
|
800 return false; |
|
801 } else { |
|
802 return enterDefault(propertyNode); |
|
803 } |
|
804 } |
|
805 |
|
806 @Override |
|
807 public boolean enterIdentNode(IdentNode identNode) { |
|
808 verifyIdent(identNode, contextString); |
|
809 if (!checkIdentLValue(identNode)) { |
|
810 referenceError(identNode, null, true); |
|
811 return false; |
|
812 } |
|
813 return false; |
|
814 } |
|
815 |
|
816 @Override |
|
817 public boolean enterAccessNode(AccessNode accessNode) { |
|
818 return false; |
|
819 } |
|
820 |
|
821 @Override |
|
822 public boolean enterIndexNode(IndexNode indexNode) { |
|
823 return false; |
|
824 } |
|
825 |
|
826 @Override |
|
827 public boolean enterBinaryNode(BinaryNode binaryNode) { |
|
828 if (binaryNode.isTokenType(ASSIGN)) { |
|
829 binaryNode.lhs().accept(this); |
|
830 // Initializer(rhs) can be any AssignmentExpression |
|
831 return false; |
|
832 } else { |
|
833 return enterDefault(binaryNode); |
|
834 } |
|
835 } |
|
836 |
|
837 @Override |
|
838 public boolean enterUnaryNode(UnaryNode unaryNode) { |
|
839 if (unaryNode.isTokenType(SPREAD_ARRAY)) { |
|
840 // rest element |
|
841 return true; |
|
842 } else { |
|
843 return enterDefault(unaryNode); |
|
844 } |
|
845 } |
|
846 |
|
847 @Override |
|
848 protected boolean enterDefault(Node node) { |
|
849 throw error(String.format("unexpected node in AssignmentPattern: %s", node)); |
|
850 } |
|
851 }); |
|
852 } |
|
853 |
|
854 private static Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) { |
|
855 final TokenType opType = Token.descType(op); |
|
856 |
|
857 // Build up node. |
|
858 if (BinaryNode.isLogical(opType)) { |
657 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); |
859 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); |
658 } |
860 } |
659 return new BinaryNode(op, lhs, rhs); |
861 return new BinaryNode(op, lhs, rhs); |
660 } |
862 } |
661 |
863 |
984 final FunctionNode fn = propertyFunction.functionNode; |
1219 final FunctionNode fn = propertyFunction.functionNode; |
985 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); |
1220 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); |
986 } |
1221 } |
987 |
1222 |
988 /** |
1223 /** |
|
1224 * ClassDeclaration[Yield, Default] : |
|
1225 * class BindingIdentifier[?Yield] ClassTail[?Yield] |
|
1226 * [+Default] class ClassTail[?Yield] |
|
1227 */ |
|
1228 private ClassNode classDeclaration(boolean isDefault) { |
|
1229 int classLineNumber = line; |
|
1230 |
|
1231 ClassNode classExpression = classExpression(!isDefault); |
|
1232 |
|
1233 if (!isDefault) { |
|
1234 VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST); |
|
1235 appendStatement(classVar); |
|
1236 } |
|
1237 return classExpression; |
|
1238 } |
|
1239 |
|
1240 /** |
|
1241 * ClassExpression[Yield] : |
|
1242 * class BindingIdentifier[?Yield]opt ClassTail[?Yield] |
|
1243 */ |
|
1244 private ClassNode classExpression(boolean isStatement) { |
|
1245 assert type == CLASS; |
|
1246 int classLineNumber = line; |
|
1247 long classToken = token; |
|
1248 next(); |
|
1249 |
|
1250 IdentNode className = null; |
|
1251 if (isStatement || type == IDENT) { |
|
1252 className = getIdent(); |
|
1253 } |
|
1254 |
|
1255 return classTail(classLineNumber, classToken, className); |
|
1256 } |
|
1257 |
|
1258 private static final class ClassElementKey { |
|
1259 private final boolean isStatic; |
|
1260 private final String propertyName; |
|
1261 |
|
1262 private ClassElementKey(boolean isStatic, String propertyName) { |
|
1263 this.isStatic = isStatic; |
|
1264 this.propertyName = propertyName; |
|
1265 } |
|
1266 |
|
1267 @Override |
|
1268 public int hashCode() { |
|
1269 final int prime = 31; |
|
1270 int result = 1; |
|
1271 result = prime * result + (isStatic ? 1231 : 1237); |
|
1272 result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode()); |
|
1273 return result; |
|
1274 } |
|
1275 |
|
1276 @Override |
|
1277 public boolean equals(Object obj) { |
|
1278 if (obj instanceof ClassElementKey) { |
|
1279 ClassElementKey other = (ClassElementKey) obj; |
|
1280 return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName); |
|
1281 } |
|
1282 return false; |
|
1283 } |
|
1284 } |
|
1285 |
|
1286 /** |
|
1287 * Parse ClassTail and ClassBody. |
|
1288 * |
|
1289 * ClassTail[Yield] : |
|
1290 * ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } |
|
1291 * ClassHeritage[Yield] : |
|
1292 * extends LeftHandSideExpression[?Yield] |
|
1293 * |
|
1294 * ClassBody[Yield] : |
|
1295 * ClassElementList[?Yield] |
|
1296 * ClassElementList[Yield] : |
|
1297 * ClassElement[?Yield] |
|
1298 * ClassElementList[?Yield] ClassElement[?Yield] |
|
1299 * ClassElement[Yield] : |
|
1300 * MethodDefinition[?Yield] |
|
1301 * static MethodDefinition[?Yield] |
|
1302 * ; |
|
1303 */ |
|
1304 private ClassNode classTail(final int classLineNumber, final long classToken, final IdentNode className) { |
|
1305 final boolean oldStrictMode = isStrictMode; |
|
1306 isStrictMode = true; |
|
1307 try { |
|
1308 Expression classHeritage = null; |
|
1309 if (type == EXTENDS) { |
|
1310 next(); |
|
1311 classHeritage = leftHandSideExpression(); |
|
1312 } |
|
1313 |
|
1314 expect(LBRACE); |
|
1315 |
|
1316 PropertyNode constructor = null; |
|
1317 final ArrayList<PropertyNode> classElements = new ArrayList<>(); |
|
1318 final Map<ClassElementKey, Integer> keyToIndexMap = new HashMap<>(); |
|
1319 for (;;) { |
|
1320 if (type == SEMICOLON) { |
|
1321 next(); |
|
1322 continue; |
|
1323 } |
|
1324 if (type == RBRACE) { |
|
1325 break; |
|
1326 } |
|
1327 final long classElementToken = token; |
|
1328 boolean isStatic = false; |
|
1329 if (type == STATIC) { |
|
1330 isStatic = true; |
|
1331 next(); |
|
1332 } |
|
1333 boolean generator = false; |
|
1334 if (isES6() && type == MUL) { |
|
1335 generator = true; |
|
1336 next(); |
|
1337 } |
|
1338 final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator); |
|
1339 if (classElement.isComputed()) { |
|
1340 classElements.add(classElement); |
|
1341 } else if (!classElement.isStatic() && classElement.getKeyName().equals("constructor")) { |
|
1342 if (constructor == null) { |
|
1343 constructor = classElement; |
|
1344 } else { |
|
1345 throw error(AbstractParser.message("multiple.constructors"), classElementToken); |
|
1346 } |
|
1347 } else { |
|
1348 // Check for duplicate method definitions and combine accessor methods. |
|
1349 // In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names). |
|
1350 |
|
1351 final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName()); |
|
1352 final Integer existing = keyToIndexMap.get(key); |
|
1353 |
|
1354 if (existing == null) { |
|
1355 keyToIndexMap.put(key, classElements.size()); |
|
1356 classElements.add(classElement); |
|
1357 } else { |
|
1358 final PropertyNode existingProperty = classElements.get(existing); |
|
1359 |
|
1360 final Expression value = classElement.getValue(); |
|
1361 final FunctionNode getter = classElement.getGetter(); |
|
1362 final FunctionNode setter = classElement.getSetter(); |
|
1363 |
|
1364 if (value != null || existingProperty.getValue() != null) { |
|
1365 keyToIndexMap.put(key, classElements.size()); |
|
1366 classElements.add(classElement); |
|
1367 } else if (getter != null) { |
|
1368 assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; |
|
1369 classElements.set(existing, existingProperty.setGetter(getter)); |
|
1370 } else if (setter != null) { |
|
1371 assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; |
|
1372 classElements.set(existing, existingProperty.setSetter(setter)); |
|
1373 } |
|
1374 } |
|
1375 } |
|
1376 } |
|
1377 |
|
1378 final long lastToken = token; |
|
1379 expect(RBRACE); |
|
1380 |
|
1381 if (constructor == null) { |
|
1382 constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null); |
|
1383 } |
|
1384 |
|
1385 classElements.trimToSize(); |
|
1386 return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements); |
|
1387 } finally { |
|
1388 isStrictMode = oldStrictMode; |
|
1389 } |
|
1390 } |
|
1391 |
|
1392 private PropertyNode createDefaultClassConstructor(int classLineNumber, long classToken, long lastToken, IdentNode className, boolean subclass) { |
|
1393 final int ctorFinish = finish; |
|
1394 final List<Statement> statements; |
|
1395 final List<IdentNode> parameters; |
|
1396 final long identToken = Token.recast(classToken, TokenType.IDENT); |
|
1397 if (subclass) { |
|
1398 final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper(); |
|
1399 final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter(); |
|
1400 final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent); |
|
1401 final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false); |
|
1402 statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall)); |
|
1403 parameters = Collections.singletonList(argsIdent); |
|
1404 } else { |
|
1405 statements = Collections.emptyList(); |
|
1406 parameters = Collections.emptyList(); |
|
1407 } |
|
1408 |
|
1409 final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements); |
|
1410 final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, "constructor"); |
|
1411 final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters); |
|
1412 function.setLastToken(lastToken); |
|
1413 |
|
1414 function.setFlag(FunctionNode.ES6_IS_METHOD); |
|
1415 function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR); |
|
1416 if (subclass) { |
|
1417 function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR); |
|
1418 function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); |
|
1419 } |
|
1420 if (className == null) { |
|
1421 function.setFlag(FunctionNode.IS_ANONYMOUS); |
|
1422 } |
|
1423 |
|
1424 final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode( |
|
1425 function, |
|
1426 classToken, |
|
1427 ctorName, |
|
1428 parameters, |
|
1429 FunctionNode.Kind.NORMAL, |
|
1430 classLineNumber, |
|
1431 body |
|
1432 ), null, null, false, false); |
|
1433 return constructor; |
|
1434 } |
|
1435 |
|
1436 private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) { |
|
1437 final long methodToken = token; |
|
1438 final int methodLine = line; |
|
1439 final boolean computed = type == LBRACKET; |
|
1440 final boolean isIdent = type == IDENT; |
|
1441 final Expression propertyName = propertyName(); |
|
1442 int flags = FunctionNode.ES6_IS_METHOD; |
|
1443 if (!computed) { |
|
1444 final String name = ((PropertyKey)propertyName).getPropertyName(); |
|
1445 if (!generator && isIdent && type != LPAREN && name.equals("get")) { |
|
1446 final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags); |
|
1447 verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); |
|
1448 return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed); |
|
1449 } else if (!generator && isIdent && type != LPAREN && name.equals("set")) { |
|
1450 final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags); |
|
1451 verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); |
|
1452 return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed); |
|
1453 } else { |
|
1454 if (!isStatic && !generator && name.equals("constructor")) { |
|
1455 flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR; |
|
1456 if (subclass) { |
|
1457 flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR; |
|
1458 } |
|
1459 } |
|
1460 verifyAllowedMethodName(propertyName, isStatic, computed, generator, false); |
|
1461 } |
|
1462 } |
|
1463 final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed); |
|
1464 return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed); |
|
1465 } |
|
1466 |
|
1467 /** |
|
1468 * ES6 14.5.1 Static Semantics: Early Errors. |
|
1469 */ |
|
1470 private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) { |
|
1471 if (!computed) { |
|
1472 if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals("constructor")) { |
|
1473 throw error(AbstractParser.message("generator.constructor"), key.getToken()); |
|
1474 } |
|
1475 if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals("constructor")) { |
|
1476 throw error(AbstractParser.message("accessor.constructor"), key.getToken()); |
|
1477 } |
|
1478 if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) { |
|
1479 throw error(AbstractParser.message("static.prototype.method"), key.getToken()); |
|
1480 } |
|
1481 } |
|
1482 } |
|
1483 |
|
1484 /** |
989 * block : |
1485 * block : |
990 * { StatementList? } |
1486 * { StatementList? } |
991 * |
1487 * |
992 * see 12.1 |
1488 * see 12.1 |
993 * |
1489 * |
1064 * See 12.2 |
1576 * See 12.2 |
1065 * |
1577 * |
1066 * Parse a VAR statement. |
1578 * Parse a VAR statement. |
1067 * @param isStatement True if a statement (not used in a FOR.) |
1579 * @param isStatement True if a statement (not used in a FOR.) |
1068 */ |
1580 */ |
1069 private List<VarNode> variableStatement(final TokenType varType) { |
1581 private void variableStatement(final TokenType varType) { |
1070 return variableStatement(varType, true, -1); |
1582 variableDeclarationList(varType, true, -1); |
1071 } |
1583 } |
1072 |
1584 |
1073 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement, final int sourceOrder) { |
1585 private List<Expression> variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) { |
1074 // VAR tested in caller. |
1586 // VAR tested in caller. |
|
1587 assert varType == VAR || varType == LET || varType == CONST; |
1075 next(); |
1588 next(); |
1076 |
1589 |
1077 final List<VarNode> vars = new ArrayList<>(); |
1590 final List<Expression> bindings = new ArrayList<>(); |
1078 int varFlags = 0; |
1591 int varFlags = 0; |
1079 if (varType == LET) { |
1592 if (varType == LET) { |
1080 varFlags |= VarNode.IS_LET; |
1593 varFlags |= VarNode.IS_LET; |
1081 } else if (varType == CONST) { |
1594 } else if (varType == CONST) { |
1082 varFlags |= VarNode.IS_CONST; |
1595 varFlags |= VarNode.IS_CONST; |
1083 } |
1596 } |
1084 |
1597 |
|
1598 Expression missingAssignment = null; |
1085 while (true) { |
1599 while (true) { |
1086 // Get starting token. |
1600 // Get starting token. |
1087 final int varLine = line; |
1601 final int varLine = line; |
1088 final long varToken = token; |
1602 final long varToken = token; |
1089 // Get name of var. |
1603 // Get name of var. |
1090 final IdentNode name = getIdent(); |
1604 if (type == YIELD && inGeneratorFunction()) { |
1091 verifyStrictIdent(name, "variable name"); |
1605 expect(IDENT); |
|
1606 } |
|
1607 |
|
1608 final String contextString = "variable name"; |
|
1609 Expression binding = bindingIdentifierOrPattern(contextString); |
|
1610 final boolean isDestructuring = !(binding instanceof IdentNode); |
|
1611 if (isDestructuring) { |
|
1612 final int finalVarFlags = varFlags; |
|
1613 verifyDestructuringBindingPattern(binding, new Consumer<IdentNode>() { |
|
1614 public void accept(final IdentNode identNode) { |
|
1615 verifyIdent(identNode, contextString); |
|
1616 final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags); |
|
1617 appendStatement(var); |
|
1618 } |
|
1619 }); |
|
1620 } |
1092 |
1621 |
1093 // Assume no init. |
1622 // Assume no init. |
1094 Expression init = null; |
1623 Expression init = null; |
1095 |
1624 |
1096 // Look for initializer assignment. |
1625 // Look for initializer assignment. |
1097 if (type == ASSIGN) { |
1626 if (type == ASSIGN) { |
1098 next(); |
1627 next(); |
1099 |
1628 |
1100 // Get initializer expression. Suppress IN if not statement. |
1629 // Get initializer expression. Suppress IN if not statement. |
1101 defaultNames.push(name); |
1630 if (!isDestructuring) { |
|
1631 defaultNames.push(binding); |
|
1632 } |
1102 try { |
1633 try { |
1103 init = assignmentExpression(!isStatement); |
1634 init = assignmentExpression(!isStatement); |
1104 } finally { |
1635 } finally { |
1105 defaultNames.pop(); |
1636 if (!isDestructuring) { |
1106 } |
1637 defaultNames.pop(); |
1107 } else if (varType == CONST && isStatement) { |
1638 } |
1108 throw error(AbstractParser.message("missing.const.assignment", name.getName())); |
1639 } |
1109 } |
1640 } else if (isStatement) { |
1110 |
1641 if (isDestructuring) { |
1111 // Only set declaration flag on lexically scoped let/const as it adds runtime overhead. |
1642 throw error(AbstractParser.message("missing.destructuring.assignment"), token); |
1112 final IdentNode actualName = varType == LET || varType == CONST ? name.setIsDeclaredHere() : name; |
1643 } else if (varType == CONST) { |
1113 // Allocate var node. |
1644 throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName())); |
1114 final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, actualName, init, varFlags); |
1645 } |
1115 vars.add(var); |
1646 // else, if we are in a for loop, delay checking until we know the kind of loop |
1116 appendStatement(var); |
1647 } |
|
1648 |
|
1649 if (!isDestructuring) { |
|
1650 assert init != null || varType != CONST || !isStatement; |
|
1651 final IdentNode ident = (IdentNode)binding; |
|
1652 if (!isStatement && ident.getName().equals("let")) { |
|
1653 throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1 |
|
1654 } |
|
1655 // Only set declaration flag on lexically scoped let/const as it adds runtime overhead. |
|
1656 final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident; |
|
1657 binding = name; |
|
1658 final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags); |
|
1659 appendStatement(var); |
|
1660 if (init == null && varType == CONST) { |
|
1661 if (missingAssignment == null) { |
|
1662 missingAssignment = binding; |
|
1663 } |
|
1664 } |
|
1665 } else { |
|
1666 assert init != null || !isStatement; |
|
1667 binding = init == null ? binding : verifyAssignment(Token.recast(varToken, ASSIGN), binding, init); |
|
1668 if (isStatement) { |
|
1669 appendStatement(new ExpressionStatement(varLine, binding.getToken(), finish, binding)); |
|
1670 } else if (init == null) { |
|
1671 if (missingAssignment == null) { |
|
1672 missingAssignment = binding; |
|
1673 } |
|
1674 } |
|
1675 } |
|
1676 bindings.add(binding); |
1117 |
1677 |
1118 if (type != COMMARIGHT) { |
1678 if (type != COMMARIGHT) { |
1119 break; |
1679 break; |
1120 } |
1680 } |
1121 next(); |
1681 next(); |
1122 } |
1682 } |
1123 |
1683 |
1124 // If is a statement then handle end of line. |
1684 // If is a statement then handle end of line. |
1125 if (isStatement) { |
1685 if (isStatement) { |
1126 endOfLine(); |
1686 endOfLine(); |
1127 } |
1687 } else { |
1128 |
1688 if (type == SEMICOLON) { |
1129 return vars; |
1689 // late check for missing assignment, now we know it's a for (init; test; modify) loop |
|
1690 if (missingAssignment != null) { |
|
1691 if (missingAssignment instanceof IdentNode) { |
|
1692 throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)missingAssignment).getName())); |
|
1693 } else { |
|
1694 throw error(AbstractParser.message("missing.destructuring.assignment"), missingAssignment.getToken()); |
|
1695 } |
|
1696 } |
|
1697 } |
|
1698 } |
|
1699 |
|
1700 return bindings; |
|
1701 } |
|
1702 |
|
1703 private boolean isBindingIdentifier() { |
|
1704 return type == IDENT || isNonStrictModeIdent(); |
|
1705 } |
|
1706 |
|
1707 private IdentNode bindingIdentifier(final String contextString) { |
|
1708 final IdentNode name = getIdent(); |
|
1709 verifyIdent(name, contextString); |
|
1710 return name; |
|
1711 } |
|
1712 |
|
1713 private Expression bindingPattern() { |
|
1714 if (type == LBRACKET) { |
|
1715 return arrayLiteral(); |
|
1716 } else if (type == LBRACE) { |
|
1717 return objectLiteral(); |
|
1718 } else { |
|
1719 throw error(AbstractParser.message("expected.binding")); |
|
1720 } |
|
1721 } |
|
1722 |
|
1723 private Expression bindingIdentifierOrPattern(final String contextString) { |
|
1724 if (isBindingIdentifier() || !isES6()) { |
|
1725 return bindingIdentifier(contextString); |
|
1726 } else { |
|
1727 return bindingPattern(); |
|
1728 } |
|
1729 } |
|
1730 |
|
1731 /** |
|
1732 * Verify destructuring variable declaration binding pattern and extract bound variable declarations. |
|
1733 */ |
|
1734 private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer<IdentNode> identifierCallback) { |
|
1735 assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; |
|
1736 pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
|
1737 @Override |
|
1738 public boolean enterLiteralNode(final LiteralNode<?> literalNode) { |
|
1739 if (literalNode.isArray()) { |
|
1740 boolean restElement = false; |
|
1741 for (final Expression element : literalNode.getElementExpressions()) { |
|
1742 if (restElement) { |
|
1743 throw error(String.format("Unexpected element after rest element"), element.getToken()); |
|
1744 } |
|
1745 if (element != null) { |
|
1746 if (element.isTokenType(SPREAD_ARRAY)) { |
|
1747 restElement = true; |
|
1748 if (!(((UnaryNode) element).getExpression() instanceof IdentNode)) { |
|
1749 throw error(String.format("Expected a valid binding identifier"), element.getToken()); |
|
1750 |
|
1751 } |
|
1752 } |
|
1753 element.accept(this); |
|
1754 } |
|
1755 } |
|
1756 return false; |
|
1757 } else { |
|
1758 return enterDefault(literalNode); |
|
1759 } |
|
1760 } |
|
1761 |
|
1762 @Override |
|
1763 public boolean enterObjectNode(final ObjectNode objectNode) { |
|
1764 return true; |
|
1765 } |
|
1766 |
|
1767 @Override |
|
1768 public boolean enterPropertyNode(final PropertyNode propertyNode) { |
|
1769 if (propertyNode.getValue() != null) { |
|
1770 propertyNode.getValue().accept(this); |
|
1771 return false; |
|
1772 } else { |
|
1773 return enterDefault(propertyNode); |
|
1774 } |
|
1775 } |
|
1776 |
|
1777 @Override |
|
1778 public boolean enterIdentNode(final IdentNode identNode) { |
|
1779 identifierCallback.accept(identNode); |
|
1780 return false; |
|
1781 } |
|
1782 |
|
1783 @Override |
|
1784 public boolean enterBinaryNode(final BinaryNode binaryNode) { |
|
1785 if (binaryNode.isTokenType(ASSIGN)) { |
|
1786 binaryNode.lhs().accept(this); |
|
1787 // Initializer(rhs) can be any AssignmentExpression |
|
1788 return false; |
|
1789 } else { |
|
1790 return enterDefault(binaryNode); |
|
1791 } |
|
1792 } |
|
1793 |
|
1794 @Override |
|
1795 public boolean enterUnaryNode(final UnaryNode unaryNode) { |
|
1796 if (unaryNode.isTokenType(SPREAD_ARRAY)) { |
|
1797 // rest element |
|
1798 return true; |
|
1799 } else { |
|
1800 return enterDefault(unaryNode); |
|
1801 } |
|
1802 } |
|
1803 |
|
1804 @Override |
|
1805 protected boolean enterDefault(final Node node) { |
|
1806 throw error(String.format("unexpected node in BindingPattern: %s", node)); |
|
1807 } |
|
1808 }); |
1130 } |
1809 } |
1131 |
1810 |
1132 /** |
1811 /** |
1133 * EmptyStatement : |
1812 * EmptyStatement : |
1134 * ; |
1813 * ; |
1589 // Construct and add RETURN node. |
2314 // Construct and add RETURN node. |
1590 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); |
2315 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); |
1591 } |
2316 } |
1592 |
2317 |
1593 /** |
2318 /** |
1594 * YieldStatement : |
2319 * Parse YieldExpression. |
1595 * yield Expression? ; // [no LineTerminator here] |
2320 * |
1596 * |
2321 * YieldExpression[In] : |
1597 * JavaScript 1.8 |
2322 * yield |
1598 * |
2323 * yield [no LineTerminator here] AssignmentExpression[?In, Yield] |
1599 * Parse YIELD statement. |
2324 * yield [no LineTerminator here] * AssignmentExpression[?In, Yield] |
1600 */ |
2325 */ |
1601 private void yieldStatement() { |
2326 private Expression yieldExpression(final boolean noIn) { |
|
2327 assert inGeneratorFunction(); |
1602 // Capture YIELD token. |
2328 // Capture YIELD token. |
1603 final int yieldLine = line; |
2329 long yieldToken = token; |
1604 final long yieldToken = token; |
|
1605 // YIELD tested in caller. |
2330 // YIELD tested in caller. |
|
2331 assert type == YIELD; |
1606 nextOrEOL(); |
2332 nextOrEOL(); |
1607 |
2333 |
1608 Expression expression = null; |
2334 Expression expression = null; |
1609 |
2335 |
1610 // SEMICOLON or expression. |
2336 boolean yieldAsterisk = false; |
|
2337 if (type == MUL) { |
|
2338 yieldAsterisk = true; |
|
2339 yieldToken = Token.recast(yieldToken, YIELD_STAR); |
|
2340 next(); |
|
2341 } |
|
2342 |
1611 switch (type) { |
2343 switch (type) { |
1612 case RBRACE: |
2344 case RBRACE: |
1613 case SEMICOLON: |
2345 case SEMICOLON: |
1614 case EOL: |
2346 case EOL: |
1615 case EOF: |
2347 case EOF: |
|
2348 case COMMARIGHT: |
|
2349 case RPAREN: |
|
2350 case RBRACKET: |
|
2351 case COLON: |
|
2352 if (!yieldAsterisk) { |
|
2353 // treat (yield) as (yield void 0) |
|
2354 expression = newUndefinedLiteral(yieldToken, finish); |
|
2355 if (type == EOL) { |
|
2356 next(); |
|
2357 } |
|
2358 break; |
|
2359 } else { |
|
2360 // AssignmentExpression required, fall through |
|
2361 } |
|
2362 |
|
2363 default: |
|
2364 expression = assignmentExpression(noIn); |
1616 break; |
2365 break; |
1617 |
2366 } |
1618 default: |
|
1619 expression = expression(); |
|
1620 break; |
|
1621 } |
|
1622 |
|
1623 endOfLine(); |
|
1624 |
2367 |
1625 // Construct and add YIELD node. |
2368 // Construct and add YIELD node. |
1626 appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression)); |
2369 return new UnaryNode(yieldToken, expression); |
|
2370 } |
|
2371 |
|
2372 private static UnaryNode newUndefinedLiteral(final long token, final int finish) { |
|
2373 return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0)); |
1627 } |
2374 } |
1628 |
2375 |
1629 /** |
2376 /** |
1630 * WithStatement : |
2377 * WithStatement : |
1631 * with ( Expression ) Statement |
2378 * with ( Expression ) Statement |
2183 |
2975 |
2184 final Expression prevValue = existingProperty.getValue(); |
2976 final Expression prevValue = existingProperty.getValue(); |
2185 final FunctionNode prevGetter = existingProperty.getGetter(); |
2977 final FunctionNode prevGetter = existingProperty.getGetter(); |
2186 final FunctionNode prevSetter = existingProperty.getSetter(); |
2978 final FunctionNode prevSetter = existingProperty.getSetter(); |
2187 |
2979 |
2188 // ECMA 11.1.5 strict mode restrictions |
2980 if (!isES6()) { |
2189 if (isStrictMode && value != null && prevValue != null) { |
2981 checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter); |
2190 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); |
2982 } else { |
2191 } |
2983 if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() && |
2192 |
2984 existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) { |
2193 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; |
2985 throw error(AbstractParser.message("multiple.proto.key"), property.getToken()); |
2194 final boolean isAccessor = getter != null || setter != null; |
|
2195 |
|
2196 // data property redefined as accessor property |
|
2197 if (prevValue != null && isAccessor) { |
|
2198 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); |
|
2199 } |
|
2200 |
|
2201 // accessor property redefined as data |
|
2202 if (isPrevAccessor && value != null) { |
|
2203 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); |
|
2204 } |
|
2205 |
|
2206 if (isAccessor && isPrevAccessor) { |
|
2207 if (getter != null && prevGetter != null || |
|
2208 setter != null && prevSetter != null) { |
|
2209 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); |
|
2210 } |
2986 } |
2211 } |
2987 } |
2212 |
2988 |
2213 if (value != null) { |
2989 if (value != null || prevValue != null) { |
|
2990 map.put(key, elements.size()); |
2214 elements.add(property); |
2991 elements.add(property); |
2215 } else if (getter != null) { |
2992 } else if (getter != null) { |
|
2993 assert prevGetter != null || prevSetter != null; |
2216 elements.set(existing, existingProperty.setGetter(getter)); |
2994 elements.set(existing, existingProperty.setGetter(getter)); |
2217 } else if (setter != null) { |
2995 } else if (setter != null) { |
|
2996 assert prevGetter != null || prevSetter != null; |
2218 elements.set(existing, existingProperty.setSetter(setter)); |
2997 elements.set(existing, existingProperty.setSetter(setter)); |
2219 } |
2998 } |
2220 break; |
2999 break; |
2221 } |
3000 } |
2222 } |
3001 } |
2223 |
3002 |
2224 return new ObjectNode(objectToken, finish, elements); |
3003 return new ObjectNode(objectToken, finish, elements); |
2225 } |
3004 } |
2226 |
3005 |
2227 /** |
3006 private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) { |
2228 * PropertyName : |
3007 // ECMA 11.1.5 strict mode restrictions |
|
3008 if (isStrictMode && value != null && prevValue != null) { |
|
3009 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3010 } |
|
3011 |
|
3012 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; |
|
3013 final boolean isAccessor = getter != null || setter != null; |
|
3014 |
|
3015 // data property redefined as accessor property |
|
3016 if (prevValue != null && isAccessor) { |
|
3017 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3018 } |
|
3019 |
|
3020 // accessor property redefined as data |
|
3021 if (isPrevAccessor && value != null) { |
|
3022 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3023 } |
|
3024 |
|
3025 if (isAccessor && isPrevAccessor) { |
|
3026 if (getter != null && prevGetter != null || |
|
3027 setter != null && prevSetter != null) { |
|
3028 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); |
|
3029 } |
|
3030 } |
|
3031 } |
|
3032 |
|
3033 /** |
|
3034 * LiteralPropertyName : |
2229 * IdentifierName |
3035 * IdentifierName |
2230 * StringLiteral |
3036 * StringLiteral |
2231 * NumericLiteral |
3037 * NumericLiteral |
2232 * |
3038 * |
2233 * See 11.1.5 |
|
2234 * |
|
2235 * @return PropertyName node |
3039 * @return PropertyName node |
2236 */ |
3040 */ |
2237 @SuppressWarnings("fallthrough") |
3041 @SuppressWarnings("fallthrough") |
2238 private PropertyKey propertyName() { |
3042 private PropertyKey literalPropertyName() { |
2239 switch (type) { |
3043 switch (type) { |
2240 case IDENT: |
3044 case IDENT: |
2241 return getIdent().setIsPropertyName(); |
3045 return getIdent().setIsPropertyName(); |
2242 case OCTAL_LEGACY: |
3046 case OCTAL_LEGACY: |
2243 if (isStrictMode) { |
3047 if (isStrictMode) { |
2278 private PropertyNode propertyAssignment() { |
3110 private PropertyNode propertyAssignment() { |
2279 // Capture firstToken. |
3111 // Capture firstToken. |
2280 final long propertyToken = token; |
3112 final long propertyToken = token; |
2281 final int functionLine = line; |
3113 final int functionLine = line; |
2282 |
3114 |
2283 PropertyKey propertyName; |
3115 final Expression propertyName; |
2284 |
3116 final boolean isIdentifier; |
|
3117 |
|
3118 boolean generator = false; |
|
3119 if (type == MUL && isES6()) { |
|
3120 generator = true; |
|
3121 next(); |
|
3122 } |
|
3123 |
|
3124 final boolean computed = type == LBRACKET; |
2285 if (type == IDENT) { |
3125 if (type == IDENT) { |
2286 // Get IDENT. |
3126 // Get IDENT. |
2287 final String ident = (String)expectValue(IDENT); |
3127 final String ident = (String)expectValue(IDENT); |
2288 |
3128 |
2289 if (type != COLON) { |
3129 if (type != COLON && (type != LPAREN || !isES6())) { |
2290 final long getSetToken = propertyToken; |
3130 final long getSetToken = propertyToken; |
2291 |
3131 |
2292 switch (ident) { |
3132 switch (ident) { |
2293 case "get": |
3133 case "get": |
2294 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); |
3134 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); |
2295 return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); |
3135 return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed); |
2296 |
3136 |
2297 case "set": |
3137 case "set": |
2298 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); |
3138 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); |
2299 return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); |
3139 return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed); |
2300 default: |
3140 default: |
2301 break; |
3141 break; |
2302 } |
3142 } |
2303 } |
3143 } |
2304 |
3144 |
2305 propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); |
3145 isIdentifier = true; |
|
3146 IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); |
|
3147 if (type == COLON && ident.equals("__proto__")) { |
|
3148 identNode = identNode.setIsProtoPropertyName(); |
|
3149 } |
|
3150 propertyName = identNode; |
2306 } else { |
3151 } else { |
|
3152 isIdentifier = isNonStrictModeIdent(); |
2307 propertyName = propertyName(); |
3153 propertyName = propertyName(); |
2308 } |
3154 } |
2309 |
3155 |
2310 expect(COLON); |
3156 Expression propertyValue; |
2311 |
3157 |
2312 defaultNames.push(propertyName); |
3158 if (generator) { |
2313 try { |
3159 expectDontAdvance(LPAREN); |
2314 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); |
3160 } |
2315 } finally { |
3161 |
2316 defaultNames.pop(); |
3162 if (type == LPAREN && isES6()) { |
2317 } |
3163 propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode; |
|
3164 } else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) { |
|
3165 propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName()); |
|
3166 if (type == ASSIGN && isES6()) { |
|
3167 // TODO if not destructuring, this is a SyntaxError |
|
3168 final long assignToken = token; |
|
3169 next(); |
|
3170 final Expression rhs = assignmentExpression(false); |
|
3171 propertyValue = verifyAssignment(assignToken, propertyValue, rhs); |
|
3172 } |
|
3173 } else { |
|
3174 expect(COLON); |
|
3175 |
|
3176 defaultNames.push(propertyName); |
|
3177 try { |
|
3178 propertyValue = assignmentExpression(false); |
|
3179 } finally { |
|
3180 defaultNames.pop(); |
|
3181 } |
|
3182 } |
|
3183 |
|
3184 return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed); |
2318 } |
3185 } |
2319 |
3186 |
2320 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { |
3187 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { |
2321 final PropertyKey getIdent = propertyName(); |
3188 return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD); |
2322 final String getterName = getIdent.getPropertyName(); |
3189 } |
2323 final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); |
3190 |
|
3191 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) { |
|
3192 final boolean computed = type == LBRACKET; |
|
3193 final Expression propertyName = propertyName(); |
|
3194 final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false); |
|
3195 final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName)); |
2324 expect(LPAREN); |
3196 expect(LPAREN); |
2325 expect(RPAREN); |
3197 expect(RPAREN); |
2326 |
3198 |
2327 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); |
3199 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); |
|
3200 functionNode.setFlag(flags); |
|
3201 if (computed) { |
|
3202 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
|
3203 } |
2328 lc.push(functionNode); |
3204 lc.push(functionNode); |
2329 |
3205 |
2330 Block functionBody; |
3206 Block functionBody; |
2331 |
3207 |
2332 |
3208 |
2387 parameters, |
3272 parameters, |
2388 FunctionNode.Kind.SETTER, |
3273 FunctionNode.Kind.SETTER, |
2389 functionLine, |
3274 functionLine, |
2390 functionBody); |
3275 functionBody); |
2391 |
3276 |
2392 return new PropertyFunction(setIdent, function); |
3277 return new PropertyFunction(propertyName, function, computed); |
|
3278 } |
|
3279 |
|
3280 private PropertyFunction propertyMethodFunction(Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, boolean computed) { |
|
3281 final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false); |
|
3282 final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName); |
|
3283 |
|
3284 FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; |
|
3285 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null); |
|
3286 functionNode.setFlag(flags); |
|
3287 if (computed) { |
|
3288 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
|
3289 } |
|
3290 lc.push(functionNode); |
|
3291 |
|
3292 try { |
|
3293 final ParserContextBlockNode parameterBlock = newBlock(); |
|
3294 final List<IdentNode> parameters; |
|
3295 try { |
|
3296 expect(LPAREN); |
|
3297 parameters = formalParameterList(generator); |
|
3298 functionNode.setParameters(parameters); |
|
3299 expect(RPAREN); |
|
3300 } finally { |
|
3301 restoreBlock(parameterBlock); |
|
3302 } |
|
3303 |
|
3304 Block functionBody = functionBody(functionNode); |
|
3305 |
|
3306 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); |
|
3307 |
|
3308 final FunctionNode function = createFunctionNode( |
|
3309 functionNode, |
|
3310 methodToken, |
|
3311 methodNameNode, |
|
3312 parameters, |
|
3313 functionKind, |
|
3314 methodLine, |
|
3315 functionBody); |
|
3316 return new PropertyFunction(key, function, computed); |
|
3317 } finally { |
|
3318 lc.pop(functionNode); |
|
3319 } |
2393 } |
3320 } |
2394 |
3321 |
2395 private static class PropertyFunction { |
3322 private static class PropertyFunction { |
2396 final PropertyKey ident; |
3323 final Expression key; |
2397 final FunctionNode functionNode; |
3324 final FunctionNode functionNode; |
2398 |
3325 final boolean computed; |
2399 PropertyFunction(final PropertyKey ident, final FunctionNode function) { |
3326 |
2400 this.ident = ident; |
3327 PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) { |
|
3328 this.key = key; |
2401 this.functionNode = function; |
3329 this.functionNode = function; |
2402 } |
3330 this.computed = computed; |
2403 } |
3331 } |
2404 |
3332 } |
2405 /** |
3333 |
2406 * Parse left hand side expression. |
3334 /** |
2407 * |
|
2408 * LeftHandSideExpression : |
3335 * LeftHandSideExpression : |
2409 * NewExpression |
3336 * NewExpression |
2410 * CallExpression |
3337 * CallExpression |
2411 * |
3338 * |
2412 * CallExpression : |
3339 * CallExpression : |
2413 * MemberExpression Arguments |
3340 * MemberExpression Arguments |
|
3341 * SuperCall |
2414 * CallExpression Arguments |
3342 * CallExpression Arguments |
2415 * CallExpression [ Expression ] |
3343 * CallExpression [ Expression ] |
2416 * CallExpression . IdentifierName |
3344 * CallExpression . IdentifierName |
2417 * CallExpression TemplateLiteral |
3345 * |
2418 * |
3346 * SuperCall : |
|
3347 * super Arguments |
|
3348 * |
|
3349 * See 11.2 |
|
3350 * |
|
3351 * Parse left hand side expression. |
2419 * @return Expression node. |
3352 * @return Expression node. |
2420 */ |
3353 */ |
2421 private Expression leftHandSideExpression() { |
3354 private Expression leftHandSideExpression() { |
2422 int callLine = line; |
3355 int callLine = line; |
2423 long callToken = token; |
3356 long callToken = token; |
2721 final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); |
3756 final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); |
2722 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); |
3757 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); |
2723 isAnonymous = true; |
3758 isAnonymous = true; |
2724 } |
3759 } |
2725 |
3760 |
2726 expect(LPAREN); |
3761 FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; |
2727 final List<IdentNode> parameters = formalParameterList(); |
3762 List<IdentNode> parameters = Collections.emptyList(); |
2728 expect(RPAREN); |
3763 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters); |
2729 |
|
2730 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters); |
|
2731 lc.push(functionNode); |
3764 lc.push(functionNode); |
|
3765 |
2732 Block functionBody = null; |
3766 Block functionBody = null; |
2733 // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" |
3767 // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" |
2734 // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". |
3768 // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". |
2735 hideDefaultName(); |
3769 hideDefaultName(); |
2736 try{ |
3770 try { |
|
3771 final ParserContextBlockNode parameterBlock = newBlock(); |
|
3772 try { |
|
3773 expect(LPAREN); |
|
3774 parameters = formalParameterList(generator); |
|
3775 functionNode.setParameters(parameters); |
|
3776 expect(RPAREN); |
|
3777 } finally { |
|
3778 restoreBlock(parameterBlock); |
|
3779 } |
|
3780 |
2737 functionBody = functionBody(functionNode); |
3781 functionBody = functionBody(functionNode); |
|
3782 |
|
3783 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); |
2738 } finally { |
3784 } finally { |
2739 defaultNames.pop(); |
3785 defaultNames.pop(); |
2740 lc.pop(functionNode); |
3786 lc.pop(functionNode); |
2741 } |
3787 } |
2742 |
3788 |
2743 if (isStatement) { |
3789 if (isStatement) { |
2744 if (topLevel || useBlockScope()) { |
3790 if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) { |
2745 functionNode.setFlag(FunctionNode.IS_DECLARED); |
3791 functionNode.setFlag(FunctionNode.IS_DECLARED); |
2746 } else if (isStrictMode) { |
3792 } else if (isStrictMode) { |
2747 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); |
3793 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); |
2748 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { |
3794 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { |
2749 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); |
3795 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); |
2914 expect(COMMARIGHT); |
3963 expect(COMMARIGHT); |
2915 } else { |
3964 } else { |
2916 first = false; |
3965 first = false; |
2917 } |
3966 } |
2918 |
3967 |
2919 // Get and add parameter. |
3968 boolean restParameter = false; |
2920 final IdentNode ident = getIdent(); |
3969 if (type == ELLIPSIS && isES6()) { |
2921 |
3970 next(); |
2922 // ECMA 13.1 strict mode restrictions |
3971 restParameter = true; |
2923 verifyStrictIdent(ident, "function parameter"); |
3972 } |
2924 |
3973 |
|
3974 if (type == YIELD && yield) { |
|
3975 expect(IDENT); |
|
3976 } |
|
3977 |
|
3978 final long paramToken = token; |
|
3979 final int paramLine = line; |
|
3980 final String contextString = "function parameter"; |
|
3981 IdentNode ident; |
|
3982 if (isBindingIdentifier() || restParameter || !isES6()) { |
|
3983 ident = bindingIdentifier(contextString); |
|
3984 |
|
3985 if (restParameter) { |
|
3986 ident = ident.setIsRestParameter(); |
|
3987 // rest parameter must be last |
|
3988 expectDontAdvance(endType); |
|
3989 parameters.add(ident); |
|
3990 break; |
|
3991 } else if (type == ASSIGN && isES6()) { |
|
3992 next(); |
|
3993 ident = ident.setIsDefaultParameter(); |
|
3994 |
|
3995 if (type == YIELD && yield) { |
|
3996 // error: yield in default expression |
|
3997 expect(IDENT); |
|
3998 } |
|
3999 |
|
4000 // default parameter |
|
4001 Expression initializer = assignmentExpression(false); |
|
4002 |
|
4003 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4004 if (currentFunction != null) { |
|
4005 // desugar to: param = (param === undefined) ? initializer : param; |
|
4006 // possible alternative: if (param === undefined) param = initializer; |
|
4007 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
|
4008 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
|
4009 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); |
|
4010 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
|
4011 } |
|
4012 } |
|
4013 |
|
4014 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4015 if (currentFunction != null) { |
|
4016 currentFunction.addParameterBinding(ident); |
|
4017 if (ident.isRestParameter() || ident.isDefaultParameter()) { |
|
4018 currentFunction.setSimpleParameterList(false); |
|
4019 } |
|
4020 } |
|
4021 } else { |
|
4022 final Expression pattern = bindingPattern(); |
|
4023 // Introduce synthetic temporary parameter to capture the object to be destructured. |
|
4024 ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter(); |
|
4025 verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString); |
|
4026 |
|
4027 Expression value = ident; |
|
4028 if (type == ASSIGN) { |
|
4029 next(); |
|
4030 ident = ident.setIsDefaultParameter(); |
|
4031 |
|
4032 // binding pattern with initializer. desugar to: (param === undefined) ? initializer : param |
|
4033 Expression initializer = assignmentExpression(false); |
|
4034 // TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list) |
|
4035 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
|
4036 value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
|
4037 } |
|
4038 |
|
4039 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4040 if (currentFunction != null) { |
|
4041 // destructuring assignment |
|
4042 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value); |
|
4043 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
|
4044 } |
|
4045 } |
2925 parameters.add(ident); |
4046 parameters.add(ident); |
2926 } |
4047 } |
2927 |
4048 |
2928 parameters.trimToSize(); |
4049 parameters.trimToSize(); |
2929 return parameters; |
4050 return parameters; |
|
4051 } |
|
4052 |
|
4053 private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) { |
|
4054 verifyDestructuringBindingPattern(pattern, new Consumer<IdentNode>() { |
|
4055 public void accept(IdentNode identNode) { |
|
4056 verifyIdent(identNode, contextString); |
|
4057 |
|
4058 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4059 if (currentFunction != null) { |
|
4060 // declare function-scope variables for destructuring bindings |
|
4061 lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null)); |
|
4062 // detect duplicate bounds names in parameter list |
|
4063 currentFunction.addParameterBinding(identNode); |
|
4064 currentFunction.setSimpleParameterList(false); |
|
4065 } |
|
4066 } |
|
4067 }); |
2930 } |
4068 } |
2931 |
4069 |
2932 /** |
4070 /** |
2933 * FunctionBody : |
4071 * FunctionBody : |
2934 * SourceElements? |
4072 * SourceElements? |
3245 |
4370 |
3246 if (last != EOL) { |
4371 if (last != EOL) { |
3247 switch (type) { |
4372 switch (type) { |
3248 case INCPREFIX: |
4373 case INCPREFIX: |
3249 case DECPREFIX: |
4374 case DECPREFIX: |
|
4375 final long opToken = token; |
3250 final TokenType opType = type; |
4376 final TokenType opType = type; |
3251 final Expression lhs = expression; |
4377 final Expression lhs = expression; |
3252 // ++, -- without operand.. |
4378 // ++, -- without operand.. |
3253 if (lhs == null) { |
4379 if (lhs == null) { |
3254 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); |
4380 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); |
3255 } |
4381 } |
3256 |
|
3257 if (!(lhs instanceof AccessNode || |
|
3258 lhs instanceof IndexNode || |
|
3259 lhs instanceof IdentNode)) { |
|
3260 next(); |
|
3261 return referenceError(lhs, null, env._early_lvalue_error); |
|
3262 } |
|
3263 if (lhs instanceof IdentNode) { |
|
3264 if (!checkIdentLValue((IdentNode)lhs)) { |
|
3265 next(); |
|
3266 return referenceError(lhs, null, false); |
|
3267 } |
|
3268 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); |
|
3269 } |
|
3270 expression = incDecExpression(token, type, expression, true); |
|
3271 next(); |
4382 next(); |
3272 break; |
4383 |
|
4384 return verifyIncDecExpression(opToken, opType, lhs, true); |
3273 default: |
4385 default: |
3274 break; |
4386 break; |
3275 } |
4387 } |
3276 } |
4388 } |
3277 |
4389 |
3278 if (expression == null) { |
4390 if (expression == null) { |
3279 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); |
4391 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); |
3280 } |
4392 } |
3281 |
4393 |
3282 return expression; |
4394 return expression; |
|
4395 } |
|
4396 |
|
4397 private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) { |
|
4398 assert lhs != null; |
|
4399 |
|
4400 if (!(lhs instanceof AccessNode || |
|
4401 lhs instanceof IndexNode || |
|
4402 lhs instanceof IdentNode)) { |
|
4403 return referenceError(lhs, null, env._early_lvalue_error); |
|
4404 } |
|
4405 |
|
4406 if (lhs instanceof IdentNode) { |
|
4407 if (!checkIdentLValue((IdentNode)lhs)) { |
|
4408 return referenceError(lhs, null, false); |
|
4409 } |
|
4410 verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); |
|
4411 } |
|
4412 |
|
4413 return incDecExpression(unaryToken, opType, lhs, isPostfix); |
3283 } |
4414 } |
3284 |
4415 |
3285 /** |
4416 /** |
3286 * {@code |
4417 * {@code |
3287 * MultiplicativeExpression : |
4418 * MultiplicativeExpression : |
3446 } |
4612 } |
3447 |
4613 |
3448 return lhs; |
4614 return lhs; |
3449 } |
4615 } |
3450 |
4616 |
|
4617 /** |
|
4618 * AssignmentExpression. |
|
4619 * |
|
4620 * AssignmentExpression[In, Yield] : |
|
4621 * ConditionalExpression[?In, ?Yield] |
|
4622 * [+Yield] YieldExpression[?In] |
|
4623 * ArrowFunction[?In, ?Yield] |
|
4624 * LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield] |
|
4625 * LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield] |
|
4626 */ |
3451 protected Expression assignmentExpression(final boolean noIn) { |
4627 protected Expression assignmentExpression(final boolean noIn) { |
3452 // This method is protected so that subclass can get details |
4628 // This method is protected so that subclass can get details |
3453 // at assignment expression start point! |
4629 // at assignment expression start point! |
3454 |
4630 |
3455 // Exclude commas in expression parsing. |
4631 if (type == YIELD && inGeneratorFunction() && isES6()) { |
3456 return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); |
4632 return yieldExpression(noIn); |
|
4633 } |
|
4634 |
|
4635 final long startToken = token; |
|
4636 final int startLine = line; |
|
4637 final Expression exprLhs = conditionalExpression(noIn); |
|
4638 |
|
4639 if (type == ARROW && isES6()) { |
|
4640 if (checkNoLineTerminator()) { |
|
4641 final Expression paramListExpr; |
|
4642 if (exprLhs instanceof ExpressionList) { |
|
4643 paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0)); |
|
4644 } else { |
|
4645 paramListExpr = exprLhs; |
|
4646 } |
|
4647 return arrowFunction(startToken, startLine, paramListExpr); |
|
4648 } |
|
4649 } |
|
4650 assert !(exprLhs instanceof ExpressionList); |
|
4651 |
|
4652 if (isAssignmentOperator(type)) { |
|
4653 final boolean isAssign = type == ASSIGN; |
|
4654 if (isAssign) { |
|
4655 defaultNames.push(exprLhs); |
|
4656 } |
|
4657 try { |
|
4658 final long assignToken = token; |
|
4659 next(); |
|
4660 final Expression exprRhs = assignmentExpression(noIn); |
|
4661 return verifyAssignment(assignToken, exprLhs, exprRhs); |
|
4662 } finally { |
|
4663 if (isAssign) { |
|
4664 defaultNames.pop(); |
|
4665 } |
|
4666 } |
|
4667 } else { |
|
4668 return exprLhs; |
|
4669 } |
|
4670 } |
|
4671 |
|
4672 /** |
|
4673 * Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}? |
|
4674 */ |
|
4675 private static boolean isAssignmentOperator(TokenType type) { |
|
4676 switch (type) { |
|
4677 case ASSIGN: |
|
4678 case ASSIGN_ADD: |
|
4679 case ASSIGN_BIT_AND: |
|
4680 case ASSIGN_BIT_OR: |
|
4681 case ASSIGN_BIT_XOR: |
|
4682 case ASSIGN_DIV: |
|
4683 case ASSIGN_MOD: |
|
4684 case ASSIGN_MUL: |
|
4685 case ASSIGN_SAR: |
|
4686 case ASSIGN_SHL: |
|
4687 case ASSIGN_SHR: |
|
4688 case ASSIGN_SUB: |
|
4689 return true; |
|
4690 } |
|
4691 return false; |
|
4692 } |
|
4693 |
|
4694 /** |
|
4695 * ConditionalExpression. |
|
4696 */ |
|
4697 private Expression conditionalExpression(boolean noIn) { |
|
4698 return expression(TERNARY.getPrecedence(), noIn); |
|
4699 } |
|
4700 |
|
4701 /** |
|
4702 * ArrowFunction. |
|
4703 * |
|
4704 * @param startToken start token of the ArrowParameters expression |
|
4705 * @param functionLine start line of the arrow function |
|
4706 * @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list) |
|
4707 */ |
|
4708 private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) { |
|
4709 // caller needs to check that there's no LineTerminator between parameter list and arrow |
|
4710 assert type != ARROW || checkNoLineTerminator(); |
|
4711 expect(ARROW); |
|
4712 |
|
4713 final long functionToken = Token.recast(startToken, ARROW); |
|
4714 final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), "=>:" + functionLine); |
|
4715 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null); |
|
4716 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); |
|
4717 |
|
4718 lc.push(functionNode); |
|
4719 try { |
|
4720 ParserContextBlockNode parameterBlock = newBlock(); |
|
4721 final List<IdentNode> parameters; |
|
4722 try { |
|
4723 parameters = convertArrowFunctionParameterList(paramListExpr, functionLine); |
|
4724 functionNode.setParameters(parameters); |
|
4725 |
|
4726 if (!functionNode.isSimpleParameterList()) { |
|
4727 markEvalInArrowParameterList(parameterBlock); |
|
4728 } |
|
4729 } finally { |
|
4730 restoreBlock(parameterBlock); |
|
4731 } |
|
4732 Block functionBody = functionBody(functionNode); |
|
4733 |
|
4734 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); |
|
4735 |
|
4736 verifyParameterList(parameters, functionNode); |
|
4737 |
|
4738 final FunctionNode function = createFunctionNode( |
|
4739 functionNode, |
|
4740 functionToken, |
|
4741 name, |
|
4742 parameters, |
|
4743 FunctionNode.Kind.ARROW, |
|
4744 functionLine, |
|
4745 functionBody); |
|
4746 return function; |
|
4747 } finally { |
|
4748 lc.pop(functionNode); |
|
4749 } |
|
4750 } |
|
4751 |
|
4752 private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) { |
|
4753 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); |
|
4754 final ParserContextFunctionNode current = iter.next(); |
|
4755 final ParserContextFunctionNode parent = iter.next(); |
|
4756 |
|
4757 if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) { |
|
4758 // we might have flagged has-eval in the parent function during parsing the parameter list, |
|
4759 // if the parameter list contains eval; must tag arrow function as has-eval. |
|
4760 for (final Statement st : parameterBlock.getStatements()) { |
|
4761 st.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
|
4762 @Override |
|
4763 public boolean enterCallNode(final CallNode callNode) { |
|
4764 if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) { |
|
4765 current.setFlag(FunctionNode.HAS_EVAL); |
|
4766 } |
|
4767 return true; |
|
4768 } |
|
4769 }); |
|
4770 } |
|
4771 // TODO: function containing the arrow function should not be flagged has-eval |
|
4772 } |
|
4773 } |
|
4774 |
|
4775 private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) { |
|
4776 final List<IdentNode> parameters; |
|
4777 if (paramListExpr == null) { |
|
4778 // empty parameter list, i.e. () => |
|
4779 parameters = Collections.emptyList(); |
|
4780 } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) { |
|
4781 parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine)); |
|
4782 } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) { |
|
4783 parameters = new ArrayList<>(); |
|
4784 Expression car = paramListExpr; |
|
4785 do { |
|
4786 final Expression cdr = ((BinaryNode) car).rhs(); |
|
4787 parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine)); |
|
4788 car = ((BinaryNode) car).lhs(); |
|
4789 } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT); |
|
4790 parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine)); |
|
4791 } else { |
|
4792 throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken()); |
|
4793 } |
|
4794 return parameters; |
|
4795 } |
|
4796 |
|
4797 private IdentNode verifyArrowParameter(Expression param, int index, int paramLine) { |
|
4798 final String contextString = "function parameter"; |
|
4799 if (param instanceof IdentNode) { |
|
4800 IdentNode ident = (IdentNode)param; |
|
4801 verifyStrictIdent(ident, contextString); |
|
4802 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4803 if (currentFunction != null) { |
|
4804 currentFunction.addParameterBinding(ident); |
|
4805 } |
|
4806 return ident; |
|
4807 } |
|
4808 |
|
4809 if (param.isTokenType(ASSIGN)) { |
|
4810 Expression lhs = ((BinaryNode) param).lhs(); |
|
4811 long paramToken = lhs.getToken(); |
|
4812 Expression initializer = ((BinaryNode) param).rhs(); |
|
4813 if (lhs instanceof IdentNode) { |
|
4814 // default parameter |
|
4815 IdentNode ident = (IdentNode) lhs; |
|
4816 |
|
4817 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4818 if (currentFunction != null) { |
|
4819 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
|
4820 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
|
4821 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); |
|
4822 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
|
4823 |
|
4824 currentFunction.addParameterBinding(ident); |
|
4825 currentFunction.setSimpleParameterList(false); |
|
4826 } |
|
4827 return ident; |
|
4828 } else if (isDestructuringLhs(lhs)) { |
|
4829 // binding pattern with initializer |
|
4830 // Introduce synthetic temporary parameter to capture the object to be destructured. |
|
4831 IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter(); |
|
4832 verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); |
|
4833 |
|
4834 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4835 if (currentFunction != null) { |
|
4836 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); |
|
4837 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); |
|
4838 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value); |
|
4839 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
|
4840 } |
|
4841 return ident; |
|
4842 } |
|
4843 } else if (isDestructuringLhs(param)) { |
|
4844 // binding pattern |
|
4845 long paramToken = param.getToken(); |
|
4846 |
|
4847 // Introduce synthetic temporary parameter to capture the object to be destructured. |
|
4848 IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter(); |
|
4849 verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); |
|
4850 |
|
4851 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); |
|
4852 if (currentFunction != null) { |
|
4853 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident); |
|
4854 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); |
|
4855 } |
|
4856 return ident; |
|
4857 } |
|
4858 throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken()); |
|
4859 } |
|
4860 |
|
4861 private boolean checkNoLineTerminator() { |
|
4862 assert type == ARROW; |
|
4863 if (last == RPAREN) { |
|
4864 return true; |
|
4865 } else if (last == IDENT) { |
|
4866 return true; |
|
4867 } |
|
4868 for (int i = k - 1; i >= 0; i--) { |
|
4869 TokenType t = T(i); |
|
4870 switch (t) { |
|
4871 case RPAREN: |
|
4872 case IDENT: |
|
4873 return true; |
|
4874 case EOL: |
|
4875 return false; |
|
4876 case COMMENT: |
|
4877 continue; |
|
4878 default: |
|
4879 if (t.getKind() == TokenKind.FUTURESTRICT) { |
|
4880 return true; |
|
4881 } |
|
4882 return false; |
|
4883 } |
|
4884 } |
|
4885 return false; |
|
4886 } |
|
4887 |
|
4888 /** |
|
4889 * Peek ahead to see if what follows after the ellipsis is a rest parameter |
|
4890 * at the end of an arrow function parameter list. |
|
4891 */ |
|
4892 private boolean isRestParameterEndOfArrowFunctionParameterList() { |
|
4893 assert type == ELLIPSIS; |
|
4894 // find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT |
|
4895 int i = 1; |
|
4896 for (;;) { |
|
4897 TokenType t = T(k + i++); |
|
4898 if (t == IDENT) { |
|
4899 break; |
|
4900 } else if (t == EOL || t == COMMENT) { |
|
4901 continue; |
|
4902 } else { |
|
4903 return false; |
|
4904 } |
|
4905 } |
|
4906 for (;;) { |
|
4907 TokenType t = T(k + i++); |
|
4908 if (t == RPAREN) { |
|
4909 break; |
|
4910 } else if (t == EOL || t == COMMENT) { |
|
4911 continue; |
|
4912 } else { |
|
4913 return false; |
|
4914 } |
|
4915 } |
|
4916 for (;;) { |
|
4917 TokenType t = T(k + i++); |
|
4918 if (t == ARROW) { |
|
4919 break; |
|
4920 } else if (t == COMMENT) { |
|
4921 continue; |
|
4922 } else { |
|
4923 return false; |
|
4924 } |
|
4925 } |
|
4926 return true; |
3457 } |
4927 } |
3458 |
4928 |
3459 /** |
4929 /** |
3460 * Parse an end of line. |
4930 * Parse an end of line. |
3461 */ |
4931 */ |
3549 next(); |
5019 next(); |
3550 rawStrings.add(LiteralNode.newInstance(stringToken, finish, rawString)); |
5020 rawStrings.add(LiteralNode.newInstance(stringToken, finish, rawString)); |
3551 cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString)); |
5021 cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString)); |
3552 } |
5022 } |
3553 |
5023 |
|
5024 |
|
5025 /** |
|
5026 * Parse a module. |
|
5027 * |
|
5028 * Module : |
|
5029 * ModuleBody? |
|
5030 * |
|
5031 * ModuleBody : |
|
5032 * ModuleItemList |
|
5033 */ |
|
5034 private FunctionNode module(final String moduleName) { |
|
5035 boolean oldStrictMode = isStrictMode; |
|
5036 try { |
|
5037 isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1) |
|
5038 |
|
5039 // Make a pseudo-token for the script holding its start and length. |
|
5040 int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish); |
|
5041 final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart); |
|
5042 final int functionLine = line; |
|
5043 |
|
5044 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName); |
|
5045 final ParserContextFunctionNode script = createParserContextFunctionNode( |
|
5046 ident, |
|
5047 functionToken, |
|
5048 FunctionNode.Kind.MODULE, |
|
5049 functionLine, |
|
5050 Collections.<IdentNode>emptyList()); |
|
5051 lc.push(script); |
|
5052 |
|
5053 final ParserContextModuleNode module = new ParserContextModuleNode(moduleName); |
|
5054 lc.push(module); |
|
5055 |
|
5056 final ParserContextBlockNode body = newBlock(); |
|
5057 |
|
5058 functionDeclarations = new ArrayList<>(); |
|
5059 moduleBody(); |
|
5060 addFunctionDeclarations(script); |
|
5061 functionDeclarations = null; |
|
5062 |
|
5063 restoreBlock(body); |
|
5064 body.setFlag(Block.NEEDS_SCOPE); |
|
5065 final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements()); |
|
5066 lc.pop(module); |
|
5067 lc.pop(script); |
|
5068 script.setLastToken(token); |
|
5069 |
|
5070 expect(EOF); |
|
5071 |
|
5072 script.setModule(module.createModule()); |
|
5073 return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody); |
|
5074 } finally { |
|
5075 isStrictMode = oldStrictMode; |
|
5076 } |
|
5077 } |
|
5078 |
|
5079 /** |
|
5080 * Parse module body. |
|
5081 * |
|
5082 * ModuleBody : |
|
5083 * ModuleItemList |
|
5084 * |
|
5085 * ModuleItemList : |
|
5086 * ModuleItem |
|
5087 * ModuleItemList ModuleItem |
|
5088 * |
|
5089 * ModuleItem : |
|
5090 * ImportDeclaration |
|
5091 * ExportDeclaration |
|
5092 * StatementListItem |
|
5093 */ |
|
5094 private void moduleBody() { |
|
5095 loop: |
|
5096 while (type != EOF) { |
|
5097 switch (type) { |
|
5098 case EOF: |
|
5099 break loop; |
|
5100 case IMPORT: |
|
5101 importDeclaration(); |
|
5102 break; |
|
5103 case EXPORT: |
|
5104 exportDeclaration(); |
|
5105 break; |
|
5106 default: |
|
5107 // StatementListItem |
|
5108 statement(true, false, false, false); |
|
5109 break; |
|
5110 } |
|
5111 } |
|
5112 } |
|
5113 |
|
5114 |
|
5115 /** |
|
5116 * Parse import declaration. |
|
5117 * |
|
5118 * ImportDeclaration : |
|
5119 * import ImportClause FromClause ; |
|
5120 * import ModuleSpecifier ; |
|
5121 * ImportClause : |
|
5122 * ImportedDefaultBinding |
|
5123 * NameSpaceImport |
|
5124 * NamedImports |
|
5125 * ImportedDefaultBinding , NameSpaceImport |
|
5126 * ImportedDefaultBinding , NamedImports |
|
5127 * ImportedDefaultBinding : |
|
5128 * ImportedBinding |
|
5129 * ModuleSpecifier : |
|
5130 * StringLiteral |
|
5131 * ImportedBinding : |
|
5132 * BindingIdentifier |
|
5133 */ |
|
5134 private void importDeclaration() { |
|
5135 expect(IMPORT); |
|
5136 final ParserContextModuleNode module = lc.getCurrentModule(); |
|
5137 if (type == STRING || type == ESCSTRING) { |
|
5138 // import ModuleSpecifier ; |
|
5139 final String moduleSpecifier = (String) getValue(); |
|
5140 next(); |
|
5141 module.addModuleRequest(moduleSpecifier); |
|
5142 } else { |
|
5143 // import ImportClause FromClause ; |
|
5144 List<Module.ImportEntry> importEntries; |
|
5145 if (type == MUL) { |
|
5146 importEntries = Collections.singletonList(nameSpaceImport()); |
|
5147 } else if (type == LBRACE) { |
|
5148 importEntries = namedImports(); |
|
5149 } else if (isBindingIdentifier()) { |
|
5150 // ImportedDefaultBinding |
|
5151 final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding"); |
|
5152 Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName()); |
|
5153 |
|
5154 if (type == COMMARIGHT) { |
|
5155 next(); |
|
5156 importEntries = new ArrayList<>(); |
|
5157 if (type == MUL) { |
|
5158 importEntries.add(nameSpaceImport()); |
|
5159 } else if (type == LBRACE) { |
|
5160 importEntries.addAll(namedImports()); |
|
5161 } else { |
|
5162 throw error(AbstractParser.message("expected.named.import")); |
|
5163 } |
|
5164 } else { |
|
5165 importEntries = Collections.singletonList(defaultImport); |
|
5166 } |
|
5167 } else { |
|
5168 throw error(AbstractParser.message("expected.import")); |
|
5169 } |
|
5170 |
|
5171 final String moduleSpecifier = fromClause(); |
|
5172 module.addModuleRequest(moduleSpecifier); |
|
5173 for (int i = 0; i < importEntries.size(); i++) { |
|
5174 module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier)); |
|
5175 } |
|
5176 } |
|
5177 expect(SEMICOLON); |
|
5178 } |
|
5179 |
|
5180 /** |
|
5181 * NameSpaceImport : |
|
5182 * * as ImportedBinding |
|
5183 * |
|
5184 * @return imported binding identifier |
|
5185 */ |
|
5186 private Module.ImportEntry nameSpaceImport() { |
|
5187 assert type == MUL; |
|
5188 next(); |
|
5189 final long asToken = token; |
|
5190 final String as = (String) expectValue(IDENT); |
|
5191 if (!"as".equals(as)) { |
|
5192 throw error(AbstractParser.message("expected.as"), asToken); |
|
5193 } |
|
5194 final IdentNode localNameSpace = bindingIdentifier("ImportedBinding"); |
|
5195 return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName()); |
|
5196 } |
|
5197 |
|
5198 /** |
|
5199 * NamedImports : |
|
5200 * { } |
|
5201 * { ImportsList } |
|
5202 * { ImportsList , } |
|
5203 * ImportsList : |
|
5204 * ImportSpecifier |
|
5205 * ImportsList , ImportSpecifier |
|
5206 * ImportSpecifier : |
|
5207 * ImportedBinding |
|
5208 * IdentifierName as ImportedBinding |
|
5209 * ImportedBinding : |
|
5210 * BindingIdentifier |
|
5211 */ |
|
5212 private List<Module.ImportEntry> namedImports() { |
|
5213 assert type == LBRACE; |
|
5214 next(); |
|
5215 List<Module.ImportEntry> importEntries = new ArrayList<>(); |
|
5216 while (type != RBRACE) { |
|
5217 final boolean bindingIdentifier = isBindingIdentifier(); |
|
5218 final long nameToken = token; |
|
5219 final IdentNode importName = getIdentifierName(); |
|
5220 if (type == IDENT && "as".equals(getValue())) { |
|
5221 next(); |
|
5222 final IdentNode localName = bindingIdentifier("ImportedBinding"); |
|
5223 importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName())); |
|
5224 } else if (!bindingIdentifier) { |
|
5225 throw error(AbstractParser.message("expected.binding.identifier"), nameToken); |
|
5226 } else { |
|
5227 importEntries.add(Module.ImportEntry.importSpecifier(importName.getName())); |
|
5228 } |
|
5229 if (type == COMMARIGHT) { |
|
5230 next(); |
|
5231 } else { |
|
5232 break; |
|
5233 } |
|
5234 } |
|
5235 expect(RBRACE); |
|
5236 return importEntries; |
|
5237 } |
|
5238 |
|
5239 /** |
|
5240 * FromClause : |
|
5241 * from ModuleSpecifier |
|
5242 */ |
|
5243 private String fromClause() { |
|
5244 final long fromToken = token; |
|
5245 final String name = (String) expectValue(IDENT); |
|
5246 if (!"from".equals(name)) { |
|
5247 throw error(AbstractParser.message("expected.from"), fromToken); |
|
5248 } |
|
5249 if (type == STRING || type == ESCSTRING) { |
|
5250 final String moduleSpecifier = (String) getValue(); |
|
5251 next(); |
|
5252 return moduleSpecifier; |
|
5253 } else { |
|
5254 throw error(expectMessage(STRING)); |
|
5255 } |
|
5256 } |
|
5257 |
|
5258 /** |
|
5259 * Parse export declaration. |
|
5260 * |
|
5261 * ExportDeclaration : |
|
5262 * export * FromClause ; |
|
5263 * export ExportClause FromClause ; |
|
5264 * export ExportClause ; |
|
5265 * export VariableStatement |
|
5266 * export Declaration |
|
5267 * export default HoistableDeclaration[Default] |
|
5268 * export default ClassDeclaration[Default] |
|
5269 * export default [lookahead !in {function, class}] AssignmentExpression[In] ; |
|
5270 */ |
|
5271 private void exportDeclaration() { |
|
5272 expect(EXPORT); |
|
5273 final ParserContextModuleNode module = lc.getCurrentModule(); |
|
5274 switch (type) { |
|
5275 case MUL: { |
|
5276 next(); |
|
5277 final String moduleRequest = fromClause(); |
|
5278 expect(SEMICOLON); |
|
5279 module.addModuleRequest(moduleRequest); |
|
5280 module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest)); |
|
5281 break; |
|
5282 } |
|
5283 case LBRACE: { |
|
5284 final List<Module.ExportEntry> exportEntries = exportClause(); |
|
5285 if (type == IDENT && "from".equals(getValue())) { |
|
5286 final String moduleRequest = fromClause(); |
|
5287 module.addModuleRequest(moduleRequest); |
|
5288 for (Module.ExportEntry exportEntry : exportEntries) { |
|
5289 module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest)); |
|
5290 } |
|
5291 } else { |
|
5292 for (Module.ExportEntry exportEntry : exportEntries) { |
|
5293 module.addLocalExportEntry(exportEntry); |
|
5294 } |
|
5295 } |
|
5296 expect(SEMICOLON); |
|
5297 break; |
|
5298 } |
|
5299 case DEFAULT: |
|
5300 next(); |
|
5301 final Expression assignmentExpression; |
|
5302 IdentNode ident; |
|
5303 final int lineNumber = line; |
|
5304 final long rhsToken = token; |
|
5305 final boolean declaration; |
|
5306 switch (type) { |
|
5307 case FUNCTION: |
|
5308 assignmentExpression = functionExpression(false, true); |
|
5309 ident = ((FunctionNode) assignmentExpression).getIdent(); |
|
5310 declaration = true; |
|
5311 break; |
|
5312 case CLASS: |
|
5313 assignmentExpression = classDeclaration(true); |
|
5314 ident = ((ClassNode) assignmentExpression).getIdent(); |
|
5315 declaration = true; |
|
5316 break; |
|
5317 default: |
|
5318 assignmentExpression = assignmentExpression(false); |
|
5319 ident = null; |
|
5320 declaration = false; |
|
5321 break; |
|
5322 } |
|
5323 if (ident != null) { |
|
5324 module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName())); |
|
5325 } else { |
|
5326 ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME); |
|
5327 lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression)); |
|
5328 if (!declaration) { |
|
5329 expect(SEMICOLON); |
|
5330 } |
|
5331 module.addLocalExportEntry(Module.ExportEntry.exportDefault()); |
|
5332 } |
|
5333 break; |
|
5334 case VAR: |
|
5335 case LET: |
|
5336 case CONST: |
|
5337 final List<Statement> statements = lc.getCurrentBlock().getStatements(); |
|
5338 final int previousEnd = statements.size(); |
|
5339 variableStatement(type); |
|
5340 for (final Statement statement : statements.subList(previousEnd, statements.size())) { |
|
5341 if (statement instanceof VarNode) { |
|
5342 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName())); |
|
5343 } |
|
5344 } |
|
5345 break; |
|
5346 case CLASS: { |
|
5347 final ClassNode classDeclaration = classDeclaration(false); |
|
5348 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName())); |
|
5349 break; |
|
5350 } |
|
5351 case FUNCTION: { |
|
5352 final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true); |
|
5353 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName())); |
|
5354 break; |
|
5355 } |
|
5356 default: |
|
5357 throw error(AbstractParser.message("invalid.export"), token); |
|
5358 } |
|
5359 } |
|
5360 |
|
5361 /** |
|
5362 * ExportClause : |
|
5363 * { } |
|
5364 * { ExportsList } |
|
5365 * { ExportsList , } |
|
5366 * ExportsList : |
|
5367 * ExportSpecifier |
|
5368 * ExportsList , ExportSpecifier |
|
5369 * ExportSpecifier : |
|
5370 * IdentifierName |
|
5371 * IdentifierName as IdentifierName |
|
5372 * |
|
5373 * @return a list of ExportSpecifiers |
|
5374 */ |
|
5375 private List<Module.ExportEntry> exportClause() { |
|
5376 assert type == LBRACE; |
|
5377 next(); |
|
5378 List<Module.ExportEntry> exports = new ArrayList<>(); |
|
5379 while (type != RBRACE) { |
|
5380 final IdentNode localName = getIdentifierName(); |
|
5381 if (type == IDENT && "as".equals(getValue())) { |
|
5382 next(); |
|
5383 final IdentNode exportName = getIdentifierName(); |
|
5384 exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName())); |
|
5385 } else { |
|
5386 exports.add(Module.ExportEntry.exportSpecifier(localName.getName())); |
|
5387 } |
|
5388 if (type == COMMARIGHT) { |
|
5389 next(); |
|
5390 } else { |
|
5391 break; |
|
5392 } |
|
5393 } |
|
5394 expect(RBRACE); |
|
5395 return exports; |
|
5396 } |
|
5397 |
3554 @Override |
5398 @Override |
3555 public String toString() { |
5399 public String toString() { |
3556 return "'JavaScript Parsing'"; |
5400 return "'JavaScript Parsing'"; |
3557 } |
5401 } |
3558 |
5402 |