Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/parsing/parser.h" | 5 #include "src/parsing/parser.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "src/api.h" | 9 #include "src/api.h" |
| 10 #include "src/ast/ast-expression-rewriter.h" | 10 #include "src/ast/ast-expression-rewriter.h" |
| (...skipping 1651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1662 | 1662 |
| 1663 void Parser::DeclareAndInitializeVariables( | 1663 void Parser::DeclareAndInitializeVariables( |
| 1664 Block* block, const DeclarationDescriptor* declaration_descriptor, | 1664 Block* block, const DeclarationDescriptor* declaration_descriptor, |
| 1665 const DeclarationParsingResult::Declaration* declaration, | 1665 const DeclarationParsingResult::Declaration* declaration, |
| 1666 ZoneList<const AstRawString*>* names, bool* ok) { | 1666 ZoneList<const AstRawString*>* names, bool* ok) { |
| 1667 DCHECK_NOT_NULL(block); | 1667 DCHECK_NOT_NULL(block); |
| 1668 PatternRewriter::DeclareAndInitializeVariables( | 1668 PatternRewriter::DeclareAndInitializeVariables( |
| 1669 this, block, declaration_descriptor, declaration, names, ok); | 1669 this, block, declaration_descriptor, declaration, names, ok); |
| 1670 } | 1670 } |
| 1671 | 1671 |
| 1672 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, | 1672 ZoneList<const AstRawString*>* Parser::DeclareLabel( |
| 1673 const AstRawString* label) { | 1673 ZoneList<const AstRawString*>* labels, Expression* expr, bool* ok) { |
| 1674 DCHECK(label != NULL); | 1674 VariableProxy* var = expr->AsVariableProxy(); |
| 1675 if (labels != NULL) { | 1675 const AstRawString* label = var->raw_name(); |
| 1676 for (int i = labels->length(); i-- > 0; ) { | 1676 // TODO(1240780): We don't check for redeclaration of labels |
| 1677 if (labels->at(i) == label) { | 1677 // during preparsing since keeping track of the set of active |
| 1678 return true; | 1678 // labels requires nontrivial changes to the way scopes are |
| 1679 } | 1679 // structured. However, these are probably changes we want to |
| 1680 // make later anyway so we should go back and fix this then. | |
| 1681 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) { | |
| 1682 ReportMessage(MessageTemplate::kLabelRedeclaration, label); | |
| 1683 *ok = false; | |
| 1684 return nullptr; | |
| 1685 } | |
| 1686 if (labels == nullptr) { | |
| 1687 labels = new (zone()) ZoneList<const AstRawString*>(1, zone()); | |
| 1688 } | |
| 1689 labels->Add(label, zone()); | |
| 1690 // Remove the "ghost" variable that turned out to be a label | |
| 1691 // from the top scope. This way, we don't try to resolve it | |
| 1692 // during the scope processing. | |
| 1693 scope()->RemoveUnresolved(var); | |
| 1694 return labels; | |
| 1695 } | |
| 1696 | |
| 1697 bool Parser::ContainsLabel(ZoneList<const AstRawString*>* labels, | |
| 1698 const AstRawString* label) { | |
| 1699 DCHECK_NOT_NULL(label); | |
| 1700 if (labels != nullptr) { | |
| 1701 for (int i = labels->length(); i-- > 0;) { | |
| 1702 if (labels->at(i) == label) return true; | |
| 1680 } | 1703 } |
| 1681 } | 1704 } |
| 1682 return false; | 1705 return false; |
| 1683 } | 1706 } |
| 1684 | 1707 |
| 1708 Expression* Parser::RewriteReturn(Expression* return_value, int pos) { | |
| 1709 if (IsSubclassConstructor(function_state_->kind())) { | |
| 1710 // For subclass constructors we need to return this in case of undefined | |
| 1711 // return a Smi (transformed into an exception in the ConstructStub) | |
| 1712 // for a non object. | |
| 1713 // | |
| 1714 // return expr; | |
| 1715 // | |
| 1716 // Is rewritten as: | |
| 1717 // | |
| 1718 // return (temp = expr) === undefined ? this : | |
| 1719 // %_IsJSReceiver(temp) ? temp : 1; | |
| 1720 | |
| 1721 // temp = expr | |
| 1722 Variable* temp = NewTemporary(ast_value_factory()->empty_string()); | |
| 1723 Assignment* assign = factory()->NewAssignment( | |
| 1724 Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos); | |
| 1725 | |
| 1726 // %_IsJSReceiver(temp) | |
| 1727 ZoneList<Expression*>* is_spec_object_args = | |
| 1728 new (zone()) ZoneList<Expression*>(1, zone()); | |
| 1729 is_spec_object_args->Add(factory()->NewVariableProxy(temp), zone()); | |
| 1730 Expression* is_spec_object_call = factory()->NewCallRuntime( | |
| 1731 Runtime::kInlineIsJSReceiver, is_spec_object_args, pos); | |
| 1732 | |
| 1733 // %_IsJSReceiver(temp) ? temp : 1; | |
| 1734 Expression* is_object_conditional = factory()->NewConditional( | |
| 1735 is_spec_object_call, factory()->NewVariableProxy(temp), | |
| 1736 factory()->NewSmiLiteral(1, pos), pos); | |
| 1737 | |
| 1738 // temp === undefined | |
| 1739 Expression* is_undefined = factory()->NewCompareOperation( | |
| 1740 Token::EQ_STRICT, assign, | |
| 1741 factory()->NewUndefinedLiteral(kNoSourcePosition), pos); | |
| 1742 | |
| 1743 // is_undefined ? this : is_object_conditional | |
| 1744 return_value = factory()->NewConditional(is_undefined, ThisExpression(pos), | |
| 1745 is_object_conditional, pos); | |
| 1746 } | |
| 1747 if (is_generator()) { | |
| 1748 return_value = impl()->BuildIteratorResult(return_value, true); | |
|
marja
2016/09/09 08:44:59
Why impl() here?
nickie
2016/09/09 09:42:26
Right, my bad. I tried to keep this in parser bas
| |
| 1749 } else if (is_async_function()) { | |
| 1750 return_value = | |
| 1751 impl()->BuildResolvePromise(return_value, return_value->position()); | |
|
marja
2016/09/09 08:44:59
Ditto
nickie
2016/09/09 09:42:26
Done.
| |
| 1752 } | |
| 1753 return return_value; | |
| 1754 } | |
| 1755 | |
| 1685 Statement* Parser::ParseFunctionDeclaration(bool* ok) { | 1756 Statement* Parser::ParseFunctionDeclaration(bool* ok) { |
| 1686 Consume(Token::FUNCTION); | 1757 Consume(Token::FUNCTION); |
| 1687 int pos = position(); | 1758 int pos = position(); |
| 1688 ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal; | 1759 ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal; |
| 1689 if (Check(Token::MUL)) { | 1760 if (Check(Token::MUL)) { |
| 1690 flags |= ParseFunctionFlags::kIsGenerator; | 1761 flags |= ParseFunctionFlags::kIsGenerator; |
| 1691 if (allow_harmony_restrictive_declarations()) { | 1762 if (allow_harmony_restrictive_declarations()) { |
| 1692 ReportMessageAt(scanner()->location(), | 1763 ReportMessageAt(scanner()->location(), |
| 1693 MessageTemplate::kGeneratorInLegacyContext); | 1764 MessageTemplate::kGeneratorInLegacyContext); |
| 1694 *ok = false; | 1765 *ok = false; |
| 1695 return nullptr; | 1766 return nullptr; |
| 1696 } | 1767 } |
| 1697 } | 1768 } |
| 1698 | 1769 |
| 1699 return ParseHoistableDeclaration(pos, flags, nullptr, false, CHECK_OK); | 1770 return ParseHoistableDeclaration(pos, flags, nullptr, false, CHECK_OK); |
| 1700 } | 1771 } |
| 1701 | 1772 |
| 1702 Statement* Parser::ParseExpressionOrLabelledStatement( | |
| 1703 ZoneList<const AstRawString*>* labels, | |
| 1704 AllowLabelledFunctionStatement allow_function, bool* ok) { | |
| 1705 // ExpressionStatement | LabelledStatement :: | |
| 1706 // Expression ';' | |
| 1707 // Identifier ':' Statement | |
| 1708 // | |
| 1709 // ExpressionStatement[Yield] : | |
| 1710 // [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ; | |
| 1711 | |
| 1712 int pos = peek_position(); | |
| 1713 | |
| 1714 switch (peek()) { | |
| 1715 case Token::FUNCTION: | |
| 1716 case Token::LBRACE: | |
| 1717 UNREACHABLE(); // Always handled by the callers. | |
| 1718 case Token::CLASS: | |
| 1719 ReportUnexpectedToken(Next()); | |
| 1720 *ok = false; | |
| 1721 return nullptr; | |
| 1722 default: | |
| 1723 break; | |
| 1724 } | |
| 1725 | |
| 1726 bool starts_with_idenfifier = peek_any_identifier(); | |
| 1727 Expression* expr = ParseExpression(true, CHECK_OK); | |
| 1728 if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL && | |
| 1729 expr->AsVariableProxy() != NULL && | |
| 1730 !expr->AsVariableProxy()->is_this()) { | |
| 1731 // Expression is a single identifier, and not, e.g., a parenthesized | |
| 1732 // identifier. | |
| 1733 VariableProxy* var = expr->AsVariableProxy(); | |
| 1734 const AstRawString* label = var->raw_name(); | |
| 1735 // TODO(1240780): We don't check for redeclaration of labels | |
| 1736 // during preparsing since keeping track of the set of active | |
| 1737 // labels requires nontrivial changes to the way scopes are | |
| 1738 // structured. However, these are probably changes we want to | |
| 1739 // make later anyway so we should go back and fix this then. | |
| 1740 if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) { | |
| 1741 ReportMessage(MessageTemplate::kLabelRedeclaration, label); | |
| 1742 *ok = false; | |
| 1743 return NULL; | |
| 1744 } | |
| 1745 if (labels == NULL) { | |
| 1746 labels = new(zone()) ZoneList<const AstRawString*>(4, zone()); | |
| 1747 } | |
| 1748 labels->Add(label, zone()); | |
| 1749 // Remove the "ghost" variable that turned out to be a label | |
| 1750 // from the top scope. This way, we don't try to resolve it | |
| 1751 // during the scope processing. | |
| 1752 scope()->RemoveUnresolved(var); | |
| 1753 Expect(Token::COLON, CHECK_OK); | |
| 1754 // ES#sec-labelled-function-declarations Labelled Function Declarations | |
| 1755 if (peek() == Token::FUNCTION && is_sloppy(language_mode())) { | |
| 1756 if (allow_function == kAllowLabelledFunctionStatement) { | |
| 1757 return ParseFunctionDeclaration(ok); | |
| 1758 } else { | |
| 1759 return ParseScopedStatement(labels, true, ok); | |
| 1760 } | |
| 1761 } | |
| 1762 return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok); | |
| 1763 } | |
| 1764 | |
| 1765 // If we have an extension, we allow a native function declaration. | |
| 1766 // A native function declaration starts with "native function" with | |
| 1767 // no line-terminator between the two words. | |
| 1768 if (extension_ != NULL && peek() == Token::FUNCTION && | |
| 1769 !scanner()->HasAnyLineTerminatorBeforeNext() && expr != NULL && | |
| 1770 expr->AsVariableProxy() != NULL && | |
| 1771 expr->AsVariableProxy()->raw_name() == | |
| 1772 ast_value_factory()->native_string() && | |
| 1773 !scanner()->literal_contains_escapes()) { | |
| 1774 return ParseNativeDeclaration(ok); | |
| 1775 } | |
| 1776 | |
| 1777 // Parsed expression statement, followed by semicolon. | |
| 1778 ExpectSemicolon(CHECK_OK); | |
| 1779 return factory()->NewExpressionStatement(expr, pos); | |
| 1780 } | |
| 1781 | |
| 1782 | |
| 1783 IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels, | |
| 1784 bool* ok) { | |
| 1785 // IfStatement :: | |
| 1786 // 'if' '(' Expression ')' Statement ('else' Statement)? | |
| 1787 | |
| 1788 int pos = peek_position(); | |
| 1789 Expect(Token::IF, CHECK_OK); | |
| 1790 Expect(Token::LPAREN, CHECK_OK); | |
| 1791 Expression* condition = ParseExpression(true, CHECK_OK); | |
| 1792 Expect(Token::RPAREN, CHECK_OK); | |
| 1793 Statement* then_statement = ParseScopedStatement(labels, false, CHECK_OK); | |
| 1794 Statement* else_statement = NULL; | |
| 1795 if (peek() == Token::ELSE) { | |
| 1796 Next(); | |
| 1797 else_statement = ParseScopedStatement(labels, false, CHECK_OK); | |
| 1798 } else { | |
| 1799 else_statement = factory()->NewEmptyStatement(kNoSourcePosition); | |
| 1800 } | |
| 1801 return factory()->NewIfStatement( | |
| 1802 condition, then_statement, else_statement, pos); | |
| 1803 } | |
| 1804 | |
| 1805 | |
| 1806 Statement* Parser::ParseContinueStatement(bool* ok) { | |
| 1807 // ContinueStatement :: | |
| 1808 // 'continue' Identifier? ';' | |
| 1809 | |
| 1810 int pos = peek_position(); | |
| 1811 Expect(Token::CONTINUE, CHECK_OK); | |
| 1812 const AstRawString* label = NULL; | |
| 1813 Token::Value tok = peek(); | |
| 1814 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
| 1815 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { | |
| 1816 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
| 1817 label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 1818 } | |
| 1819 IterationStatement* target = LookupContinueTarget(label, CHECK_OK); | |
| 1820 if (target == NULL) { | |
| 1821 // Illegal continue statement. | |
| 1822 MessageTemplate::Template message = MessageTemplate::kIllegalContinue; | |
| 1823 if (label != NULL) { | |
| 1824 message = MessageTemplate::kUnknownLabel; | |
| 1825 } | |
| 1826 ReportMessage(message, label); | |
| 1827 *ok = false; | |
| 1828 return NULL; | |
| 1829 } | |
| 1830 ExpectSemicolon(CHECK_OK); | |
| 1831 return factory()->NewContinueStatement(target, pos); | |
| 1832 } | |
| 1833 | |
| 1834 | |
| 1835 Statement* Parser::ParseBreakStatement(ZoneList<const AstRawString*>* labels, | |
| 1836 bool* ok) { | |
| 1837 // BreakStatement :: | |
| 1838 // 'break' Identifier? ';' | |
| 1839 | |
| 1840 int pos = peek_position(); | |
| 1841 Expect(Token::BREAK, CHECK_OK); | |
| 1842 const AstRawString* label = NULL; | |
| 1843 Token::Value tok = peek(); | |
| 1844 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
| 1845 tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { | |
| 1846 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
| 1847 label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
| 1848 } | |
| 1849 // Parse labeled break statements that target themselves into | |
| 1850 // empty statements, e.g. 'l1: l2: l3: break l2;' | |
| 1851 if (label != NULL && ContainsLabel(labels, label)) { | |
| 1852 ExpectSemicolon(CHECK_OK); | |
| 1853 return factory()->NewEmptyStatement(pos); | |
| 1854 } | |
| 1855 BreakableStatement* target = NULL; | |
| 1856 target = LookupBreakTarget(label, CHECK_OK); | |
| 1857 if (target == NULL) { | |
| 1858 // Illegal break statement. | |
| 1859 MessageTemplate::Template message = MessageTemplate::kIllegalBreak; | |
| 1860 if (label != NULL) { | |
| 1861 message = MessageTemplate::kUnknownLabel; | |
| 1862 } | |
| 1863 ReportMessage(message, label); | |
| 1864 *ok = false; | |
| 1865 return NULL; | |
| 1866 } | |
| 1867 ExpectSemicolon(CHECK_OK); | |
| 1868 return factory()->NewBreakStatement(target, pos); | |
| 1869 } | |
| 1870 | |
| 1871 | |
| 1872 Statement* Parser::ParseReturnStatement(bool* ok) { | |
| 1873 // ReturnStatement :: | |
| 1874 // 'return' Expression? ';' | |
| 1875 | |
| 1876 // Consume the return token. It is necessary to do that before | |
| 1877 // reporting any errors on it, because of the way errors are | |
| 1878 // reported (underlining). | |
| 1879 Expect(Token::RETURN, CHECK_OK); | |
| 1880 Scanner::Location loc = scanner()->location(); | |
| 1881 | |
| 1882 Token::Value tok = peek(); | |
| 1883 Statement* result; | |
| 1884 Expression* return_value; | |
| 1885 if (scanner()->HasAnyLineTerminatorBeforeNext() || | |
| 1886 tok == Token::SEMICOLON || | |
| 1887 tok == Token::RBRACE || | |
| 1888 tok == Token::EOS) { | |
| 1889 if (IsSubclassConstructor(function_state_->kind())) { | |
| 1890 return_value = ThisExpression(loc.beg_pos); | |
| 1891 } else { | |
| 1892 return_value = GetLiteralUndefined(position()); | |
| 1893 } | |
| 1894 } else { | |
| 1895 int pos = peek_position(); | |
| 1896 | |
| 1897 if (IsSubclassConstructor(function_state_->kind())) { | |
| 1898 // Because of the return code rewriting that happens in case of a subclass | |
| 1899 // constructor we don't want to accept tail calls, therefore we don't set | |
| 1900 // ReturnExprScope to kInsideValidReturnStatement here. | |
| 1901 return_value = ParseExpression(true, CHECK_OK); | |
| 1902 | |
| 1903 // For subclass constructors we need to return this in case of undefined | |
| 1904 // return a Smi (transformed into an exception in the ConstructStub) | |
| 1905 // for a non object. | |
| 1906 // | |
| 1907 // return expr; | |
| 1908 // | |
| 1909 // Is rewritten as: | |
| 1910 // | |
| 1911 // return (temp = expr) === undefined ? this : | |
| 1912 // %_IsJSReceiver(temp) ? temp : 1; | |
| 1913 | |
| 1914 // temp = expr | |
| 1915 Variable* temp = NewTemporary(ast_value_factory()->empty_string()); | |
| 1916 Assignment* assign = factory()->NewAssignment( | |
| 1917 Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos); | |
| 1918 | |
| 1919 // %_IsJSReceiver(temp) | |
| 1920 ZoneList<Expression*>* is_spec_object_args = | |
| 1921 new (zone()) ZoneList<Expression*>(1, zone()); | |
| 1922 is_spec_object_args->Add(factory()->NewVariableProxy(temp), zone()); | |
| 1923 Expression* is_spec_object_call = factory()->NewCallRuntime( | |
| 1924 Runtime::kInlineIsJSReceiver, is_spec_object_args, pos); | |
| 1925 | |
| 1926 // %_IsJSReceiver(temp) ? temp : 1; | |
| 1927 Expression* is_object_conditional = factory()->NewConditional( | |
| 1928 is_spec_object_call, factory()->NewVariableProxy(temp), | |
| 1929 factory()->NewSmiLiteral(1, pos), pos); | |
| 1930 | |
| 1931 // temp === undefined | |
| 1932 Expression* is_undefined = factory()->NewCompareOperation( | |
| 1933 Token::EQ_STRICT, assign, | |
| 1934 factory()->NewUndefinedLiteral(kNoSourcePosition), pos); | |
| 1935 | |
| 1936 // is_undefined ? this : is_object_conditional | |
| 1937 return_value = factory()->NewConditional( | |
| 1938 is_undefined, ThisExpression(pos), is_object_conditional, pos); | |
| 1939 } else { | |
| 1940 ReturnExprScope maybe_allow_tail_calls( | |
| 1941 function_state_, ReturnExprContext::kInsideValidReturnStatement); | |
| 1942 return_value = ParseExpression(true, CHECK_OK); | |
| 1943 | |
| 1944 if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) { | |
| 1945 // ES6 14.6.1 Static Semantics: IsInTailPosition | |
| 1946 function_state_->AddImplicitTailCallExpression(return_value); | |
| 1947 } | |
| 1948 } | |
| 1949 } | |
| 1950 ExpectSemicolon(CHECK_OK); | |
| 1951 | |
| 1952 if (is_generator()) { | |
| 1953 return_value = BuildIteratorResult(return_value, true); | |
| 1954 } else if (is_async_function()) { | |
| 1955 return_value = BuildResolvePromise(return_value, return_value->position()); | |
| 1956 } | |
| 1957 | |
| 1958 result = factory()->NewReturnStatement(return_value, loc.beg_pos); | |
| 1959 | |
| 1960 DeclarationScope* decl_scope = GetDeclarationScope(); | |
| 1961 if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) { | |
| 1962 ReportMessageAt(loc, MessageTemplate::kIllegalReturn); | |
| 1963 *ok = false; | |
| 1964 return NULL; | |
| 1965 } | |
| 1966 return result; | |
| 1967 } | |
| 1968 | |
| 1969 | |
| 1970 Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels, | |
| 1971 bool* ok) { | |
| 1972 // WithStatement :: | |
| 1973 // 'with' '(' Expression ')' Statement | |
| 1974 | |
| 1975 Expect(Token::WITH, CHECK_OK); | |
| 1976 int pos = position(); | |
| 1977 | |
| 1978 if (is_strict(language_mode())) { | |
| 1979 ReportMessage(MessageTemplate::kStrictWith); | |
| 1980 *ok = false; | |
| 1981 return NULL; | |
| 1982 } | |
| 1983 | |
| 1984 Expect(Token::LPAREN, CHECK_OK); | |
| 1985 Expression* expr = ParseExpression(true, CHECK_OK); | |
| 1986 Expect(Token::RPAREN, CHECK_OK); | |
| 1987 | |
| 1988 Scope* with_scope = NewScope(WITH_SCOPE); | |
| 1989 Statement* body; | |
| 1990 { | |
| 1991 BlockState block_state(&scope_state_, with_scope); | |
| 1992 with_scope->set_start_position(scanner()->peek_location().beg_pos); | |
| 1993 body = ParseScopedStatement(labels, true, CHECK_OK); | |
| 1994 with_scope->set_end_position(scanner()->location().end_pos); | |
| 1995 } | |
| 1996 return factory()->NewWithStatement(with_scope, expr, body, pos); | |
| 1997 } | |
| 1998 | |
| 1999 | |
| 2000 CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { | 1773 CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { |
| 2001 // CaseClause :: | 1774 // CaseClause :: |
| 2002 // 'case' Expression ':' StatementList | 1775 // 'case' Expression ':' StatementList |
| 2003 // 'default' ':' StatementList | 1776 // 'default' ':' StatementList |
| 2004 | 1777 |
| 2005 Expression* label = NULL; // NULL expression indicates default case | 1778 Expression* label = NULL; // NULL expression indicates default case |
| 2006 if (peek() == Token::CASE) { | 1779 if (peek() == Token::CASE) { |
| 2007 Expect(Token::CASE, CHECK_OK); | 1780 Expect(Token::CASE, CHECK_OK); |
| 2008 label = ParseExpression(true, CHECK_OK); | 1781 label = ParseExpression(true, CHECK_OK); |
| 2009 } else { | 1782 } else { |
| (...skipping 3997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6007 node->Print(Isolate::Current()); | 5780 node->Print(Isolate::Current()); |
| 6008 } | 5781 } |
| 6009 #endif // DEBUG | 5782 #endif // DEBUG |
| 6010 | 5783 |
| 6011 #undef CHECK_OK | 5784 #undef CHECK_OK |
| 6012 #undef CHECK_OK_VOID | 5785 #undef CHECK_OK_VOID |
| 6013 #undef CHECK_FAILED | 5786 #undef CHECK_FAILED |
| 6014 | 5787 |
| 6015 } // namespace internal | 5788 } // namespace internal |
| 6016 } // namespace v8 | 5789 } // namespace v8 |
| OLD | NEW |