diff options
Diffstat (limited to 'V8Binding/v8/src/parser.cc')
-rw-r--r-- | V8Binding/v8/src/parser.cc | 4835 |
1 files changed, 0 insertions, 4835 deletions
diff --git a/V8Binding/v8/src/parser.cc b/V8Binding/v8/src/parser.cc deleted file mode 100644 index 3b24687..0000000 --- a/V8Binding/v8/src/parser.cc +++ /dev/null @@ -1,4835 +0,0 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "v8.h" - -#include "api.h" -#include "ast.h" -#include "bootstrapper.h" -#include "compiler.h" -#include "platform.h" -#include "runtime.h" -#include "parser.h" -#include "scopes.h" -#include "string-stream.h" - -namespace v8 { -namespace internal { - -class ParserFactory; -class ParserLog; -class TemporaryScope; -class Target; - -template <typename T> class ZoneListWrapper; - - -// PositionStack is used for on-stack allocation of token positions for -// new expressions. Please look at ParseNewExpression. - -class PositionStack { - public: - explicit PositionStack(bool* ok) : top_(NULL), ok_(ok) {} - ~PositionStack() { ASSERT(!*ok_ || is_empty()); } - - class Element { - public: - Element(PositionStack* stack, int value) { - previous_ = stack->top(); - value_ = value; - stack->set_top(this); - } - - private: - Element* previous() { return previous_; } - int value() { return value_; } - friend class PositionStack; - Element* previous_; - int value_; - }; - - bool is_empty() { return top_ == NULL; } - int pop() { - ASSERT(!is_empty()); - int result = top_->value(); - top_ = top_->previous(); - return result; - } - - private: - Element* top() { return top_; } - void set_top(Element* value) { top_ = value; } - Element* top_; - bool* ok_; -}; - - -class Parser { - public: - Parser(Handle<Script> script, bool allow_natives_syntax, - v8::Extension* extension, bool is_pre_parsing, - ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data); - virtual ~Parser() { } - - // Pre-parse the program from the character stream; returns true on - // success, false if a stack-overflow happened during parsing. - bool PreParseProgram(Handle<String> source, unibrow::CharacterStream* stream); - - void ReportMessage(const char* message, Vector<const char*> args); - virtual void ReportMessageAt(Scanner::Location loc, - const char* message, - Vector<const char*> args) = 0; - - - // Returns NULL if parsing failed. - FunctionLiteral* ParseProgram(Handle<String> source, - unibrow::CharacterStream* stream, - bool in_global_context); - FunctionLiteral* ParseLazy(Handle<String> source, - Handle<String> name, - int start_position, bool is_expression); - - // The minimum number of contiguous assignment that will - // be treated as an initialization block. Benchmarks show that - // the overhead exceeds the savings below this limit. - static const int kMinInitializationBlock = 3; - - protected: - - enum Mode { - PARSE_LAZILY, - PARSE_EAGERLY - }; - - // Report syntax error - void ReportUnexpectedToken(Token::Value token); - - Handle<Script> script_; - Scanner scanner_; - - Scope* top_scope_; - int with_nesting_level_; - - TemporaryScope* temp_scope_; - Mode mode_; - - Target* target_stack_; // for break, continue statements - bool allow_natives_syntax_; - v8::Extension* extension_; - ParserFactory* factory_; - ParserLog* log_; - bool is_pre_parsing_; - ScriptDataImpl* pre_data_; - - bool inside_with() const { return with_nesting_level_ > 0; } - ParserFactory* factory() const { return factory_; } - ParserLog* log() const { return log_; } - Scanner& scanner() { return scanner_; } - Mode mode() const { return mode_; } - ScriptDataImpl* pre_data() const { return pre_data_; } - - // All ParseXXX functions take as the last argument an *ok parameter - // which is set to false if parsing failed; it is unchanged otherwise. - // By making the 'exception handling' explicit, we are forced to check - // for failure at the call sites. - void* ParseSourceElements(ZoneListWrapper<Statement>* processor, - int end_token, bool* ok); - Statement* ParseStatement(ZoneStringList* labels, bool* ok); - Statement* ParseFunctionDeclaration(bool* ok); - Statement* ParseNativeDeclaration(bool* ok); - Block* ParseBlock(ZoneStringList* labels, bool* ok); - Block* ParseVariableStatement(bool* ok); - Block* ParseVariableDeclarations(bool accept_IN, Expression** var, bool* ok); - Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels, - bool* ok); - IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok); - Statement* ParseContinueStatement(bool* ok); - Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok); - Statement* ParseReturnStatement(bool* ok); - Block* WithHelper(Expression* obj, - ZoneStringList* labels, - bool is_catch_block, - bool* ok); - Statement* ParseWithStatement(ZoneStringList* labels, bool* ok); - CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok); - SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok); - LoopStatement* ParseDoStatement(ZoneStringList* labels, bool* ok); - LoopStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok); - Statement* ParseForStatement(ZoneStringList* labels, bool* ok); - Statement* ParseThrowStatement(bool* ok); - Expression* MakeCatchContext(Handle<String> id, VariableProxy* value); - TryStatement* ParseTryStatement(bool* ok); - DebuggerStatement* ParseDebuggerStatement(bool* ok); - - Expression* ParseExpression(bool accept_IN, bool* ok); - Expression* ParseAssignmentExpression(bool accept_IN, bool* ok); - Expression* ParseConditionalExpression(bool accept_IN, bool* ok); - Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok); - Expression* ParseUnaryExpression(bool* ok); - Expression* ParsePostfixExpression(bool* ok); - Expression* ParseLeftHandSideExpression(bool* ok); - Expression* ParseNewExpression(bool* ok); - Expression* ParseMemberExpression(bool* ok); - Expression* ParseNewPrefix(PositionStack* stack, bool* ok); - Expression* ParseMemberWithNewPrefixesExpression(PositionStack* stack, - bool* ok); - Expression* ParsePrimaryExpression(bool* ok); - Expression* ParseArrayLiteral(bool* ok); - Expression* ParseObjectLiteral(bool* ok); - Expression* ParseRegExpLiteral(bool seen_equal, bool* ok); - - // Decide if a property should be the object boilerplate. - bool IsBoilerplateProperty(ObjectLiteral::Property* property); - // If the expression is a literal, return the literal value; - // if the expression is a materialized literal and is simple return a - // compile time value as encoded by CompileTimeValue::GetValue(). - // Otherwise, return undefined literal as the placeholder - // in the object literal boilerplate. - Handle<Object> GetBoilerplateValue(Expression* expression); - - enum FunctionLiteralType { - EXPRESSION, - DECLARATION, - NESTED - }; - - ZoneList<Expression*>* ParseArguments(bool* ok); - FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name, - int function_token_position, - FunctionLiteralType type, - bool* ok); - - - // Magical syntax support. - Expression* ParseV8Intrinsic(bool* ok); - - INLINE(Token::Value peek()) { return scanner_.peek(); } - INLINE(Token::Value Next()) { return scanner_.Next(); } - INLINE(void Consume(Token::Value token)); - void Expect(Token::Value token, bool* ok); - void ExpectSemicolon(bool* ok); - - // Get odd-ball literals. - Literal* GetLiteralUndefined(); - Literal* GetLiteralTheHole(); - Literal* GetLiteralNumber(double value); - - Handle<String> ParseIdentifier(bool* ok); - Handle<String> ParseIdentifierOrGetOrSet(bool* is_get, - bool* is_set, - bool* ok); - - // Parser support - virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, - FunctionLiteral* fun, - bool resolve, - bool* ok) = 0; - - bool TargetStackContainsLabel(Handle<String> label); - BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok); - IterationStatement* LookupContinueTarget(Handle<String> label, bool* ok); - - void RegisterTargetUse(BreakTarget* target, Target* stop); - - // Create a number literal. - Literal* NewNumberLiteral(double value); - - // Generate AST node that throw a ReferenceError with the given type. - Expression* NewThrowReferenceError(Handle<String> type); - - // Generate AST node that throw a SyntaxError with the given - // type. The first argument may be null (in the handle sense) in - // which case no arguments are passed to the constructor. - Expression* NewThrowSyntaxError(Handle<String> type, Handle<Object> first); - - // Generate AST node that throw a TypeError with the given - // type. Both arguments must be non-null (in the handle sense). - Expression* NewThrowTypeError(Handle<String> type, - Handle<Object> first, - Handle<Object> second); - - // Generic AST generator for throwing errors from compiled code. - Expression* NewThrowError(Handle<String> constructor, - Handle<String> type, - Vector< Handle<Object> > arguments); - - friend class Target; - friend class TargetScope; - friend class LexicalScope; - friend class TemporaryScope; -}; - - -template <typename T, int initial_size> -class BufferedZoneList { - public: - - BufferedZoneList() : - list_(NULL), last_(NULL) {} - - // Adds element at end of list. This element is buffered and can - // be read using last() or removed using RemoveLast until a new Add or until - // RemoveLast or GetList has been called. - void Add(T* value) { - if (last_ != NULL) { - if (list_ == NULL) { - list_ = new ZoneList<T*>(initial_size); - } - list_->Add(last_); - } - last_ = value; - } - - T* last() { - ASSERT(last_ != NULL); - return last_; - } - - T* RemoveLast() { - ASSERT(last_ != NULL); - T* result = last_; - if (list_ != NULL && list_->length() > 0) - last_ = list_->RemoveLast(); - else - last_ = NULL; - return result; - } - - T* Get(int i) { - ASSERT(0 <= i && i < length()); - if (list_ == NULL) { - ASSERT_EQ(0, i); - return last_; - } else { - if (i == list_->length()) { - ASSERT(last_ != NULL); - return last_; - } else { - return list_->at(i); - } - } - } - - void Clear() { - list_ = NULL; - last_ = NULL; - } - - int length() { - int length = (list_ == NULL) ? 0 : list_->length(); - return length + ((last_ == NULL) ? 0 : 1); - } - - ZoneList<T*>* GetList() { - if (list_ == NULL) { - list_ = new ZoneList<T*>(initial_size); - } - if (last_ != NULL) { - list_->Add(last_); - last_ = NULL; - } - return list_; - } - - private: - ZoneList<T*>* list_; - T* last_; -}; - -// Accumulates RegExp atoms and assertions into lists of terms and alternatives. -class RegExpBuilder: public ZoneObject { - public: - RegExpBuilder(); - void AddCharacter(uc16 character); - // "Adds" an empty expression. Does nothing except consume a - // following quantifier - void AddEmpty(); - void AddAtom(RegExpTree* tree); - void AddAssertion(RegExpTree* tree); - void NewAlternative(); // '|' - void AddQuantifierToAtom(int min, int max, bool is_greedy); - RegExpTree* ToRegExp(); - private: - void FlushCharacters(); - void FlushText(); - void FlushTerms(); - bool pending_empty_; - ZoneList<uc16>* characters_; - BufferedZoneList<RegExpTree, 2> terms_; - BufferedZoneList<RegExpTree, 2> text_; - BufferedZoneList<RegExpTree, 2> alternatives_; -#ifdef DEBUG - enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_; -#define LAST(x) last_added_ = x; -#else -#define LAST(x) -#endif -}; - - -RegExpBuilder::RegExpBuilder() - : pending_empty_(false), - characters_(NULL), - terms_(), - alternatives_() -#ifdef DEBUG - , last_added_(ADD_NONE) -#endif - {} - - -void RegExpBuilder::FlushCharacters() { - pending_empty_ = false; - if (characters_ != NULL) { - RegExpTree* atom = new RegExpAtom(characters_->ToConstVector()); - characters_ = NULL; - text_.Add(atom); - LAST(ADD_ATOM); - } -} - - -void RegExpBuilder::FlushText() { - FlushCharacters(); - int num_text = text_.length(); - if (num_text == 0) { - return; - } else if (num_text == 1) { - terms_.Add(text_.last()); - } else { - RegExpText* text = new RegExpText(); - for (int i = 0; i < num_text; i++) - text_.Get(i)->AppendToText(text); - terms_.Add(text); - } - text_.Clear(); -} - - -void RegExpBuilder::AddCharacter(uc16 c) { - pending_empty_ = false; - if (characters_ == NULL) { - characters_ = new ZoneList<uc16>(4); - } - characters_->Add(c); - LAST(ADD_CHAR); -} - - -void RegExpBuilder::AddEmpty() { - pending_empty_ = true; -} - - -void RegExpBuilder::AddAtom(RegExpTree* term) { - if (term->IsEmpty()) { - AddEmpty(); - return; - } - if (term->IsTextElement()) { - FlushCharacters(); - text_.Add(term); - } else { - FlushText(); - terms_.Add(term); - } - LAST(ADD_ATOM); -} - - -void RegExpBuilder::AddAssertion(RegExpTree* assert) { - FlushText(); - terms_.Add(assert); - LAST(ADD_ASSERT); -} - - -void RegExpBuilder::NewAlternative() { - FlushTerms(); -} - - -void RegExpBuilder::FlushTerms() { - FlushText(); - int num_terms = terms_.length(); - RegExpTree* alternative; - if (num_terms == 0) { - alternative = RegExpEmpty::GetInstance(); - } else if (num_terms == 1) { - alternative = terms_.last(); - } else { - alternative = new RegExpAlternative(terms_.GetList()); - } - alternatives_.Add(alternative); - terms_.Clear(); - LAST(ADD_NONE); -} - - -RegExpTree* RegExpBuilder::ToRegExp() { - FlushTerms(); - int num_alternatives = alternatives_.length(); - if (num_alternatives == 0) { - return RegExpEmpty::GetInstance(); - } - if (num_alternatives == 1) { - return alternatives_.last(); - } - return new RegExpDisjunction(alternatives_.GetList()); -} - - -void RegExpBuilder::AddQuantifierToAtom(int min, int max, bool is_greedy) { - if (pending_empty_) { - pending_empty_ = false; - return; - } - RegExpTree* atom; - if (characters_ != NULL) { - ASSERT(last_added_ == ADD_CHAR); - // Last atom was character. - Vector<const uc16> char_vector = characters_->ToConstVector(); - int num_chars = char_vector.length(); - if (num_chars > 1) { - Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1); - text_.Add(new RegExpAtom(prefix)); - char_vector = char_vector.SubVector(num_chars - 1, num_chars); - } - characters_ = NULL; - atom = new RegExpAtom(char_vector); - FlushText(); - } else if (text_.length() > 0) { - ASSERT(last_added_ == ADD_ATOM); - atom = text_.RemoveLast(); - FlushText(); - } else if (terms_.length() > 0) { - ASSERT(last_added_ == ADD_ATOM); - atom = terms_.RemoveLast(); - if (atom->max_match() == 0) { - // Guaranteed to only match an empty string. - LAST(ADD_TERM); - if (min == 0) { - return; - } - terms_.Add(atom); - return; - } - } else { - // Only call immediately after adding an atom or character! - UNREACHABLE(); - return; - } - terms_.Add(new RegExpQuantifier(min, max, is_greedy, atom)); - LAST(ADD_TERM); -} - - -class RegExpParser { - public: - RegExpParser(FlatStringReader* in, - Handle<String>* error, - bool multiline_mode); - RegExpTree* ParsePattern(); - RegExpTree* ParseDisjunction(); - RegExpTree* ParseGroup(); - RegExpTree* ParseCharacterClass(); - - // Parses a {...,...} quantifier and stores the range in the given - // out parameters. - bool ParseIntervalQuantifier(int* min_out, int* max_out); - - // Parses and returns a single escaped character. The character - // must not be 'b' or 'B' since they are usually handle specially. - uc32 ParseClassCharacterEscape(); - - // Checks whether the following is a length-digit hexadecimal number, - // and sets the value if it is. - bool ParseHexEscape(int length, uc32* value); - - uc32 ParseControlLetterEscape(); - uc32 ParseOctalLiteral(); - - // Tries to parse the input as a back reference. If successful it - // stores the result in the output parameter and returns true. If - // it fails it will push back the characters read so the same characters - // can be reparsed. - bool ParseBackReferenceIndex(int* index_out); - - CharacterRange ParseClassAtom(uc16* char_class); - RegExpTree* ReportError(Vector<const char> message); - void Advance(); - void Advance(int dist); - void Reset(int pos); - - // Reports whether the pattern might be used as a literal search string. - // Only use if the result of the parse is a single atom node. - bool simple(); - bool contains_anchor() { return contains_anchor_; } - void set_contains_anchor() { contains_anchor_ = true; } - int captures_started() { return captures_ == NULL ? 0 : captures_->length(); } - int position() { return next_pos_ - 1; } - bool failed() { return failed_; } - - static const int kMaxCaptures = 1 << 16; - static const uc32 kEndMarker = (1 << 21); - private: - enum SubexpressionType { - INITIAL, - CAPTURE, // All positive values represent captures. - POSITIVE_LOOKAHEAD, - NEGATIVE_LOOKAHEAD, - GROUPING - }; - - class RegExpParserState : public ZoneObject { - public: - RegExpParserState(RegExpParserState* previous_state, - SubexpressionType group_type, - int disjunction_capture_index) - : previous_state_(previous_state), - builder_(new RegExpBuilder()), - group_type_(group_type), - disjunction_capture_index_(disjunction_capture_index) {} - // Parser state of containing expression, if any. - RegExpParserState* previous_state() { return previous_state_; } - bool IsSubexpression() { return previous_state_ != NULL; } - // RegExpBuilder building this regexp's AST. - RegExpBuilder* builder() { return builder_; } - // Type of regexp being parsed (parenthesized group or entire regexp). - SubexpressionType group_type() { return group_type_; } - // Index in captures array of first capture in this sub-expression, if any. - // Also the capture index of this sub-expression itself, if group_type - // is CAPTURE. - int capture_index() { return disjunction_capture_index_; } - private: - // Linked list implementation of stack of states. - RegExpParserState* previous_state_; - // Builder for the stored disjunction. - RegExpBuilder* builder_; - // Stored disjunction type (capture, look-ahead or grouping), if any. - SubexpressionType group_type_; - // Stored disjunction's capture index (if any). - int disjunction_capture_index_; - }; - - uc32 current() { return current_; } - bool has_more() { return has_more_; } - bool has_next() { return next_pos_ < in()->length(); } - uc32 Next(); - FlatStringReader* in() { return in_; } - void ScanForCaptures(); - uc32 current_; - bool has_more_; - bool multiline_; - int next_pos_; - FlatStringReader* in_; - Handle<String>* error_; - bool simple_; - bool contains_anchor_; - ZoneList<RegExpCapture*>* captures_; - bool is_scanned_for_captures_; - // The capture count is only valid after we have scanned for captures. - int capture_count_; - bool failed_; -}; - - -// A temporary scope stores information during parsing, just like -// a plain scope. However, temporary scopes are not kept around -// after parsing or referenced by syntax trees so they can be stack- -// allocated and hence used by the pre-parser. -class TemporaryScope BASE_EMBEDDED { - public: - explicit TemporaryScope(Parser* parser); - ~TemporaryScope(); - - int NextMaterializedLiteralIndex() { - int next_index = - materialized_literal_count_ + JSFunction::kLiteralsPrefixSize; - materialized_literal_count_++; - return next_index; - } - int materialized_literal_count() { return materialized_literal_count_; } - - void set_contains_array_literal() { contains_array_literal_ = true; } - bool contains_array_literal() { return contains_array_literal_; } - - void SetThisPropertyAssignmentInfo( - bool only_this_property_assignments, - bool only_simple_this_property_assignments, - Handle<FixedArray> this_property_assignments) { - only_this_property_assignments_ = only_this_property_assignments; - only_simple_this_property_assignments_ = - only_simple_this_property_assignments; - this_property_assignments_ = this_property_assignments; - } - bool only_this_property_assignments() { - return only_this_property_assignments_; - } - bool only_simple_this_property_assignments() { - return only_simple_this_property_assignments_; - } - Handle<FixedArray> this_property_assignments() { - return this_property_assignments_; - } - - void AddProperty() { expected_property_count_++; } - int expected_property_count() { return expected_property_count_; } - private: - // Captures the number of nodes that need materialization in the - // function. regexp literals, and boilerplate for object literals. - int materialized_literal_count_; - - // Captures whether or not the function contains array literals. If - // the function contains array literals, we have to allocate space - // for the array constructor in the literals array of the function. - // This array constructor is used when creating the actual array - // literals. - bool contains_array_literal_; - - // Properties count estimation. - int expected_property_count_; - - bool only_this_property_assignments_; - bool only_simple_this_property_assignments_; - Handle<FixedArray> this_property_assignments_; - - // Bookkeeping - Parser* parser_; - TemporaryScope* parent_; - - friend class Parser; -}; - - -TemporaryScope::TemporaryScope(Parser* parser) - : materialized_literal_count_(0), - contains_array_literal_(false), - expected_property_count_(0), - only_this_property_assignments_(false), - only_simple_this_property_assignments_(false), - this_property_assignments_(Factory::empty_fixed_array()), - parser_(parser), - parent_(parser->temp_scope_) { - parser->temp_scope_ = this; -} - - -TemporaryScope::~TemporaryScope() { - parser_->temp_scope_ = parent_; -} - - -// A zone list wrapper lets code either access a access a zone list -// or appear to do so while actually ignoring all operations. -template <typename T> -class ZoneListWrapper { - public: - ZoneListWrapper() : list_(NULL) { } - explicit ZoneListWrapper(int size) : list_(new ZoneList<T*>(size)) { } - void Add(T* that) { if (list_) list_->Add(that); } - int length() { return list_->length(); } - ZoneList<T*>* elements() { return list_; } - T* at(int index) { return list_->at(index); } - private: - ZoneList<T*>* list_; -}; - - -// Allocation macro that should be used to allocate objects that must -// only be allocated in real parsing mode. Note that in preparse mode -// not only is the syntax tree not created but the constructor -// arguments are not evaluated. -#define NEW(expr) (is_pre_parsing_ ? NULL : new expr) - - -class ParserFactory BASE_EMBEDDED { - public: - explicit ParserFactory(bool is_pre_parsing) : - is_pre_parsing_(is_pre_parsing) { } - - virtual ~ParserFactory() { } - - virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with); - - virtual Handle<String> LookupSymbol(const char* string, int length) { - return Handle<String>(); - } - - virtual Handle<String> EmptySymbol() { - return Handle<String>(); - } - - virtual Expression* NewProperty(Expression* obj, Expression* key, int pos) { - if (obj == VariableProxySentinel::this_proxy()) { - return Property::this_property(); - } else { - return ValidLeftHandSideSentinel::instance(); - } - } - - virtual Expression* NewCall(Expression* expression, - ZoneList<Expression*>* arguments, - int pos) { - return Call::sentinel(); - } - - virtual Statement* EmptyStatement() { - return NULL; - } - - template <typename T> ZoneListWrapper<T> NewList(int size) { - return is_pre_parsing_ ? ZoneListWrapper<T>() : ZoneListWrapper<T>(size); - } - - private: - bool is_pre_parsing_; -}; - - -class ParserLog BASE_EMBEDDED { - public: - virtual ~ParserLog() { } - - // Records the occurrence of a function. The returned object is - // only guaranteed to be valid until the next function has been - // logged. - virtual FunctionEntry LogFunction(int start) { return FunctionEntry(); } - - virtual void LogError() { } -}; - - -class AstBuildingParserFactory : public ParserFactory { - public: - AstBuildingParserFactory() : ParserFactory(false) { } - - virtual Scope* NewScope(Scope* parent, Scope::Type type, bool inside_with); - - virtual Handle<String> LookupSymbol(const char* string, int length) { - return Factory::LookupSymbol(Vector<const char>(string, length)); - } - - virtual Handle<String> EmptySymbol() { - return Factory::empty_symbol(); - } - - virtual Expression* NewProperty(Expression* obj, Expression* key, int pos) { - return new Property(obj, key, pos); - } - - virtual Expression* NewCall(Expression* expression, - ZoneList<Expression*>* arguments, - int pos) { - return new Call(expression, arguments, pos); - } - - virtual Statement* EmptyStatement(); -}; - - -class ParserRecorder: public ParserLog { - public: - ParserRecorder(); - virtual FunctionEntry LogFunction(int start); - virtual void LogError() { } - virtual void LogMessage(Scanner::Location loc, - const char* message, - Vector<const char*> args); - void WriteString(Vector<const char> str); - static const char* ReadString(unsigned* start, int* chars); - List<unsigned>* store() { return &store_; } - private: - bool has_error_; - List<unsigned> store_; -}; - - -FunctionEntry ScriptDataImpl::GetFunctionEnd(int start) { - if (nth(last_entry_).start_pos() > start) { - // If the last entry we looked up is higher than what we're - // looking for then it's useless and we reset it. - last_entry_ = 0; - } - for (int i = last_entry_; i < EntryCount(); i++) { - FunctionEntry entry = nth(i); - if (entry.start_pos() == start) { - last_entry_ = i; - return entry; - } - } - return FunctionEntry(); -} - - -bool ScriptDataImpl::SanityCheck() { - if (store_.length() < static_cast<int>(ScriptDataImpl::kHeaderSize)) - return false; - if (magic() != ScriptDataImpl::kMagicNumber) - return false; - if (version() != ScriptDataImpl::kCurrentVersion) - return false; - return true; -} - - -int ScriptDataImpl::EntryCount() { - return (store_.length() - kHeaderSize) / FunctionEntry::kSize; -} - - -FunctionEntry ScriptDataImpl::nth(int n) { - int offset = kHeaderSize + n * FunctionEntry::kSize; - return FunctionEntry(Vector<unsigned>(store_.start() + offset, - FunctionEntry::kSize)); -} - - -ParserRecorder::ParserRecorder() - : has_error_(false), store_(4) { - Vector<unsigned> preamble = store()->AddBlock(0, ScriptDataImpl::kHeaderSize); - preamble[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber; - preamble[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion; - preamble[ScriptDataImpl::kHasErrorOffset] = false; -} - - -void ParserRecorder::WriteString(Vector<const char> str) { - store()->Add(str.length()); - for (int i = 0; i < str.length(); i++) - store()->Add(str[i]); -} - - -const char* ParserRecorder::ReadString(unsigned* start, int* chars) { - int length = start[0]; - char* result = NewArray<char>(length + 1); - for (int i = 0; i < length; i++) - result[i] = start[i + 1]; - result[length] = '\0'; - if (chars != NULL) *chars = length; - return result; -} - - -void ParserRecorder::LogMessage(Scanner::Location loc, const char* message, - Vector<const char*> args) { - if (has_error_) return; - store()->Rewind(ScriptDataImpl::kHeaderSize); - store()->at(ScriptDataImpl::kHasErrorOffset) = true; - store()->Add(loc.beg_pos); - store()->Add(loc.end_pos); - store()->Add(args.length()); - WriteString(CStrVector(message)); - for (int i = 0; i < args.length(); i++) - WriteString(CStrVector(args[i])); -} - - -Scanner::Location ScriptDataImpl::MessageLocation() { - int beg_pos = Read(0); - int end_pos = Read(1); - return Scanner::Location(beg_pos, end_pos); -} - - -const char* ScriptDataImpl::BuildMessage() { - unsigned* start = ReadAddress(3); - return ParserRecorder::ReadString(start, NULL); -} - - -Vector<const char*> ScriptDataImpl::BuildArgs() { - int arg_count = Read(2); - const char** array = NewArray<const char*>(arg_count); - int pos = ScriptDataImpl::kHeaderSize + Read(3); - for (int i = 0; i < arg_count; i++) { - int count = 0; - array[i] = ParserRecorder::ReadString(ReadAddress(pos), &count); - pos += count + 1; - } - return Vector<const char*>(array, arg_count); -} - - -unsigned ScriptDataImpl::Read(int position) { - return store_[ScriptDataImpl::kHeaderSize + position]; -} - - -unsigned* ScriptDataImpl::ReadAddress(int position) { - return &store_[ScriptDataImpl::kHeaderSize + position]; -} - - -FunctionEntry ParserRecorder::LogFunction(int start) { - if (has_error_) return FunctionEntry(); - FunctionEntry result(store()->AddBlock(0, FunctionEntry::kSize)); - result.set_start_pos(start); - return result; -} - - -class AstBuildingParser : public Parser { - public: - AstBuildingParser(Handle<Script> script, bool allow_natives_syntax, - v8::Extension* extension, ScriptDataImpl* pre_data) - : Parser(script, allow_natives_syntax, extension, false, - factory(), log(), pre_data) { } - virtual void ReportMessageAt(Scanner::Location loc, const char* message, - Vector<const char*> args); - virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, - FunctionLiteral* fun, bool resolve, bool* ok); - AstBuildingParserFactory* factory() { return &factory_; } - ParserLog* log() { return &log_; } - - private: - ParserLog log_; - AstBuildingParserFactory factory_; -}; - - -class PreParser : public Parser { - public: - PreParser(Handle<Script> script, bool allow_natives_syntax, - v8::Extension* extension) - : Parser(script, allow_natives_syntax, extension, true, - factory(), recorder(), NULL) - , factory_(true) { } - virtual void ReportMessageAt(Scanner::Location loc, const char* message, - Vector<const char*> args); - virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, - FunctionLiteral* fun, bool resolve, bool* ok); - ParserFactory* factory() { return &factory_; } - ParserRecorder* recorder() { return &recorder_; } - - private: - ParserRecorder recorder_; - ParserFactory factory_; -}; - - -Scope* AstBuildingParserFactory::NewScope(Scope* parent, Scope::Type type, - bool inside_with) { - Scope* result = new Scope(parent, type); - result->Initialize(inside_with); - return result; -} - - -Statement* AstBuildingParserFactory::EmptyStatement() { - // Use a statically allocated empty statement singleton to avoid - // allocating lots and lots of empty statements. - static v8::internal::EmptyStatement empty; - return ∅ -} - - -Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type, - bool inside_with) { - ASSERT(parent != NULL); - parent->type_ = type; - return parent; -} - - -VariableProxy* PreParser::Declare(Handle<String> name, Variable::Mode mode, - FunctionLiteral* fun, bool resolve, - bool* ok) { - return NULL; -} - - - -// ---------------------------------------------------------------------------- -// Target is a support class to facilitate manipulation of the -// Parser's target_stack_ (the stack of potential 'break' and -// 'continue' statement targets). Upon construction, a new target is -// added; it is removed upon destruction. - -class Target BASE_EMBEDDED { - public: - Target(Parser* parser, AstNode* node) - : parser_(parser), node_(node), previous_(parser_->target_stack_) { - parser_->target_stack_ = this; - } - - ~Target() { - parser_->target_stack_ = previous_; - } - - Target* previous() { return previous_; } - AstNode* node() { return node_; } - - private: - Parser* parser_; - AstNode* node_; - Target* previous_; -}; - - -class TargetScope BASE_EMBEDDED { - public: - explicit TargetScope(Parser* parser) - : parser_(parser), previous_(parser->target_stack_) { - parser->target_stack_ = NULL; - } - - ~TargetScope() { - parser_->target_stack_ = previous_; - } - - private: - Parser* parser_; - Target* previous_; -}; - - -// ---------------------------------------------------------------------------- -// LexicalScope is a support class to facilitate manipulation of the -// Parser's scope stack. The constructor sets the parser's top scope -// to the incoming scope, and the destructor resets it. - -class LexicalScope BASE_EMBEDDED { - public: - LexicalScope(Parser* parser, Scope* scope) - : parser_(parser), - prev_scope_(parser->top_scope_), - prev_level_(parser->with_nesting_level_) { - parser_->top_scope_ = scope; - parser_->with_nesting_level_ = 0; - } - - ~LexicalScope() { - parser_->top_scope_ = prev_scope_; - parser_->with_nesting_level_ = prev_level_; - } - - private: - Parser* parser_; - Scope* prev_scope_; - int prev_level_; -}; - - -// ---------------------------------------------------------------------------- -// The CHECK_OK macro is a convenient macro to enforce error -// handling for functions that may fail (by returning !*ok). -// -// CAUTION: This macro appends extra statements after a call, -// thus it must never be used where only a single statement -// is correct (e.g. an if statement branch w/o braces)! - -#define CHECK_OK ok); \ - if (!*ok) return NULL; \ - ((void)0 -#define DUMMY ) // to make indentation work -#undef DUMMY - -#define CHECK_FAILED /**/); \ - if (failed_) return NULL; \ - ((void)0 -#define DUMMY ) // to make indentation work -#undef DUMMY - -// ---------------------------------------------------------------------------- -// Implementation of Parser - -Parser::Parser(Handle<Script> script, - bool allow_natives_syntax, - v8::Extension* extension, - bool is_pre_parsing, - ParserFactory* factory, - ParserLog* log, - ScriptDataImpl* pre_data) - : script_(script), - scanner_(is_pre_parsing), - top_scope_(NULL), - with_nesting_level_(0), - temp_scope_(NULL), - target_stack_(NULL), - allow_natives_syntax_(allow_natives_syntax), - extension_(extension), - factory_(factory), - log_(log), - is_pre_parsing_(is_pre_parsing), - pre_data_(pre_data) { -} - - -bool Parser::PreParseProgram(Handle<String> source, - unibrow::CharacterStream* stream) { - HistogramTimerScope timer(&Counters::pre_parse); - AssertNoZoneAllocation assert_no_zone_allocation; - AssertNoAllocation assert_no_allocation; - NoHandleAllocation no_handle_allocation; - scanner_.Init(source, stream, 0); - ASSERT(target_stack_ == NULL); - mode_ = PARSE_EAGERLY; - DummyScope top_scope; - LexicalScope scope(this, &top_scope); - TemporaryScope temp_scope(this); - ZoneListWrapper<Statement> processor; - bool ok = true; - ParseSourceElements(&processor, Token::EOS, &ok); - return !scanner().stack_overflow(); -} - - -FunctionLiteral* Parser::ParseProgram(Handle<String> source, - unibrow::CharacterStream* stream, - bool in_global_context) { - CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); - - HistogramTimerScope timer(&Counters::parse); - Counters::total_parse_size.Increment(source->length()); - - // Initialize parser state. - source->TryFlattenIfNotFlat(); - scanner_.Init(source, stream, 0); - ASSERT(target_stack_ == NULL); - - // Compute the parsing mode. - mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY; - if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY; - - Scope::Type type = - in_global_context - ? Scope::GLOBAL_SCOPE - : Scope::EVAL_SCOPE; - Handle<String> no_name = factory()->EmptySymbol(); - - FunctionLiteral* result = NULL; - { Scope* scope = factory()->NewScope(top_scope_, type, inside_with()); - LexicalScope lexical_scope(this, scope); - TemporaryScope temp_scope(this); - ZoneListWrapper<Statement> body(16); - bool ok = true; - ParseSourceElements(&body, Token::EOS, &ok); - if (ok) { - result = NEW(FunctionLiteral( - no_name, - top_scope_, - body.elements(), - temp_scope.materialized_literal_count(), - temp_scope.contains_array_literal(), - temp_scope.expected_property_count(), - temp_scope.only_this_property_assignments(), - temp_scope.only_simple_this_property_assignments(), - temp_scope.this_property_assignments(), - 0, - 0, - source->length(), - false)); - } else if (scanner().stack_overflow()) { - Top::StackOverflow(); - } - } - - // Make sure the target stack is empty. - ASSERT(target_stack_ == NULL); - - // If there was a syntax error we have to get rid of the AST - // and it is not safe to do so before the scope has been deleted. - if (result == NULL) zone_scope.DeleteOnExit(); - return result; -} - - -FunctionLiteral* Parser::ParseLazy(Handle<String> source, - Handle<String> name, - int start_position, - bool is_expression) { - CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); - HistogramTimerScope timer(&Counters::parse_lazy); - source->TryFlattenIfNotFlat(); - Counters::total_parse_size.Increment(source->length()); - SafeStringInputBuffer buffer(source.location()); - - // Initialize parser state. - scanner_.Init(source, &buffer, start_position); - ASSERT(target_stack_ == NULL); - mode_ = PARSE_EAGERLY; - - // Place holder for the result. - FunctionLiteral* result = NULL; - - { - // Parse the function literal. - Handle<String> no_name = factory()->EmptySymbol(); - Scope* scope = - factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with()); - LexicalScope lexical_scope(this, scope); - TemporaryScope temp_scope(this); - - FunctionLiteralType type = is_expression ? EXPRESSION : DECLARATION; - bool ok = true; - result = ParseFunctionLiteral(name, RelocInfo::kNoPosition, type, &ok); - // Make sure the results agree. - ASSERT(ok == (result != NULL)); - // The only errors should be stack overflows. - ASSERT(ok || scanner_.stack_overflow()); - } - - // Make sure the target stack is empty. - ASSERT(target_stack_ == NULL); - - // If there was a stack overflow we have to get rid of AST and it is - // not safe to do before scope has been deleted. - if (result == NULL) { - Top::StackOverflow(); - zone_scope.DeleteOnExit(); - } - return result; -} - - -void Parser::ReportMessage(const char* type, Vector<const char*> args) { - Scanner::Location source_location = scanner_.location(); - ReportMessageAt(source_location, type, args); -} - - -void AstBuildingParser::ReportMessageAt(Scanner::Location source_location, - const char* type, - Vector<const char*> args) { - MessageLocation location(script_, - source_location.beg_pos, source_location.end_pos); - Handle<JSArray> array = Factory::NewJSArray(args.length()); - for (int i = 0; i < args.length(); i++) { - SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i]))); - } - Handle<Object> result = Factory::NewSyntaxError(type, array); - Top::Throw(*result, &location); -} - - -void PreParser::ReportMessageAt(Scanner::Location source_location, - const char* type, - Vector<const char*> args) { - recorder()->LogMessage(source_location, type, args); -} - - -// Base class containing common code for the different finder classes used by -// the parser. -class ParserFinder { - protected: - ParserFinder() {} - static Assignment* AsAssignment(Statement* stat) { - if (stat == NULL) return NULL; - ExpressionStatement* exp_stat = stat->AsExpressionStatement(); - if (exp_stat == NULL) return NULL; - return exp_stat->expression()->AsAssignment(); - } -}; - - -// An InitializationBlockFinder finds and marks sequences of statements of the -// form x.y.z.a = ...; x.y.z.b = ...; etc. -class InitializationBlockFinder : public ParserFinder { - public: - InitializationBlockFinder() - : first_in_block_(NULL), last_in_block_(NULL), block_size_(0) {} - - ~InitializationBlockFinder() { - if (InBlock()) EndBlock(); - } - - void Update(Statement* stat) { - Assignment* assignment = AsAssignment(stat); - if (InBlock()) { - if (BlockContinues(assignment)) { - UpdateBlock(assignment); - } else { - EndBlock(); - } - } - if (!InBlock() && (assignment != NULL) && - (assignment->op() == Token::ASSIGN)) { - StartBlock(assignment); - } - } - - private: - // Returns true if the expressions appear to denote the same object. - // In the context of initialization blocks, we only consider expressions - // of the form 'x.y.z'. - static bool SameObject(Expression* e1, Expression* e2) { - VariableProxy* v1 = e1->AsVariableProxy(); - VariableProxy* v2 = e2->AsVariableProxy(); - if (v1 != NULL && v2 != NULL) { - return v1->name()->Equals(*v2->name()); - } - Property* p1 = e1->AsProperty(); - Property* p2 = e2->AsProperty(); - if ((p1 == NULL) || (p2 == NULL)) return false; - Literal* key1 = p1->key()->AsLiteral(); - Literal* key2 = p2->key()->AsLiteral(); - if ((key1 == NULL) || (key2 == NULL)) return false; - if (!key1->handle()->IsString() || !key2->handle()->IsString()) { - return false; - } - String* name1 = String::cast(*key1->handle()); - String* name2 = String::cast(*key2->handle()); - if (!name1->Equals(name2)) return false; - return SameObject(p1->obj(), p2->obj()); - } - - // Returns true if the expressions appear to denote different properties - // of the same object. - static bool PropertyOfSameObject(Expression* e1, Expression* e2) { - Property* p1 = e1->AsProperty(); - Property* p2 = e2->AsProperty(); - if ((p1 == NULL) || (p2 == NULL)) return false; - return SameObject(p1->obj(), p2->obj()); - } - - bool BlockContinues(Assignment* assignment) { - if ((assignment == NULL) || (first_in_block_ == NULL)) return false; - if (assignment->op() != Token::ASSIGN) return false; - return PropertyOfSameObject(first_in_block_->target(), - assignment->target()); - } - - void StartBlock(Assignment* assignment) { - first_in_block_ = assignment; - last_in_block_ = assignment; - block_size_ = 1; - } - - void UpdateBlock(Assignment* assignment) { - last_in_block_ = assignment; - ++block_size_; - } - - void EndBlock() { - if (block_size_ >= Parser::kMinInitializationBlock) { - first_in_block_->mark_block_start(); - last_in_block_->mark_block_end(); - } - last_in_block_ = first_in_block_ = NULL; - block_size_ = 0; - } - - bool InBlock() { return first_in_block_ != NULL; } - - Assignment* first_in_block_; - Assignment* last_in_block_; - int block_size_; - - DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder); -}; - - -// A ThisNamedPropertyAssigmentFinder finds and marks statements of the form -// this.x = ...;, where x is a named property. It also determines whether a -// function contains only assignments of this type. -class ThisNamedPropertyAssigmentFinder : public ParserFinder { - public: - ThisNamedPropertyAssigmentFinder() - : only_this_property_assignments_(true), - only_simple_this_property_assignments_(true), - names_(NULL), - assigned_arguments_(NULL), - assigned_constants_(NULL) {} - - void Update(Scope* scope, Statement* stat) { - // Bail out if function already has non this property assignment - // statements. - if (!only_this_property_assignments_) { - return; - } - - // Check whether this statement is of the form this.x = ...; - Assignment* assignment = AsAssignment(stat); - if (IsThisPropertyAssignment(assignment)) { - HandleThisPropertyAssignment(scope, assignment); - } else { - only_this_property_assignments_ = false; - only_simple_this_property_assignments_ = false; - } - } - - // Returns whether only statements of the form this.x = ...; was encountered. - bool only_this_property_assignments() { - return only_this_property_assignments_; - } - - // Returns whether only statements of the form this.x = y; where y is either a - // constant or a function argument was encountered. - bool only_simple_this_property_assignments() { - return only_simple_this_property_assignments_; - } - - // Returns a fixed array containing three elements for each assignment of the - // form this.x = y; - Handle<FixedArray> GetThisPropertyAssignments() { - if (names_ == NULL) { - return Factory::empty_fixed_array(); - } - ASSERT(names_ != NULL); - ASSERT(assigned_arguments_ != NULL); - ASSERT_EQ(names_->length(), assigned_arguments_->length()); - ASSERT_EQ(names_->length(), assigned_constants_->length()); - Handle<FixedArray> assignments = - Factory::NewFixedArray(names_->length() * 3); - for (int i = 0; i < names_->length(); i++) { - assignments->set(i * 3, *names_->at(i)); - assignments->set(i * 3 + 1, Smi::FromInt(assigned_arguments_->at(i))); - assignments->set(i * 3 + 2, *assigned_constants_->at(i)); - } - return assignments; - } - - private: - bool IsThisPropertyAssignment(Assignment* assignment) { - if (assignment != NULL) { - Property* property = assignment->target()->AsProperty(); - return assignment->op() == Token::ASSIGN - && property != NULL - && property->obj()->AsVariableProxy() != NULL - && property->obj()->AsVariableProxy()->is_this(); - } - return false; - } - - void HandleThisPropertyAssignment(Scope* scope, Assignment* assignment) { - // Check that the property assigned to is a named property. - Property* property = assignment->target()->AsProperty(); - ASSERT(property != NULL); - Literal* literal = property->key()->AsLiteral(); - uint32_t dummy; - if (literal != NULL && - literal->handle()->IsString() && - !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { - Handle<String> key = Handle<String>::cast(literal->handle()); - - // Check whether the value assigned is either a constant or matches the - // name of one of the arguments to the function. - if (assignment->value()->AsLiteral() != NULL) { - // Constant assigned. - Literal* literal = assignment->value()->AsLiteral(); - AssignmentFromConstant(key, literal->handle()); - } else if (assignment->value()->AsVariableProxy() != NULL) { - // Variable assigned. - Handle<String> name = - assignment->value()->AsVariableProxy()->name(); - // Check whether the variable assigned matches an argument name. - int index = -1; - for (int i = 0; i < scope->num_parameters(); i++) { - if (*scope->parameter(i)->name() == *name) { - // Assigned from function argument. - index = i; - break; - } - } - if (index != -1) { - AssignmentFromParameter(key, index); - } else { - AssignmentFromSomethingElse(key); - } - } else { - AssignmentFromSomethingElse(key); - } - } - } - - void AssignmentFromParameter(Handle<String> name, int index) { - EnsureAllocation(); - names_->Add(name); - assigned_arguments_->Add(index); - assigned_constants_->Add(Factory::undefined_value()); - } - - void AssignmentFromConstant(Handle<String> name, Handle<Object> value) { - EnsureAllocation(); - names_->Add(name); - assigned_arguments_->Add(-1); - assigned_constants_->Add(value); - } - - void AssignmentFromSomethingElse(Handle<String> name) { - EnsureAllocation(); - names_->Add(name); - assigned_arguments_->Add(-1); - assigned_constants_->Add(Factory::undefined_value()); - - // The this assignment is not a simple one. - only_simple_this_property_assignments_ = false; - } - - void EnsureAllocation() { - if (names_ == NULL) { - ASSERT(assigned_arguments_ == NULL); - ASSERT(assigned_constants_ == NULL); - names_ = new ZoneStringList(4); - assigned_arguments_ = new ZoneList<int>(4); - assigned_constants_ = new ZoneObjectList(4); - } - } - - bool only_this_property_assignments_; - bool only_simple_this_property_assignments_; - ZoneStringList* names_; - ZoneList<int>* assigned_arguments_; - ZoneObjectList* assigned_constants_; -}; - - -void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor, - int end_token, - bool* ok) { - // SourceElements :: - // (Statement)* <end_token> - - // Allocate a target stack to use for this set of source - // elements. This way, all scripts and functions get their own - // target stack thus avoiding illegal breaks and continues across - // functions. - TargetScope scope(this); - - ASSERT(processor != NULL); - InitializationBlockFinder block_finder; - ThisNamedPropertyAssigmentFinder this_property_assignment_finder; - while (peek() != end_token) { - Statement* stat = ParseStatement(NULL, CHECK_OK); - if (stat == NULL || stat->IsEmpty()) continue; - // We find and mark the initialization blocks on top level code only. - // This is because the optimization prevents reuse of the map transitions, - // so it should be used only for code that will only be run once. - if (top_scope_->is_global_scope()) { - block_finder.Update(stat); - } - // Find and mark all assignments to named properties in this (this.x =) - if (top_scope_->is_function_scope()) { - this_property_assignment_finder.Update(top_scope_, stat); - } - processor->Add(stat); - } - - // Propagate the collected information on this property assignments. - if (top_scope_->is_function_scope()) { - if (this_property_assignment_finder.only_this_property_assignments()) { - temp_scope_->SetThisPropertyAssignmentInfo( - this_property_assignment_finder.only_this_property_assignments(), - this_property_assignment_finder. - only_simple_this_property_assignments(), - this_property_assignment_finder.GetThisPropertyAssignments()); - } - } - return 0; -} - - -Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { - // Statement :: - // Block - // VariableStatement - // EmptyStatement - // ExpressionStatement - // IfStatement - // IterationStatement - // ContinueStatement - // BreakStatement - // ReturnStatement - // WithStatement - // LabelledStatement - // SwitchStatement - // ThrowStatement - // TryStatement - // DebuggerStatement - - // Note: Since labels can only be used by 'break' and 'continue' - // statements, which themselves are only valid within blocks, - // iterations or 'switch' statements (i.e., BreakableStatements), - // labels can be simply ignored in all other cases; except for - // trivial labeled break statements 'label: break label' which is - // parsed into an empty statement. - - // Keep the source position of the statement - int statement_pos = scanner().peek_location().beg_pos; - Statement* stmt = NULL; - switch (peek()) { - case Token::LBRACE: - return ParseBlock(labels, ok); - - case Token::CONST: // fall through - case Token::VAR: - stmt = ParseVariableStatement(ok); - break; - - case Token::SEMICOLON: - Next(); - return factory()->EmptyStatement(); - - case Token::IF: - stmt = ParseIfStatement(labels, ok); - break; - - case Token::DO: - stmt = ParseDoStatement(labels, ok); - break; - - case Token::WHILE: - stmt = ParseWhileStatement(labels, ok); - break; - - case Token::FOR: - stmt = ParseForStatement(labels, ok); - break; - - case Token::CONTINUE: - stmt = ParseContinueStatement(ok); - break; - - case Token::BREAK: - stmt = ParseBreakStatement(labels, ok); - break; - - case Token::RETURN: - stmt = ParseReturnStatement(ok); - break; - - case Token::WITH: - stmt = ParseWithStatement(labels, ok); - break; - - case Token::SWITCH: - stmt = ParseSwitchStatement(labels, ok); - break; - - case Token::THROW: - stmt = ParseThrowStatement(ok); - break; - - case Token::TRY: { - // NOTE: It is somewhat complicated to have labels on - // try-statements. When breaking out of a try-finally statement, - // one must take great care not to treat it as a - // fall-through. It is much easier just to wrap the entire - // try-statement in a statement block and put the labels there - Block* result = NEW(Block(labels, 1, false)); - Target target(this, result); - TryStatement* statement = ParseTryStatement(CHECK_OK); - if (statement) { - statement->set_statement_pos(statement_pos); - } - if (result) result->AddStatement(statement); - return result; - } - - case Token::FUNCTION: - return ParseFunctionDeclaration(ok); - - case Token::NATIVE: - return ParseNativeDeclaration(ok); - - case Token::DEBUGGER: - stmt = ParseDebuggerStatement(ok); - break; - - default: - stmt = ParseExpressionOrLabelledStatement(labels, ok); - } - - // Store the source position of the statement - if (stmt != NULL) stmt->set_statement_pos(statement_pos); - return stmt; -} - - -VariableProxy* AstBuildingParser::Declare(Handle<String> name, - Variable::Mode mode, - FunctionLiteral* fun, - bool resolve, - bool* ok) { - Variable* var = NULL; - // If we are inside a function, a declaration of a variable - // is a truly local variable, and the scope of the variable - // is always the function scope. - - // If a function scope exists, then we can statically declare this - // variable and also set its mode. In any case, a Declaration node - // will be added to the scope so that the declaration can be added - // to the corresponding activation frame at runtime if necessary. - // For instance declarations inside an eval scope need to be added - // to the calling function context. - if (top_scope_->is_function_scope()) { - // Declare the variable in the function scope. - var = top_scope_->LocalLookup(name); - if (var == NULL) { - // Declare the name. - var = top_scope_->DeclareLocal(name, mode); - } else { - // The name was declared before; check for conflicting - // re-declarations. If the previous declaration was a const or the - // current declaration is a const then we have a conflict. There is - // similar code in runtime.cc in the Declare functions. - if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) { - // We only have vars and consts in declarations. - ASSERT(var->mode() == Variable::VAR || - var->mode() == Variable::CONST); - const char* type = (var->mode() == Variable::VAR) ? "var" : "const"; - Handle<String> type_string = - Factory::NewStringFromUtf8(CStrVector(type), TENURED); - Expression* expression = - NewThrowTypeError(Factory::redeclaration_symbol(), - type_string, name); - top_scope_->SetIllegalRedeclaration(expression); - } - } - } - - // We add a declaration node for every declaration. The compiler - // will only generate code if necessary. In particular, declarations - // for inner local variables that do not represent functions won't - // result in any generated code. - // - // Note that we always add an unresolved proxy even if it's not - // used, simply because we don't know in this method (w/o extra - // parameters) if the proxy is needed or not. The proxy will be - // bound during variable resolution time unless it was pre-bound - // below. - // - // WARNING: This will lead to multiple declaration nodes for the - // same variable if it is declared several times. This is not a - // semantic issue as long as we keep the source order, but it may be - // a performance issue since it may lead to repeated - // Runtime::DeclareContextSlot() calls. - VariableProxy* proxy = top_scope_->NewUnresolved(name, inside_with()); - top_scope_->AddDeclaration(NEW(Declaration(proxy, mode, fun))); - - // For global const variables we bind the proxy to a variable. - if (mode == Variable::CONST && top_scope_->is_global_scope()) { - ASSERT(resolve); // should be set by all callers - Variable::Kind kind = Variable::NORMAL; - var = NEW(Variable(top_scope_, name, Variable::CONST, true, kind)); - } - - // If requested and we have a local variable, bind the proxy to the variable - // at parse-time. This is used for functions (and consts) declared inside - // statements: the corresponding function (or const) variable must be in the - // function scope and not a statement-local scope, e.g. as provided with a - // 'with' statement: - // - // with (obj) { - // function f() {} - // } - // - // which is translated into: - // - // with (obj) { - // // in this case this is not: 'var f; f = function () {};' - // var f = function () {}; - // } - // - // Note that if 'f' is accessed from inside the 'with' statement, it - // will be allocated in the context (because we must be able to look - // it up dynamically) but it will also be accessed statically, i.e., - // with a context slot index and a context chain length for this - // initialization code. Thus, inside the 'with' statement, we need - // both access to the static and the dynamic context chain; the - // runtime needs to provide both. - if (resolve && var != NULL) proxy->BindTo(var); - - return proxy; -} - - -// Language extension which is only enabled for source files loaded -// through the API's extension mechanism. A native function -// declaration is resolved by looking up the function through a -// callback provided by the extension. -Statement* Parser::ParseNativeDeclaration(bool* ok) { - if (extension_ == NULL) { - ReportUnexpectedToken(Token::NATIVE); - *ok = false; - return NULL; - } - - Expect(Token::NATIVE, CHECK_OK); - Expect(Token::FUNCTION, CHECK_OK); - Handle<String> name = ParseIdentifier(CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - bool done = (peek() == Token::RPAREN); - while (!done) { - ParseIdentifier(CHECK_OK); - done = (peek() == Token::RPAREN); - if (!done) Expect(Token::COMMA, CHECK_OK); - } - Expect(Token::RPAREN, CHECK_OK); - Expect(Token::SEMICOLON, CHECK_OK); - - if (is_pre_parsing_) return NULL; - - // Make sure that the function containing the native declaration - // isn't lazily compiled. The extension structures are only - // accessible while parsing the first time not when reparsing - // because of lazy compilation. - top_scope_->ForceEagerCompilation(); - - // Compute the function template for the native function. - v8::Handle<v8::FunctionTemplate> fun_template = - extension_->GetNativeFunction(v8::Utils::ToLocal(name)); - ASSERT(!fun_template.IsEmpty()); - - // Instantiate the function and create a boilerplate function from it. - Handle<JSFunction> fun = Utils::OpenHandle(*fun_template->GetFunction()); - const int literals = fun->NumberOfLiterals(); - Handle<Code> code = Handle<Code>(fun->shared()->code()); - Handle<JSFunction> boilerplate = - Factory::NewFunctionBoilerplate(name, literals, false, code); - - // Copy the function data to the boilerplate. Used by - // builtins.cc:HandleApiCall to perform argument type checks and to - // find the right native code to call. - boilerplate->shared()->set_function_data(fun->shared()->function_data()); - int parameters = fun->shared()->formal_parameter_count(); - boilerplate->shared()->set_formal_parameter_count(parameters); - - // TODO(1240846): It's weird that native function declarations are - // introduced dynamically when we meet their declarations, whereas - // other functions are setup when entering the surrounding scope. - FunctionBoilerplateLiteral* lit = - NEW(FunctionBoilerplateLiteral(boilerplate)); - VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK); - return NEW(ExpressionStatement( - new Assignment(Token::INIT_VAR, var, lit, RelocInfo::kNoPosition))); -} - - -Statement* Parser::ParseFunctionDeclaration(bool* ok) { - // FunctionDeclaration :: - // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' - Expect(Token::FUNCTION, CHECK_OK); - int function_token_position = scanner().location().beg_pos; - Handle<String> name = ParseIdentifier(CHECK_OK); - FunctionLiteral* fun = ParseFunctionLiteral(name, - function_token_position, - DECLARATION, - CHECK_OK); - // Even if we're not at the top-level of the global or a function - // scope, we treat is as such and introduce the function with it's - // initial value upon entering the corresponding scope. - Declare(name, Variable::VAR, fun, true, CHECK_OK); - return factory()->EmptyStatement(); -} - - -Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { - // Block :: - // '{' Statement* '}' - - // Note that a Block does not introduce a new execution scope! - // (ECMA-262, 3rd, 12.2) - // - // Construct block expecting 16 statements. - Block* result = NEW(Block(labels, 16, false)); - Target target(this, result); - Expect(Token::LBRACE, CHECK_OK); - while (peek() != Token::RBRACE) { - Statement* stat = ParseStatement(NULL, CHECK_OK); - if (stat && !stat->IsEmpty()) result->AddStatement(stat); - } - Expect(Token::RBRACE, CHECK_OK); - return result; -} - - -Block* Parser::ParseVariableStatement(bool* ok) { - // VariableStatement :: - // VariableDeclarations ';' - - Expression* dummy; // to satisfy the ParseVariableDeclarations() signature - Block* result = ParseVariableDeclarations(true, &dummy, CHECK_OK); - ExpectSemicolon(CHECK_OK); - return result; -} - - -// If the variable declaration declares exactly one non-const -// variable, then *var is set to that variable. In all other cases, -// *var is untouched; in particular, it is the caller's responsibility -// to initialize it properly. This mechanism is used for the parsing -// of 'for-in' loops. -Block* Parser::ParseVariableDeclarations(bool accept_IN, - Expression** var, - bool* ok) { - // VariableDeclarations :: - // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] - - Variable::Mode mode = Variable::VAR; - bool is_const = false; - if (peek() == Token::VAR) { - Consume(Token::VAR); - } else if (peek() == Token::CONST) { - Consume(Token::CONST); - mode = Variable::CONST; - is_const = true; - } else { - UNREACHABLE(); // by current callers - } - - // The scope of a variable/const declared anywhere inside a function - // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). Thus we can - // transform a source-level variable/const declaration into a (Function) - // Scope declaration, and rewrite the source-level initialization into an - // assignment statement. We use a block to collect multiple assignments. - // - // We mark the block as initializer block because we don't want the - // rewriter to add a '.result' assignment to such a block (to get compliant - // behavior for code such as print(eval('var x = 7')), and for cosmetic - // reasons when pretty-printing. Also, unless an assignment (initialization) - // is inside an initializer block, it is ignored. - // - // Create new block with one expected declaration. - Block* block = NEW(Block(NULL, 1, true)); - VariableProxy* last_var = NULL; // the last variable declared - int nvars = 0; // the number of variables declared - do { - // Parse variable name. - if (nvars > 0) Consume(Token::COMMA); - Handle<String> name = ParseIdentifier(CHECK_OK); - - // Declare variable. - // Note that we *always* must treat the initial value via a separate init - // assignment for variables and constants because the value must be assigned - // when the variable is encountered in the source. But the variable/constant - // is declared (and set to 'undefined') upon entering the function within - // which the variable or constant is declared. Only function variables have - // an initial value in the declaration (because they are initialized upon - // entering the function). - // - // If we have a const declaration, in an inner scope, the proxy is always - // bound to the declared variable (independent of possibly surrounding with - // statements). - last_var = Declare(name, mode, NULL, - is_const /* always bound for CONST! */, - CHECK_OK); - nvars++; - - // Parse initialization expression if present and/or needed. A - // declaration of the form: - // - // var v = x; - // - // is syntactic sugar for: - // - // var v; v = x; - // - // In particular, we need to re-lookup 'v' as it may be a - // different 'v' than the 'v' in the declaration (if we are inside - // a 'with' statement that makes a object property with name 'v' - // visible). - // - // However, note that const declarations are different! A const - // declaration of the form: - // - // const c = x; - // - // is *not* syntactic sugar for: - // - // const c; c = x; - // - // The "variable" c initialized to x is the same as the declared - // one - there is no re-lookup (see the last parameter of the - // Declare() call above). - - Expression* value = NULL; - int position = -1; - if (peek() == Token::ASSIGN) { - Expect(Token::ASSIGN, CHECK_OK); - position = scanner().location().beg_pos; - value = ParseAssignmentExpression(accept_IN, CHECK_OK); - } - - // Make sure that 'const c' actually initializes 'c' to undefined - // even though it seems like a stupid thing to do. - if (value == NULL && is_const) { - value = GetLiteralUndefined(); - } - - // Global variable declarations must be compiled in a specific - // way. When the script containing the global variable declaration - // is entered, the global variable must be declared, so that if it - // doesn't exist (not even in a prototype of the global object) it - // gets created with an initial undefined value. This is handled - // by the declarations part of the function representing the - // top-level global code; see Runtime::DeclareGlobalVariable. If - // it already exists (in the object or in a prototype), it is - // *not* touched until the variable declaration statement is - // executed. - // - // Executing the variable declaration statement will always - // guarantee to give the global object a "local" variable; a - // variable defined in the global object and not in any - // prototype. This way, global variable declarations can shadow - // properties in the prototype chain, but only after the variable - // declaration statement has been executed. This is important in - // browsers where the global object (window) has lots of - // properties defined in prototype objects. - - if (!is_pre_parsing_ && top_scope_->is_global_scope()) { - // Compute the arguments for the runtime call. - ZoneList<Expression*>* arguments = new ZoneList<Expression*>(2); - // Be careful not to assign a value to the global variable if - // we're in a with. The initialization value should not - // necessarily be stored in the global object in that case, - // which is why we need to generate a separate assignment node. - arguments->Add(NEW(Literal(name))); // we have at least 1 parameter - if (is_const || (value != NULL && !inside_with())) { - arguments->Add(value); - value = NULL; // zap the value to avoid the unnecessary assignment - } - // Construct the call to Runtime::DeclareGlobal{Variable,Const}Locally - // and add it to the initialization statement block. Note that - // this function does different things depending on if we have - // 1 or 2 parameters. - CallRuntime* initialize; - if (is_const) { - initialize = - NEW(CallRuntime( - Factory::InitializeConstGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeConstGlobal), - arguments)); - } else { - initialize = - NEW(CallRuntime( - Factory::InitializeVarGlobal_symbol(), - Runtime::FunctionForId(Runtime::kInitializeVarGlobal), - arguments)); - } - block->AddStatement(NEW(ExpressionStatement(initialize))); - } - - // Add an assignment node to the initialization statement block if - // we still have a pending initialization value. We must distinguish - // between variables and constants: Variable initializations are simply - // assignments (with all the consequences if they are inside a 'with' - // statement - they may change a 'with' object property). Constant - // initializations always assign to the declared constant which is - // always at the function scope level. This is only relevant for - // dynamically looked-up variables and constants (the start context - // for constant lookups is always the function context, while it is - // the top context for variables). Sigh... - if (value != NULL) { - Token::Value op = (is_const ? Token::INIT_CONST : Token::INIT_VAR); - Assignment* assignment = NEW(Assignment(op, last_var, value, position)); - if (block) block->AddStatement(NEW(ExpressionStatement(assignment))); - } - } while (peek() == Token::COMMA); - - if (!is_const && nvars == 1) { - // We have a single, non-const variable. - if (is_pre_parsing_) { - // If we're preparsing then we need to set the var to something - // in order for for-in loops to parse correctly. - *var = ValidLeftHandSideSentinel::instance(); - } else { - ASSERT(last_var != NULL); - *var = last_var; - } - } - - return block; -} - - -static bool ContainsLabel(ZoneStringList* labels, Handle<String> label) { - ASSERT(!label.is_null()); - if (labels != NULL) - for (int i = labels->length(); i-- > 0; ) - if (labels->at(i).is_identical_to(label)) - return true; - - return false; -} - - -Statement* Parser::ParseExpressionOrLabelledStatement(ZoneStringList* labels, - bool* ok) { - // ExpressionStatement | LabelledStatement :: - // Expression ';' - // Identifier ':' Statement - - Expression* expr = ParseExpression(true, CHECK_OK); - if (peek() == Token::COLON && expr && - expr->AsVariableProxy() != NULL && - !expr->AsVariableProxy()->is_this()) { - VariableProxy* var = expr->AsVariableProxy(); - Handle<String> label = var->name(); - // TODO(1240780): We don't check for redeclaration of labels - // during preparsing since keeping track of the set of active - // labels requires nontrivial changes to the way scopes are - // structured. However, these are probably changes we want to - // make later anyway so we should go back and fix this then. - if (!is_pre_parsing_) { - if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) { - SmartPointer<char> c_string = label->ToCString(DISALLOW_NULLS); - const char* elms[2] = { "Label", *c_string }; - Vector<const char*> args(elms, 2); - ReportMessage("redeclaration", args); - *ok = false; - return NULL; - } - if (labels == NULL) labels = new ZoneStringList(4); - labels->Add(label); - // Remove the "ghost" variable that turned out to be a label - // from the top scope. This way, we don't try to resolve it - // during the scope processing. - top_scope_->RemoveUnresolved(var); - } - Expect(Token::COLON, CHECK_OK); - return ParseStatement(labels, ok); - } - - // Parsed expression statement. - ExpectSemicolon(CHECK_OK); - return NEW(ExpressionStatement(expr)); -} - - -IfStatement* Parser::ParseIfStatement(ZoneStringList* labels, bool* ok) { - // IfStatement :: - // 'if' '(' Expression ')' Statement ('else' Statement)? - - Expect(Token::IF, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - Expression* condition = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - Statement* then_statement = ParseStatement(labels, CHECK_OK); - Statement* else_statement = NULL; - if (peek() == Token::ELSE) { - Next(); - else_statement = ParseStatement(labels, CHECK_OK); - } else if (!is_pre_parsing_) { - else_statement = factory()->EmptyStatement(); - } - return NEW(IfStatement(condition, then_statement, else_statement)); -} - - -Statement* Parser::ParseContinueStatement(bool* ok) { - // ContinueStatement :: - // 'continue' Identifier? ';' - - Expect(Token::CONTINUE, CHECK_OK); - Handle<String> label = Handle<String>::null(); - Token::Value tok = peek(); - if (!scanner_.has_line_terminator_before_next() && - tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { - label = ParseIdentifier(CHECK_OK); - } - IterationStatement* target = NULL; - if (!is_pre_parsing_) { - target = LookupContinueTarget(label, CHECK_OK); - if (target == NULL) { - // Illegal continue statement. To be consistent with KJS we delay - // reporting of the syntax error until runtime. - Handle<String> error_type = Factory::illegal_continue_symbol(); - if (!label.is_null()) error_type = Factory::unknown_label_symbol(); - Expression* throw_error = NewThrowSyntaxError(error_type, label); - return NEW(ExpressionStatement(throw_error)); - } - } - ExpectSemicolon(CHECK_OK); - return NEW(ContinueStatement(target)); -} - - -Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { - // BreakStatement :: - // 'break' Identifier? ';' - - Expect(Token::BREAK, CHECK_OK); - Handle<String> label; - Token::Value tok = peek(); - if (!scanner_.has_line_terminator_before_next() && - tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { - label = ParseIdentifier(CHECK_OK); - } - // Parse labeled break statements that target themselves into - // empty statements, e.g. 'l1: l2: l3: break l2;' - if (!label.is_null() && ContainsLabel(labels, label)) { - return factory()->EmptyStatement(); - } - BreakableStatement* target = NULL; - if (!is_pre_parsing_) { - target = LookupBreakTarget(label, CHECK_OK); - if (target == NULL) { - // Illegal break statement. To be consistent with KJS we delay - // reporting of the syntax error until runtime. - Handle<String> error_type = Factory::illegal_break_symbol(); - if (!label.is_null()) error_type = Factory::unknown_label_symbol(); - Expression* throw_error = NewThrowSyntaxError(error_type, label); - return NEW(ExpressionStatement(throw_error)); - } - } - ExpectSemicolon(CHECK_OK); - return NEW(BreakStatement(target)); -} - - -Statement* Parser::ParseReturnStatement(bool* ok) { - // ReturnStatement :: - // 'return' Expression? ';' - - // Consume the return token. It is necessary to do the before - // reporting any errors on it, because of the way errors are - // reported (underlining). - Expect(Token::RETURN, CHECK_OK); - - // An ECMAScript program is considered syntactically incorrect if it - // contains a return statement that is not within the body of a - // function. See ECMA-262, section 12.9, page 67. - // - // To be consistent with KJS we report the syntax error at runtime. - if (!is_pre_parsing_ && !top_scope_->is_function_scope()) { - Handle<String> type = Factory::illegal_return_symbol(); - Expression* throw_error = NewThrowSyntaxError(type, Handle<Object>::null()); - return NEW(ExpressionStatement(throw_error)); - } - - Token::Value tok = peek(); - if (scanner_.has_line_terminator_before_next() || - tok == Token::SEMICOLON || - tok == Token::RBRACE || - tok == Token::EOS) { - ExpectSemicolon(CHECK_OK); - return NEW(ReturnStatement(GetLiteralUndefined())); - } - - Expression* expr = ParseExpression(true, CHECK_OK); - ExpectSemicolon(CHECK_OK); - return NEW(ReturnStatement(expr)); -} - - -Block* Parser::WithHelper(Expression* obj, - ZoneStringList* labels, - bool is_catch_block, - bool* ok) { - // Parse the statement and collect escaping labels. - ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0)); - TargetCollector collector(target_list); - Statement* stat; - { Target target(this, &collector); - with_nesting_level_++; - top_scope_->RecordWithStatement(); - stat = ParseStatement(labels, CHECK_OK); - with_nesting_level_--; - } - // Create resulting block with two statements. - // 1: Evaluate the with expression. - // 2: The try-finally block evaluating the body. - Block* result = NEW(Block(NULL, 2, false)); - - if (result != NULL) { - result->AddStatement(NEW(WithEnterStatement(obj, is_catch_block))); - - // Create body block. - Block* body = NEW(Block(NULL, 1, false)); - body->AddStatement(stat); - - // Create exit block. - Block* exit = NEW(Block(NULL, 1, false)); - exit->AddStatement(NEW(WithExitStatement())); - - // Return a try-finally statement. - TryFinally* wrapper = NEW(TryFinally(body, exit)); - wrapper->set_escaping_targets(collector.targets()); - result->AddStatement(wrapper); - } - return result; -} - - -Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) { - // WithStatement :: - // 'with' '(' Expression ')' Statement - - Expect(Token::WITH, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - Expression* expr = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - - return WithHelper(expr, labels, false, CHECK_OK); -} - - -CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) { - // CaseClause :: - // 'case' Expression ':' Statement* - // 'default' ':' Statement* - - Expression* label = NULL; // NULL expression indicates default case - if (peek() == Token::CASE) { - Expect(Token::CASE, CHECK_OK); - label = ParseExpression(true, CHECK_OK); - } else { - Expect(Token::DEFAULT, CHECK_OK); - if (*default_seen_ptr) { - ReportMessage("multiple_defaults_in_switch", - Vector<const char*>::empty()); - *ok = false; - return NULL; - } - *default_seen_ptr = true; - } - Expect(Token::COLON, CHECK_OK); - - ZoneListWrapper<Statement> statements = factory()->NewList<Statement>(5); - while (peek() != Token::CASE && - peek() != Token::DEFAULT && - peek() != Token::RBRACE) { - Statement* stat = ParseStatement(NULL, CHECK_OK); - statements.Add(stat); - } - - return NEW(CaseClause(label, statements.elements())); -} - - -SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels, - bool* ok) { - // SwitchStatement :: - // 'switch' '(' Expression ')' '{' CaseClause* '}' - - SwitchStatement* statement = NEW(SwitchStatement(labels)); - Target target(this, statement); - - Expect(Token::SWITCH, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - Expression* tag = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - - bool default_seen = false; - ZoneListWrapper<CaseClause> cases = factory()->NewList<CaseClause>(4); - Expect(Token::LBRACE, CHECK_OK); - while (peek() != Token::RBRACE) { - CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK); - cases.Add(clause); - } - Expect(Token::RBRACE, CHECK_OK); - - if (statement) statement->Initialize(tag, cases.elements()); - return statement; -} - - -Statement* Parser::ParseThrowStatement(bool* ok) { - // ThrowStatement :: - // 'throw' Expression ';' - - Expect(Token::THROW, CHECK_OK); - int pos = scanner().location().beg_pos; - if (scanner_.has_line_terminator_before_next()) { - ReportMessage("newline_after_throw", Vector<const char*>::empty()); - *ok = false; - return NULL; - } - Expression* exception = ParseExpression(true, CHECK_OK); - ExpectSemicolon(CHECK_OK); - - return NEW(ExpressionStatement(new Throw(exception, pos))); -} - - -TryStatement* Parser::ParseTryStatement(bool* ok) { - // TryStatement :: - // 'try' Block Catch - // 'try' Block Finally - // 'try' Block Catch Finally - // - // Catch :: - // 'catch' '(' Identifier ')' Block - // - // Finally :: - // 'finally' Block - - Expect(Token::TRY, CHECK_OK); - - ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0)); - TargetCollector collector(target_list); - Block* try_block; - - { Target target(this, &collector); - try_block = ParseBlock(NULL, CHECK_OK); - } - - Block* catch_block = NULL; - VariableProxy* catch_var = NULL; - Block* finally_block = NULL; - - Token::Value tok = peek(); - if (tok != Token::CATCH && tok != Token::FINALLY) { - ReportMessage("no_catch_or_finally", Vector<const char*>::empty()); - *ok = false; - return NULL; - } - - // If we can break out from the catch block and there is a finally block, - // then we will need to collect jump targets from the catch block. Since - // we don't know yet if there will be a finally block, we always collect - // the jump targets. - ZoneList<BreakTarget*>* catch_target_list = NEW(ZoneList<BreakTarget*>(0)); - TargetCollector catch_collector(catch_target_list); - bool has_catch = false; - if (tok == Token::CATCH) { - has_catch = true; - Consume(Token::CATCH); - - Expect(Token::LPAREN, CHECK_OK); - Handle<String> name = ParseIdentifier(CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - - if (peek() == Token::LBRACE) { - // Allocate a temporary for holding the finally state while - // executing the finally block. - catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol()); - Literal* name_literal = NEW(Literal(name)); - Expression* obj = NEW(CatchExtensionObject(name_literal, catch_var)); - { Target target(this, &catch_collector); - catch_block = WithHelper(obj, NULL, true, CHECK_OK); - } - } else { - Expect(Token::LBRACE, CHECK_OK); - } - - tok = peek(); - } - - if (tok == Token::FINALLY || !has_catch) { - Consume(Token::FINALLY); - // Declare a variable for holding the finally state while - // executing the finally block. - finally_block = ParseBlock(NULL, CHECK_OK); - } - - // Simplify the AST nodes by converting: - // 'try { } catch { } finally { }' - // to: - // 'try { try { } catch { } } finally { }' - - if (!is_pre_parsing_ && catch_block != NULL && finally_block != NULL) { - TryCatch* statement = NEW(TryCatch(try_block, catch_var, catch_block)); - statement->set_escaping_targets(collector.targets()); - try_block = NEW(Block(NULL, 1, false)); - try_block->AddStatement(statement); - catch_block = NULL; - } - - TryStatement* result = NULL; - if (!is_pre_parsing_) { - if (catch_block != NULL) { - ASSERT(finally_block == NULL); - result = NEW(TryCatch(try_block, catch_var, catch_block)); - result->set_escaping_targets(collector.targets()); - } else { - ASSERT(finally_block != NULL); - result = NEW(TryFinally(try_block, finally_block)); - // Add the jump targets of the try block and the catch block. - for (int i = 0; i < collector.targets()->length(); i++) { - catch_collector.AddTarget(collector.targets()->at(i)); - } - result->set_escaping_targets(catch_collector.targets()); - } - } - - return result; -} - - -LoopStatement* Parser::ParseDoStatement(ZoneStringList* labels, bool* ok) { - // DoStatement :: - // 'do' Statement 'while' '(' Expression ')' ';' - - LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::DO_LOOP)); - Target target(this, loop); - - Expect(Token::DO, CHECK_OK); - Statement* body = ParseStatement(NULL, CHECK_OK); - Expect(Token::WHILE, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - Expression* cond = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - - // Allow do-statements to be terminated with and without - // semi-colons. This allows code such as 'do;while(0)return' to - // parse, which would not be the case if we had used the - // ExpectSemicolon() functionality here. - if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON); - - if (loop) loop->Initialize(NULL, cond, NULL, body); - return loop; -} - - -LoopStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { - // WhileStatement :: - // 'while' '(' Expression ')' Statement - - LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::WHILE_LOOP)); - Target target(this, loop); - - Expect(Token::WHILE, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - Expression* cond = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - Statement* body = ParseStatement(NULL, CHECK_OK); - - if (loop) loop->Initialize(NULL, cond, NULL, body); - return loop; -} - - -Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { - // ForStatement :: - // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement - - Statement* init = NULL; - - Expect(Token::FOR, CHECK_OK); - Expect(Token::LPAREN, CHECK_OK); - if (peek() != Token::SEMICOLON) { - if (peek() == Token::VAR || peek() == Token::CONST) { - Expression* each = NULL; - Block* variable_statement = - ParseVariableDeclarations(false, &each, CHECK_OK); - if (peek() == Token::IN && each != NULL) { - ForInStatement* loop = NEW(ForInStatement(labels)); - Target target(this, loop); - - Expect(Token::IN, CHECK_OK); - Expression* enumerable = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - - Statement* body = ParseStatement(NULL, CHECK_OK); - if (is_pre_parsing_) { - return NULL; - } else { - loop->Initialize(each, enumerable, body); - Block* result = NEW(Block(NULL, 2, false)); - result->AddStatement(variable_statement); - result->AddStatement(loop); - // Parsed for-in loop w/ variable/const declaration. - return result; - } - - } else { - init = variable_statement; - } - - } else { - Expression* expression = ParseExpression(false, CHECK_OK); - if (peek() == Token::IN) { - // Signal a reference error if the expression is an invalid - // left-hand side expression. We could report this as a syntax - // error here but for compatibility with JSC we choose to report - // the error at runtime. - if (expression == NULL || !expression->IsValidLeftHandSide()) { - Handle<String> type = Factory::invalid_lhs_in_for_in_symbol(); - expression = NewThrowReferenceError(type); - } - ForInStatement* loop = NEW(ForInStatement(labels)); - Target target(this, loop); - - Expect(Token::IN, CHECK_OK); - Expression* enumerable = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - - Statement* body = ParseStatement(NULL, CHECK_OK); - if (loop) loop->Initialize(expression, enumerable, body); - - // Parsed for-in loop. - return loop; - - } else { - init = NEW(ExpressionStatement(expression)); - } - } - } - - // Standard 'for' loop - LoopStatement* loop = NEW(LoopStatement(labels, LoopStatement::FOR_LOOP)); - Target target(this, loop); - - // Parsed initializer at this point. - Expect(Token::SEMICOLON, CHECK_OK); - - Expression* cond = NULL; - if (peek() != Token::SEMICOLON) { - cond = ParseExpression(true, CHECK_OK); - } - Expect(Token::SEMICOLON, CHECK_OK); - - Statement* next = NULL; - if (peek() != Token::RPAREN) { - Expression* exp = ParseExpression(true, CHECK_OK); - next = NEW(ExpressionStatement(exp)); - } - Expect(Token::RPAREN, CHECK_OK); - - Statement* body = ParseStatement(NULL, CHECK_OK); - - if (loop) loop->Initialize(init, cond, next, body); - return loop; -} - - -// Precedence = 1 -Expression* Parser::ParseExpression(bool accept_IN, bool* ok) { - // Expression :: - // AssignmentExpression - // Expression ',' AssignmentExpression - - Expression* result = ParseAssignmentExpression(accept_IN, CHECK_OK); - while (peek() == Token::COMMA) { - Expect(Token::COMMA, CHECK_OK); - Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - result = NEW(BinaryOperation(Token::COMMA, result, right)); - } - return result; -} - - -// Precedence = 2 -Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { - // AssignmentExpression :: - // ConditionalExpression - // LeftHandSideExpression AssignmentOperator AssignmentExpression - - Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK); - - if (!Token::IsAssignmentOp(peek())) { - // Parsed conditional expression only (no assignment). - return expression; - } - - // Signal a reference error if the expression is an invalid left-hand - // side expression. We could report this as a syntax error here but - // for compatibility with JSC we choose to report the error at - // runtime. - if (expression == NULL || !expression->IsValidLeftHandSide()) { - Handle<String> type = Factory::invalid_lhs_in_assignment_symbol(); - expression = NewThrowReferenceError(type); - } - - Token::Value op = Next(); // Get assignment operator. - int pos = scanner().location().beg_pos; - Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - - // TODO(1231235): We try to estimate the set of properties set by - // constructors. We define a new property whenever there is an - // assignment to a property of 'this'. We should probably only add - // properties if we haven't seen them before. Otherwise we'll - // probably overestimate the number of properties. - Property* property = expression ? expression->AsProperty() : NULL; - if (op == Token::ASSIGN && - property != NULL && - property->obj()->AsVariableProxy() != NULL && - property->obj()->AsVariableProxy()->is_this()) { - temp_scope_->AddProperty(); - } - - return NEW(Assignment(op, expression, right, pos)); -} - - -// Precedence = 3 -Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) { - // ConditionalExpression :: - // LogicalOrExpression - // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression - - // We start using the binary expression parser for prec >= 4 only! - Expression* expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); - if (peek() != Token::CONDITIONAL) return expression; - Consume(Token::CONDITIONAL); - // In parsing the first assignment expression in conditional - // expressions we always accept the 'in' keyword; see ECMA-262, - // section 11.12, page 58. - Expression* left = ParseAssignmentExpression(true, CHECK_OK); - Expect(Token::COLON, CHECK_OK); - Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK); - return NEW(Conditional(expression, left, right)); -} - - -static int Precedence(Token::Value tok, bool accept_IN) { - if (tok == Token::IN && !accept_IN) - return 0; // 0 precedence will terminate binary expression parsing - - return Token::Precedence(tok); -} - - -// Precedence >= 4 -Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { - ASSERT(prec >= 4); - Expression* x = ParseUnaryExpression(CHECK_OK); - for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { - // prec1 >= 4 - while (Precedence(peek(), accept_IN) == prec1) { - Token::Value op = Next(); - Expression* y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK); - - // Compute some expressions involving only number literals. - if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber() && - y && y->AsLiteral() && y->AsLiteral()->handle()->IsNumber()) { - double x_val = x->AsLiteral()->handle()->Number(); - double y_val = y->AsLiteral()->handle()->Number(); - - switch (op) { - case Token::ADD: - x = NewNumberLiteral(x_val + y_val); - continue; - case Token::SUB: - x = NewNumberLiteral(x_val - y_val); - continue; - case Token::MUL: - x = NewNumberLiteral(x_val * y_val); - continue; - case Token::DIV: - x = NewNumberLiteral(x_val / y_val); - continue; - case Token::BIT_OR: - x = NewNumberLiteral(DoubleToInt32(x_val) | DoubleToInt32(y_val)); - continue; - case Token::BIT_AND: - x = NewNumberLiteral(DoubleToInt32(x_val) & DoubleToInt32(y_val)); - continue; - case Token::BIT_XOR: - x = NewNumberLiteral(DoubleToInt32(x_val) ^ DoubleToInt32(y_val)); - continue; - case Token::SHL: { - int value = DoubleToInt32(x_val) << (DoubleToInt32(y_val) & 0x1f); - x = NewNumberLiteral(value); - continue; - } - case Token::SHR: { - uint32_t shift = DoubleToInt32(y_val) & 0x1f; - uint32_t value = DoubleToUint32(x_val) >> shift; - x = NewNumberLiteral(value); - continue; - } - case Token::SAR: { - uint32_t shift = DoubleToInt32(y_val) & 0x1f; - int value = ArithmeticShiftRight(DoubleToInt32(x_val), shift); - x = NewNumberLiteral(value); - continue; - } - default: - break; - } - } - - // Convert constant divisions to multiplications for speed. - if (op == Token::DIV && - y && y->AsLiteral() && y->AsLiteral()->handle()->IsNumber()) { - double y_val = y->AsLiteral()->handle()->Number(); - int64_t y_int = static_cast<int64_t>(y_val); - // There are rounding issues with this optimization, but they don't - // apply if the number to be divided with has a reciprocal that can be - // precisely represented as a floating point number. This is the case - // if the number is an integer power of 2. Negative integer powers of - // 2 work too, but for -2, -1, 1 and 2 we don't do the strength - // reduction because the inlined optimistic idiv has a reasonable - // chance of succeeding by producing a Smi answer with no remainder. - if (static_cast<double>(y_int) == y_val && - (IsPowerOf2(y_int) || IsPowerOf2(-y_int)) && - (y_int > 2 || y_int < -2)) { - y = NewNumberLiteral(1 / y_val); - op = Token::MUL; - } - } - - // For now we distinguish between comparisons and other binary - // operations. (We could combine the two and get rid of this - // code an AST node eventually.) - if (Token::IsCompareOp(op)) { - // We have a comparison. - Token::Value cmp = op; - switch (op) { - case Token::NE: cmp = Token::EQ; break; - case Token::NE_STRICT: cmp = Token::EQ_STRICT; break; - default: break; - } - x = NEW(CompareOperation(cmp, x, y)); - if (cmp != op) { - // The comparison was negated - add a NOT. - x = NEW(UnaryOperation(Token::NOT, x)); - } - - } else { - // We have a "normal" binary operation. - x = NEW(BinaryOperation(op, x, y)); - } - } - } - return x; -} - - -Expression* Parser::ParseUnaryExpression(bool* ok) { - // UnaryExpression :: - // PostfixExpression - // 'delete' UnaryExpression - // 'void' UnaryExpression - // 'typeof' UnaryExpression - // '++' UnaryExpression - // '--' UnaryExpression - // '+' UnaryExpression - // '-' UnaryExpression - // '~' UnaryExpression - // '!' UnaryExpression - - Token::Value op = peek(); - if (Token::IsUnaryOp(op)) { - op = Next(); - Expression* expression = ParseUnaryExpression(CHECK_OK); - - // Compute some expressions involving only number literals. - if (expression != NULL && expression->AsLiteral() && - expression->AsLiteral()->handle()->IsNumber()) { - double value = expression->AsLiteral()->handle()->Number(); - switch (op) { - case Token::ADD: - return expression; - case Token::SUB: - return NewNumberLiteral(-value); - case Token::BIT_NOT: - return NewNumberLiteral(~DoubleToInt32(value)); - default: break; - } - } - - return NEW(UnaryOperation(op, expression)); - - } else if (Token::IsCountOp(op)) { - op = Next(); - Expression* expression = ParseUnaryExpression(CHECK_OK); - // Signal a reference error if the expression is an invalid - // left-hand side expression. We could report this as a syntax - // error here but for compatibility with JSC we choose to report the - // error at runtime. - if (expression == NULL || !expression->IsValidLeftHandSide()) { - Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol(); - expression = NewThrowReferenceError(type); - } - return NEW(CountOperation(true /* prefix */, op, expression)); - - } else { - return ParsePostfixExpression(ok); - } -} - - -Expression* Parser::ParsePostfixExpression(bool* ok) { - // PostfixExpression :: - // LeftHandSideExpression ('++' | '--')? - - Expression* expression = ParseLeftHandSideExpression(CHECK_OK); - if (!scanner_.has_line_terminator_before_next() && Token::IsCountOp(peek())) { - // Signal a reference error if the expression is an invalid - // left-hand side expression. We could report this as a syntax - // error here but for compatibility with JSC we choose to report the - // error at runtime. - if (expression == NULL || !expression->IsValidLeftHandSide()) { - Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol(); - expression = NewThrowReferenceError(type); - } - Token::Value next = Next(); - expression = NEW(CountOperation(false /* postfix */, next, expression)); - } - return expression; -} - - -Expression* Parser::ParseLeftHandSideExpression(bool* ok) { - // LeftHandSideExpression :: - // (NewExpression | MemberExpression) ... - - Expression* result; - if (peek() == Token::NEW) { - result = ParseNewExpression(CHECK_OK); - } else { - result = ParseMemberExpression(CHECK_OK); - } - - while (true) { - switch (peek()) { - case Token::LBRACK: { - Consume(Token::LBRACK); - int pos = scanner().location().beg_pos; - Expression* index = ParseExpression(true, CHECK_OK); - result = factory()->NewProperty(result, index, pos); - Expect(Token::RBRACK, CHECK_OK); - break; - } - - case Token::LPAREN: { - int pos = scanner().location().beg_pos; - ZoneList<Expression*>* args = ParseArguments(CHECK_OK); - - // Keep track of eval() calls since they disable all local variable - // optimizations. - // The calls that need special treatment are the - // direct (i.e. not aliased) eval calls. These calls are all of the - // form eval(...) with no explicit receiver object where eval is not - // declared in the current scope chain. These calls are marked as - // potentially direct eval calls. Whether they are actually direct calls - // to eval is determined at run time. - if (!is_pre_parsing_) { - VariableProxy* callee = result->AsVariableProxy(); - if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) { - Handle<String> name = callee->name(); - Variable* var = top_scope_->Lookup(name); - if (var == NULL) { - top_scope_->RecordEvalCall(); - } - } - } - result = factory()->NewCall(result, args, pos); - break; - } - - case Token::PERIOD: { - Consume(Token::PERIOD); - int pos = scanner().location().beg_pos; - Handle<String> name = ParseIdentifier(CHECK_OK); - result = factory()->NewProperty(result, NEW(Literal(name)), pos); - break; - } - - default: - return result; - } - } -} - - - -Expression* Parser::ParseNewPrefix(PositionStack* stack, bool* ok) { - // NewExpression :: - // ('new')+ MemberExpression - - // The grammar for new expressions is pretty warped. The keyword - // 'new' can either be a part of the new expression (where it isn't - // followed by an argument list) or a part of the member expression, - // where it must be followed by an argument list. To accommodate - // this, we parse the 'new' keywords greedily and keep track of how - // many we have parsed. This information is then passed on to the - // member expression parser, which is only allowed to match argument - // lists as long as it has 'new' prefixes left - Expect(Token::NEW, CHECK_OK); - PositionStack::Element pos(stack, scanner().location().beg_pos); - - Expression* result; - if (peek() == Token::NEW) { - result = ParseNewPrefix(stack, CHECK_OK); - } else { - result = ParseMemberWithNewPrefixesExpression(stack, CHECK_OK); - } - - if (!stack->is_empty()) { - int last = stack->pop(); - result = NEW(CallNew(result, new ZoneList<Expression*>(0), last)); - } - return result; -} - - -Expression* Parser::ParseNewExpression(bool* ok) { - PositionStack stack(ok); - return ParseNewPrefix(&stack, ok); -} - - -Expression* Parser::ParseMemberExpression(bool* ok) { - return ParseMemberWithNewPrefixesExpression(NULL, ok); -} - - -Expression* Parser::ParseMemberWithNewPrefixesExpression(PositionStack* stack, - bool* ok) { - // MemberExpression :: - // (PrimaryExpression | FunctionLiteral) - // ('[' Expression ']' | '.' Identifier | Arguments)* - - // Parse the initial primary or function expression. - Expression* result = NULL; - if (peek() == Token::FUNCTION) { - Expect(Token::FUNCTION, CHECK_OK); - int function_token_position = scanner().location().beg_pos; - Handle<String> name; - if (peek() == Token::IDENTIFIER) name = ParseIdentifier(CHECK_OK); - result = ParseFunctionLiteral(name, function_token_position, - NESTED, CHECK_OK); - } else { - result = ParsePrimaryExpression(CHECK_OK); - } - - while (true) { - switch (peek()) { - case Token::LBRACK: { - Consume(Token::LBRACK); - int pos = scanner().location().beg_pos; - Expression* index = ParseExpression(true, CHECK_OK); - result = factory()->NewProperty(result, index, pos); - Expect(Token::RBRACK, CHECK_OK); - break; - } - case Token::PERIOD: { - Consume(Token::PERIOD); - int pos = scanner().location().beg_pos; - Handle<String> name = ParseIdentifier(CHECK_OK); - result = factory()->NewProperty(result, NEW(Literal(name)), pos); - break; - } - case Token::LPAREN: { - if ((stack == NULL) || stack->is_empty()) return result; - // Consume one of the new prefixes (already parsed). - ZoneList<Expression*>* args = ParseArguments(CHECK_OK); - int last = stack->pop(); - result = NEW(CallNew(result, args, last)); - break; - } - default: - return result; - } - } -} - - -DebuggerStatement* Parser::ParseDebuggerStatement(bool* ok) { - // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser - // contexts this is used as a statement which invokes the debugger as i a - // break point is present. - // DebuggerStatement :: - // 'debugger' ';' - - Expect(Token::DEBUGGER, CHECK_OK); - ExpectSemicolon(CHECK_OK); - return NEW(DebuggerStatement()); -} - - -void Parser::ReportUnexpectedToken(Token::Value token) { - // We don't report stack overflows here, to avoid increasing the - // stack depth even further. Instead we report it after parsing is - // over, in ParseProgram. - if (token == Token::ILLEGAL && scanner().stack_overflow()) - return; - // Four of the tokens are treated specially - switch (token) { - case Token::EOS: - return ReportMessage("unexpected_eos", Vector<const char*>::empty()); - case Token::NUMBER: - return ReportMessage("unexpected_token_number", - Vector<const char*>::empty()); - case Token::STRING: - return ReportMessage("unexpected_token_string", - Vector<const char*>::empty()); - case Token::IDENTIFIER: - return ReportMessage("unexpected_token_identifier", - Vector<const char*>::empty()); - default: - const char* name = Token::String(token); - ASSERT(name != NULL); - ReportMessage("unexpected_token", Vector<const char*>(&name, 1)); - } -} - - -Expression* Parser::ParsePrimaryExpression(bool* ok) { - // PrimaryExpression :: - // 'this' - // 'null' - // 'true' - // 'false' - // Identifier - // Number - // String - // ArrayLiteral - // ObjectLiteral - // RegExpLiteral - // '(' Expression ')' - - Expression* result = NULL; - switch (peek()) { - case Token::THIS: { - Consume(Token::THIS); - if (is_pre_parsing_) { - result = VariableProxySentinel::this_proxy(); - } else { - VariableProxy* recv = top_scope_->receiver(); - recv->var_uses()->RecordRead(1); - result = recv; - } - break; - } - - case Token::NULL_LITERAL: - Consume(Token::NULL_LITERAL); - result = NEW(Literal(Factory::null_value())); - break; - - case Token::TRUE_LITERAL: - Consume(Token::TRUE_LITERAL); - result = NEW(Literal(Factory::true_value())); - break; - - case Token::FALSE_LITERAL: - Consume(Token::FALSE_LITERAL); - result = NEW(Literal(Factory::false_value())); - break; - - case Token::IDENTIFIER: { - Handle<String> name = ParseIdentifier(CHECK_OK); - if (is_pre_parsing_) { - result = VariableProxySentinel::identifier_proxy(); - } else { - result = top_scope_->NewUnresolved(name, inside_with()); - } - break; - } - - case Token::NUMBER: { - Consume(Token::NUMBER); - double value = - StringToDouble(scanner_.literal_string(), ALLOW_HEX | ALLOW_OCTALS); - result = NewNumberLiteral(value); - break; - } - - case Token::STRING: { - Consume(Token::STRING); - Handle<String> symbol = - factory()->LookupSymbol(scanner_.literal_string(), - scanner_.literal_length()); - result = NEW(Literal(symbol)); - break; - } - - case Token::ASSIGN_DIV: - result = ParseRegExpLiteral(true, CHECK_OK); - break; - - case Token::DIV: - result = ParseRegExpLiteral(false, CHECK_OK); - break; - - case Token::LBRACK: - result = ParseArrayLiteral(CHECK_OK); - break; - - case Token::LBRACE: - result = ParseObjectLiteral(CHECK_OK); - break; - - case Token::LPAREN: - Consume(Token::LPAREN); - result = ParseExpression(true, CHECK_OK); - Expect(Token::RPAREN, CHECK_OK); - break; - - case Token::MOD: - if (allow_natives_syntax_ || extension_ != NULL) { - result = ParseV8Intrinsic(CHECK_OK); - break; - } - // If we're not allowing special syntax we fall-through to the - // default case. - - default: { - Token::Value tok = peek(); - // Token::Peek returns the value of the next token but - // location() gives info about the current token. - // Therefore, we need to read ahead to the next token - Next(); - ReportUnexpectedToken(tok); - *ok = false; - return NULL; - } - } - - return result; -} - - -Expression* Parser::ParseArrayLiteral(bool* ok) { - // ArrayLiteral :: - // '[' Expression? (',' Expression?)* ']' - - ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4); - Expect(Token::LBRACK, CHECK_OK); - while (peek() != Token::RBRACK) { - Expression* elem; - if (peek() == Token::COMMA) { - elem = GetLiteralTheHole(); - } else { - elem = ParseAssignmentExpression(true, CHECK_OK); - } - values.Add(elem); - if (peek() != Token::RBRACK) { - Expect(Token::COMMA, CHECK_OK); - } - } - Expect(Token::RBRACK, CHECK_OK); - - // Update the scope information before the pre-parsing bailout. - temp_scope_->set_contains_array_literal(); - int literal_index = temp_scope_->NextMaterializedLiteralIndex(); - - if (is_pre_parsing_) return NULL; - - // Allocate a fixed array with all the literals. - Handle<FixedArray> literals = - Factory::NewFixedArray(values.length(), TENURED); - - // Fill in the literals. - bool is_simple = true; - int depth = 1; - for (int i = 0; i < values.length(); i++) { - MaterializedLiteral* m_literal = values.at(i)->AsMaterializedLiteral(); - if (m_literal != NULL && m_literal->depth() + 1 > depth) { - depth = m_literal->depth() + 1; - } - Handle<Object> boilerplate_value = GetBoilerplateValue(values.at(i)); - if (boilerplate_value->IsUndefined()) { - literals->set_the_hole(i); - is_simple = false; - } else { - literals->set(i, *boilerplate_value); - } - } - - return NEW(ArrayLiteral(literals, values.elements(), - literal_index, is_simple, depth)); -} - - -bool Parser::IsBoilerplateProperty(ObjectLiteral::Property* property) { - return property != NULL && - property->kind() != ObjectLiteral::Property::PROTOTYPE; -} - - -bool CompileTimeValue::IsCompileTimeValue(Expression* expression) { - MaterializedLiteral* lit = expression->AsMaterializedLiteral(); - return lit != NULL && lit->is_simple(); -} - -Handle<FixedArray> CompileTimeValue::GetValue(Expression* expression) { - ASSERT(IsCompileTimeValue(expression)); - Handle<FixedArray> result = Factory::NewFixedArray(2, TENURED); - ObjectLiteral* object_literal = expression->AsObjectLiteral(); - if (object_literal != NULL) { - ASSERT(object_literal->is_simple()); - result->set(kTypeSlot, Smi::FromInt(OBJECT_LITERAL)); - result->set(kElementsSlot, *object_literal->constant_properties()); - } else { - ArrayLiteral* array_literal = expression->AsArrayLiteral(); - ASSERT(array_literal != NULL && array_literal->is_simple()); - result->set(kTypeSlot, Smi::FromInt(ARRAY_LITERAL)); - result->set(kElementsSlot, *array_literal->literals()); - } - return result; -} - - -CompileTimeValue::Type CompileTimeValue::GetType(Handle<FixedArray> value) { - Smi* type_value = Smi::cast(value->get(kTypeSlot)); - return static_cast<Type>(type_value->value()); -} - - -Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) { - return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot))); -} - - -Handle<Object> Parser::GetBoilerplateValue(Expression* expression) { - if (expression->AsLiteral() != NULL) { - return expression->AsLiteral()->handle(); - } - if (CompileTimeValue::IsCompileTimeValue(expression)) { - return CompileTimeValue::GetValue(expression); - } - return Factory::undefined_value(); -} - - -Expression* Parser::ParseObjectLiteral(bool* ok) { - // ObjectLiteral :: - // '{' ( - // ((Identifier | String | Number) ':' AssignmentExpression) - // | (('get' | 'set') FunctionLiteral) - // )*[','] '}' - - ZoneListWrapper<ObjectLiteral::Property> properties = - factory()->NewList<ObjectLiteral::Property>(4); - int number_of_boilerplate_properties = 0; - - Expect(Token::LBRACE, CHECK_OK); - while (peek() != Token::RBRACE) { - Literal* key = NULL; - switch (peek()) { - case Token::IDENTIFIER: { - // Store identifier keys as literal symbols to avoid - // resolving them when compiling code for the object - // literal. - bool is_getter = false; - bool is_setter = false; - Handle<String> id = - ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK); - if (is_getter || is_setter) { - // Special handling of getter and setter syntax. - if (peek() == Token::IDENTIFIER) { - Handle<String> name = ParseIdentifier(CHECK_OK); - FunctionLiteral* value = - ParseFunctionLiteral(name, RelocInfo::kNoPosition, - DECLARATION, CHECK_OK); - ObjectLiteral::Property* property = - NEW(ObjectLiteral::Property(is_getter, value)); - if (IsBoilerplateProperty(property)) - number_of_boilerplate_properties++; - properties.Add(property); - if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); - continue; // restart the while - } - } - key = NEW(Literal(id)); - break; - } - - case Token::STRING: { - Consume(Token::STRING); - Handle<String> string = - factory()->LookupSymbol(scanner_.literal_string(), - scanner_.literal_length()); - uint32_t index; - if (!string.is_null() && string->AsArrayIndex(&index)) { - key = NewNumberLiteral(index); - } else { - key = NEW(Literal(string)); - } - break; - } - - case Token::NUMBER: { - Consume(Token::NUMBER); - double value = - StringToDouble(scanner_.literal_string(), ALLOW_HEX | ALLOW_OCTALS); - key = NewNumberLiteral(value); - break; - } - - default: - Expect(Token::RBRACE, CHECK_OK); - break; - } - - Expect(Token::COLON, CHECK_OK); - Expression* value = ParseAssignmentExpression(true, CHECK_OK); - - ObjectLiteral::Property* property = - NEW(ObjectLiteral::Property(key, value)); - - // Count CONSTANT or COMPUTED properties to maintain the enumeration order. - if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++; - properties.Add(property); - - // TODO(1240767): Consider allowing trailing comma. - if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); - } - Expect(Token::RBRACE, CHECK_OK); - // Computation of literal_index must happen before pre parse bailout. - int literal_index = temp_scope_->NextMaterializedLiteralIndex(); - if (is_pre_parsing_) return NULL; - - Handle<FixedArray> constant_properties = - Factory::NewFixedArray(number_of_boilerplate_properties * 2, TENURED); - int position = 0; - bool is_simple = true; - int depth = 1; - for (int i = 0; i < properties.length(); i++) { - ObjectLiteral::Property* property = properties.at(i); - if (!IsBoilerplateProperty(property)) { - is_simple = false; - continue; - } - MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); - if (m_literal != NULL && m_literal->depth() + 1 > depth) { - depth = m_literal->depth() + 1; - } - - // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined - // value for COMPUTED properties, the real value is filled in at - // runtime. The enumeration order is maintained. - Handle<Object> key = property->key()->handle(); - Handle<Object> value = GetBoilerplateValue(property->value()); - is_simple = is_simple && !value->IsUndefined(); - - // Add name, value pair to the fixed array. - constant_properties->set(position++, *key); - constant_properties->set(position++, *value); - } - - return new ObjectLiteral(constant_properties, - properties.elements(), - literal_index, - is_simple, - depth); -} - - -Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { - if (!scanner_.ScanRegExpPattern(seen_equal)) { - Next(); - ReportMessage("unterminated_regexp", Vector<const char*>::empty()); - *ok = false; - return NULL; - } - - int literal_index = temp_scope_->NextMaterializedLiteralIndex(); - - if (is_pre_parsing_) { - // If we're preparsing we just do all the parsing stuff without - // building anything. - if (!scanner_.ScanRegExpFlags()) { - Next(); - ReportMessage("invalid_regexp_flags", Vector<const char*>::empty()); - *ok = false; - return NULL; - } - Next(); - return NULL; - } - - Handle<String> js_pattern = - Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED); - scanner_.ScanRegExpFlags(); - Handle<String> js_flags = - Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED); - Next(); - - return new RegExpLiteral(js_pattern, js_flags, literal_index); -} - - -ZoneList<Expression*>* Parser::ParseArguments(bool* ok) { - // Arguments :: - // '(' (AssignmentExpression)*[','] ')' - - ZoneListWrapper<Expression> result = factory()->NewList<Expression>(4); - Expect(Token::LPAREN, CHECK_OK); - bool done = (peek() == Token::RPAREN); - while (!done) { - Expression* argument = ParseAssignmentExpression(true, CHECK_OK); - result.Add(argument); - done = (peek() == Token::RPAREN); - if (!done) Expect(Token::COMMA, CHECK_OK); - } - Expect(Token::RPAREN, CHECK_OK); - return result.elements(); -} - - -FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, - int function_token_position, - FunctionLiteralType type, - bool* ok) { - // Function :: - // '(' FormalParameterList? ')' '{' FunctionBody '}' - - bool is_named = !var_name.is_null(); - - // The name associated with this function. If it's a function expression, - // this is the actual function name, otherwise this is the name of the - // variable declared and initialized with the function (expression). In - // that case, we don't have a function name (it's empty). - Handle<String> name = is_named ? var_name : factory()->EmptySymbol(); - // The function name, if any. - Handle<String> function_name = factory()->EmptySymbol(); - if (is_named && (type == EXPRESSION || type == NESTED)) { - function_name = name; - } - - int num_parameters = 0; - // Parse function body. - { Scope::Type type = Scope::FUNCTION_SCOPE; - Scope* scope = factory()->NewScope(top_scope_, type, inside_with()); - LexicalScope lexical_scope(this, scope); - TemporaryScope temp_scope(this); - top_scope_->SetScopeName(name); - - // FormalParameterList :: - // '(' (Identifier)*[','] ')' - Expect(Token::LPAREN, CHECK_OK); - int start_pos = scanner_.location().beg_pos; - bool done = (peek() == Token::RPAREN); - while (!done) { - Handle<String> param_name = ParseIdentifier(CHECK_OK); - if (!is_pre_parsing_) { - top_scope_->AddParameter(top_scope_->DeclareLocal(param_name, - Variable::VAR)); - num_parameters++; - } - done = (peek() == Token::RPAREN); - if (!done) Expect(Token::COMMA, CHECK_OK); - } - Expect(Token::RPAREN, CHECK_OK); - - Expect(Token::LBRACE, CHECK_OK); - ZoneListWrapper<Statement> body = factory()->NewList<Statement>(8); - - // If we have a named function expression, we add a local variable - // declaration to the body of the function with the name of the - // function and let it refer to the function itself (closure). - // NOTE: We create a proxy and resolve it here so that in the - // future we can change the AST to only refer to VariableProxies - // instead of Variables and Proxis as is the case now. - if (!function_name.is_null() && function_name->length() > 0) { - Variable* fvar = top_scope_->DeclareFunctionVar(function_name); - VariableProxy* fproxy = - top_scope_->NewUnresolved(function_name, inside_with()); - fproxy->BindTo(fvar); - body.Add(new ExpressionStatement( - new Assignment(Token::INIT_VAR, fproxy, - NEW(ThisFunction()), - RelocInfo::kNoPosition))); - } - - // Determine if the function will be lazily compiled. The mode can - // only be PARSE_LAZILY if the --lazy flag is true. - bool is_lazily_compiled = - mode() == PARSE_LAZILY && top_scope_->HasTrivialOuterContext(); - - int materialized_literal_count; - int expected_property_count; - bool contains_array_literal; - bool only_this_property_assignments; - bool only_simple_this_property_assignments; - Handle<FixedArray> this_property_assignments; - if (is_lazily_compiled && pre_data() != NULL) { - FunctionEntry entry = pre_data()->GetFunctionEnd(start_pos); - int end_pos = entry.end_pos(); - Counters::total_preparse_skipped.Increment(end_pos - start_pos); - scanner_.SeekForward(end_pos); - materialized_literal_count = entry.literal_count(); - expected_property_count = entry.property_count(); - only_this_property_assignments = false; - only_simple_this_property_assignments = false; - this_property_assignments = Factory::empty_fixed_array(); - contains_array_literal = entry.contains_array_literal(); - } else { - ParseSourceElements(&body, Token::RBRACE, CHECK_OK); - materialized_literal_count = temp_scope.materialized_literal_count(); - expected_property_count = temp_scope.expected_property_count(); - contains_array_literal = temp_scope.contains_array_literal(); - only_this_property_assignments = - temp_scope.only_this_property_assignments(); - only_simple_this_property_assignments = - temp_scope.only_simple_this_property_assignments(); - this_property_assignments = temp_scope.this_property_assignments(); - } - - Expect(Token::RBRACE, CHECK_OK); - int end_pos = scanner_.location().end_pos; - - FunctionEntry entry = log()->LogFunction(start_pos); - if (entry.is_valid()) { - entry.set_end_pos(end_pos); - entry.set_literal_count(materialized_literal_count); - entry.set_property_count(expected_property_count); - entry.set_contains_array_literal(contains_array_literal); - } - - FunctionLiteral* function_literal = - NEW(FunctionLiteral(name, - top_scope_, - body.elements(), - materialized_literal_count, - contains_array_literal, - expected_property_count, - only_this_property_assignments, - only_simple_this_property_assignments, - this_property_assignments, - num_parameters, - start_pos, - end_pos, - function_name->length() > 0)); - if (!is_pre_parsing_) { - function_literal->set_function_token_position(function_token_position); - } - return function_literal; - } -} - - -Expression* Parser::ParseV8Intrinsic(bool* ok) { - // CallRuntime :: - // '%' Identifier Arguments - - Expect(Token::MOD, CHECK_OK); - Handle<String> name = ParseIdentifier(CHECK_OK); - Runtime::Function* function = - Runtime::FunctionForName(scanner_.literal_string()); - ZoneList<Expression*>* args = ParseArguments(CHECK_OK); - if (function == NULL && extension_ != NULL) { - // The extension structures are only accessible while parsing the - // very first time not when reparsing because of lazy compilation. - top_scope_->ForceEagerCompilation(); - } - - // Check for built-in macros. - if (!is_pre_parsing_) { - if (function == Runtime::FunctionForId(Runtime::kIS_VAR)) { - // %IS_VAR(x) - // evaluates to x if x is a variable, - // leads to a parse error otherwise - if (args->length() == 1 && args->at(0)->AsVariableProxy() != NULL) { - return args->at(0); - } - *ok = false; - // Check here for other macros. - // } else if (function == Runtime::FunctionForId(Runtime::kIS_VAR)) { - // ... - } - - if (!*ok) { - // We found a macro but it failed. - ReportMessage("unable_to_parse", Vector<const char*>::empty()); - return NULL; - } - } - - // Otherwise we have a runtime call. - return NEW(CallRuntime(name, function, args)); -} - - -void Parser::Consume(Token::Value token) { - Token::Value next = Next(); - USE(next); - USE(token); - ASSERT(next == token); -} - - -void Parser::Expect(Token::Value token, bool* ok) { - Token::Value next = Next(); - if (next == token) return; - ReportUnexpectedToken(next); - *ok = false; -} - - -void Parser::ExpectSemicolon(bool* ok) { - // Check for automatic semicolon insertion according to - // the rules given in ECMA-262, section 7.9, page 21. - Token::Value tok = peek(); - if (tok == Token::SEMICOLON) { - Next(); - return; - } - if (scanner_.has_line_terminator_before_next() || - tok == Token::RBRACE || - tok == Token::EOS) { - return; - } - Expect(Token::SEMICOLON, ok); -} - - -Literal* Parser::GetLiteralUndefined() { - return NEW(Literal(Factory::undefined_value())); -} - - -Literal* Parser::GetLiteralTheHole() { - return NEW(Literal(Factory::the_hole_value())); -} - - -Literal* Parser::GetLiteralNumber(double value) { - return NewNumberLiteral(value); -} - - -Handle<String> Parser::ParseIdentifier(bool* ok) { - Expect(Token::IDENTIFIER, ok); - if (!*ok) return Handle<String>(); - return factory()->LookupSymbol(scanner_.literal_string(), - scanner_.literal_length()); -} - -// This function reads an identifier and determines whether or not it -// is 'get' or 'set'. The reason for not using ParseIdentifier and -// checking on the output is that this involves heap allocation which -// we can't do during preparsing. -Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get, - bool* is_set, - bool* ok) { - Expect(Token::IDENTIFIER, ok); - if (!*ok) return Handle<String>(); - if (scanner_.literal_length() == 3) { - const char* token = scanner_.literal_string(); - *is_get = strcmp(token, "get") == 0; - *is_set = !*is_get && strcmp(token, "set") == 0; - } - return factory()->LookupSymbol(scanner_.literal_string(), - scanner_.literal_length()); -} - - -// ---------------------------------------------------------------------------- -// Parser support - - -bool Parser::TargetStackContainsLabel(Handle<String> label) { - for (Target* t = target_stack_; t != NULL; t = t->previous()) { - BreakableStatement* stat = t->node()->AsBreakableStatement(); - if (stat != NULL && ContainsLabel(stat->labels(), label)) - return true; - } - return false; -} - - -BreakableStatement* Parser::LookupBreakTarget(Handle<String> label, bool* ok) { - bool anonymous = label.is_null(); - for (Target* t = target_stack_; t != NULL; t = t->previous()) { - BreakableStatement* stat = t->node()->AsBreakableStatement(); - if (stat == NULL) continue; - if ((anonymous && stat->is_target_for_anonymous()) || - (!anonymous && ContainsLabel(stat->labels(), label))) { - RegisterTargetUse(stat->break_target(), t->previous()); - return stat; - } - } - return NULL; -} - - -IterationStatement* Parser::LookupContinueTarget(Handle<String> label, - bool* ok) { - bool anonymous = label.is_null(); - for (Target* t = target_stack_; t != NULL; t = t->previous()) { - IterationStatement* stat = t->node()->AsIterationStatement(); - if (stat == NULL) continue; - - ASSERT(stat->is_target_for_anonymous()); - if (anonymous || ContainsLabel(stat->labels(), label)) { - RegisterTargetUse(stat->continue_target(), t->previous()); - return stat; - } - } - return NULL; -} - - -void Parser::RegisterTargetUse(BreakTarget* target, Target* stop) { - // Register that a break target found at the given stop in the - // target stack has been used from the top of the target stack. Add - // the break target to any TargetCollectors passed on the stack. - for (Target* t = target_stack_; t != stop; t = t->previous()) { - TargetCollector* collector = t->node()->AsTargetCollector(); - if (collector != NULL) collector->AddTarget(target); - } -} - - -Literal* Parser::NewNumberLiteral(double number) { - return NEW(Literal(Factory::NewNumber(number, TENURED))); -} - - -Expression* Parser::NewThrowReferenceError(Handle<String> type) { - return NewThrowError(Factory::MakeReferenceError_symbol(), - type, HandleVector<Object>(NULL, 0)); -} - - -Expression* Parser::NewThrowSyntaxError(Handle<String> type, - Handle<Object> first) { - int argc = first.is_null() ? 0 : 1; - Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc); - return NewThrowError(Factory::MakeSyntaxError_symbol(), type, arguments); -} - - -Expression* Parser::NewThrowTypeError(Handle<String> type, - Handle<Object> first, - Handle<Object> second) { - ASSERT(!first.is_null() && !second.is_null()); - Handle<Object> elements[] = { first, second }; - Vector< Handle<Object> > arguments = - HandleVector<Object>(elements, ARRAY_SIZE(elements)); - return NewThrowError(Factory::MakeTypeError_symbol(), type, arguments); -} - - -Expression* Parser::NewThrowError(Handle<String> constructor, - Handle<String> type, - Vector< Handle<Object> > arguments) { - if (is_pre_parsing_) return NULL; - - int argc = arguments.length(); - Handle<JSArray> array = Factory::NewJSArray(argc, TENURED); - ASSERT(array->IsJSArray() && array->HasFastElements()); - for (int i = 0; i < argc; i++) { - Handle<Object> element = arguments[i]; - if (!element.is_null()) { - array->SetFastElement(i, *element); - } - } - ZoneList<Expression*>* args = new ZoneList<Expression*>(2); - args->Add(new Literal(type)); - args->Add(new Literal(array)); - return new Throw(new CallRuntime(constructor, NULL, args), - scanner().location().beg_pos); -} - - -// ---------------------------------------------------------------------------- -// Regular expressions - - -RegExpParser::RegExpParser(FlatStringReader* in, - Handle<String>* error, - bool multiline) - : current_(kEndMarker), - has_more_(true), - multiline_(multiline), - next_pos_(0), - in_(in), - error_(error), - simple_(false), - contains_anchor_(false), - captures_(NULL), - is_scanned_for_captures_(false), - capture_count_(0), - failed_(false) { - Advance(1); -} - - -uc32 RegExpParser::Next() { - if (has_next()) { - return in()->Get(next_pos_); - } else { - return kEndMarker; - } -} - - -void RegExpParser::Advance() { - if (next_pos_ < in()->length()) { - StackLimitCheck check; - if (check.HasOverflowed()) { - ReportError(CStrVector(Top::kStackOverflowMessage)); - } else if (Zone::excess_allocation()) { - ReportError(CStrVector("Regular expression too large")); - } else { - current_ = in()->Get(next_pos_); - next_pos_++; - } - } else { - current_ = kEndMarker; - has_more_ = false; - } -} - - -void RegExpParser::Reset(int pos) { - next_pos_ = pos; - Advance(); -} - - -void RegExpParser::Advance(int dist) { - for (int i = 0; i < dist; i++) - Advance(); -} - - -bool RegExpParser::simple() { - return simple_; -} - -RegExpTree* RegExpParser::ReportError(Vector<const char> message) { - failed_ = true; - *error_ = Factory::NewStringFromAscii(message, NOT_TENURED); - // Zip to the end to make sure the no more input is read. - current_ = kEndMarker; - next_pos_ = in()->length(); - return NULL; -} - - -// Pattern :: -// Disjunction -RegExpTree* RegExpParser::ParsePattern() { - RegExpTree* result = ParseDisjunction(CHECK_FAILED); - ASSERT(!has_more()); - // If the result of parsing is a literal string atom, and it has the - // same length as the input, then the atom is identical to the input. - if (result->IsAtom() && result->AsAtom()->length() == in()->length()) { - simple_ = true; - } - return result; -} - - -// Disjunction :: -// Alternative -// Alternative | Disjunction -// Alternative :: -// [empty] -// Term Alternative -// Term :: -// Assertion -// Atom -// Atom Quantifier -RegExpTree* RegExpParser::ParseDisjunction() { - // Used to store current state while parsing subexpressions. - RegExpParserState initial_state(NULL, INITIAL, 0); - RegExpParserState* stored_state = &initial_state; - // Cache the builder in a local variable for quick access. - RegExpBuilder* builder = initial_state.builder(); - while (true) { - switch (current()) { - case kEndMarker: - if (stored_state->IsSubexpression()) { - // Inside a parenthesized group when hitting end of input. - ReportError(CStrVector("Unterminated group") CHECK_FAILED); - } - ASSERT_EQ(INITIAL, stored_state->group_type()); - // Parsing completed successfully. - return builder->ToRegExp(); - case ')': { - if (!stored_state->IsSubexpression()) { - ReportError(CStrVector("Unmatched ')'") CHECK_FAILED); - } - ASSERT_NE(INITIAL, stored_state->group_type()); - - Advance(); - // End disjunction parsing and convert builder content to new single - // regexp atom. - RegExpTree* body = builder->ToRegExp(); - - int end_capture_index = captures_started(); - - int capture_index = stored_state->capture_index(); - SubexpressionType type = stored_state->group_type(); - - // Restore previous state. - stored_state = stored_state->previous_state(); - builder = stored_state->builder(); - - // Build result of subexpression. - if (type == CAPTURE) { - RegExpCapture* capture = new RegExpCapture(body, capture_index); - captures_->at(capture_index - 1) = capture; - body = capture; - } else if (type != GROUPING) { - ASSERT(type == POSITIVE_LOOKAHEAD || type == NEGATIVE_LOOKAHEAD); - bool is_positive = (type == POSITIVE_LOOKAHEAD); - body = new RegExpLookahead(body, - is_positive, - end_capture_index - capture_index, - capture_index); - } - builder->AddAtom(body); - break; - } - case '|': { - Advance(); - builder->NewAlternative(); - continue; - } - case '*': - case '+': - case '?': - return ReportError(CStrVector("Nothing to repeat")); - case '^': { - Advance(); - if (multiline_) { - builder->AddAssertion( - new RegExpAssertion(RegExpAssertion::START_OF_LINE)); - } else { - builder->AddAssertion( - new RegExpAssertion(RegExpAssertion::START_OF_INPUT)); - set_contains_anchor(); - } - continue; - } - case '$': { - Advance(); - RegExpAssertion::Type type = - multiline_ ? RegExpAssertion::END_OF_LINE : - RegExpAssertion::END_OF_INPUT; - builder->AddAssertion(new RegExpAssertion(type)); - continue; - } - case '.': { - Advance(); - // everything except \x0a, \x0d, \u2028 and \u2029 - ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); - CharacterRange::AddClassEscape('.', ranges); - RegExpTree* atom = new RegExpCharacterClass(ranges, false); - builder->AddAtom(atom); - break; - } - case '(': { - SubexpressionType type = CAPTURE; - Advance(); - if (current() == '?') { - switch (Next()) { - case ':': - type = GROUPING; - break; - case '=': - type = POSITIVE_LOOKAHEAD; - break; - case '!': - type = NEGATIVE_LOOKAHEAD; - break; - default: - ReportError(CStrVector("Invalid group") CHECK_FAILED); - break; - } - Advance(2); - } else { - if (captures_ == NULL) { - captures_ = new ZoneList<RegExpCapture*>(2); - } - if (captures_started() >= kMaxCaptures) { - ReportError(CStrVector("Too many captures") CHECK_FAILED); - } - captures_->Add(NULL); - } - // Store current state and begin new disjunction parsing. - stored_state = new RegExpParserState(stored_state, - type, - captures_started()); - builder = stored_state->builder(); - break; - } - case '[': { - RegExpTree* atom = ParseCharacterClass(CHECK_FAILED); - builder->AddAtom(atom); - break; - } - // Atom :: - // \ AtomEscape - case '\\': - switch (Next()) { - case kEndMarker: - return ReportError(CStrVector("\\ at end of pattern")); - case 'b': - Advance(2); - builder->AddAssertion( - new RegExpAssertion(RegExpAssertion::BOUNDARY)); - continue; - case 'B': - Advance(2); - builder->AddAssertion( - new RegExpAssertion(RegExpAssertion::NON_BOUNDARY)); - continue; - // AtomEscape :: - // CharacterClassEscape - // - // CharacterClassEscape :: one of - // d D s S w W - case 'd': case 'D': case 's': case 'S': case 'w': case 'W': { - uc32 c = Next(); - Advance(2); - ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); - CharacterRange::AddClassEscape(c, ranges); - RegExpTree* atom = new RegExpCharacterClass(ranges, false); - builder->AddAtom(atom); - break; - } - case '1': case '2': case '3': case '4': case '5': case '6': - case '7': case '8': case '9': { - int index = 0; - if (ParseBackReferenceIndex(&index)) { - RegExpCapture* capture = NULL; - if (captures_ != NULL && index <= captures_->length()) { - capture = captures_->at(index - 1); - } - if (capture == NULL) { - builder->AddEmpty(); - break; - } - RegExpTree* atom = new RegExpBackReference(capture); - builder->AddAtom(atom); - break; - } - uc32 first_digit = Next(); - if (first_digit == '8' || first_digit == '9') { - // Treat as identity escape - builder->AddCharacter(first_digit); - Advance(2); - break; - } - } - // FALLTHROUGH - case '0': { - Advance(); - uc32 octal = ParseOctalLiteral(); - builder->AddCharacter(octal); - break; - } - // ControlEscape :: one of - // f n r t v - case 'f': - Advance(2); - builder->AddCharacter('\f'); - break; - case 'n': - Advance(2); - builder->AddCharacter('\n'); - break; - case 'r': - Advance(2); - builder->AddCharacter('\r'); - break; - case 't': - Advance(2); - builder->AddCharacter('\t'); - break; - case 'v': - Advance(2); - builder->AddCharacter('\v'); - break; - case 'c': { - Advance(2); - uc32 control = ParseControlLetterEscape(); - builder->AddCharacter(control); - break; - } - case 'x': { - Advance(2); - uc32 value; - if (ParseHexEscape(2, &value)) { - builder->AddCharacter(value); - } else { - builder->AddCharacter('x'); - } - break; - } - case 'u': { - Advance(2); - uc32 value; - if (ParseHexEscape(4, &value)) { - builder->AddCharacter(value); - } else { - builder->AddCharacter('u'); - } - break; - } - default: - // Identity escape. - builder->AddCharacter(Next()); - Advance(2); - break; - } - break; - case '{': { - int dummy; - if (ParseIntervalQuantifier(&dummy, &dummy)) { - ReportError(CStrVector("Nothing to repeat") CHECK_FAILED); - } - // fallthrough - } - default: - builder->AddCharacter(current()); - Advance(); - break; - } // end switch(current()) - - int min; - int max; - switch (current()) { - // QuantifierPrefix :: - // * - // + - // ? - // { - case '*': - min = 0; - max = RegExpTree::kInfinity; - Advance(); - break; - case '+': - min = 1; - max = RegExpTree::kInfinity; - Advance(); - break; - case '?': - min = 0; - max = 1; - Advance(); - break; - case '{': - if (ParseIntervalQuantifier(&min, &max)) { - if (max < min) { - ReportError(CStrVector("numbers out of order in {} quantifier.") - CHECK_FAILED); - } - break; - } else { - continue; - } - default: - continue; - } - bool is_greedy = true; - if (current() == '?') { - is_greedy = false; - Advance(); - } - builder->AddQuantifierToAtom(min, max, is_greedy); - } -} - -class SourceCharacter { - public: - static bool Is(uc32 c) { - switch (c) { - // case ']': case '}': - // In spidermonkey and jsc these are treated as source characters - // so we do too. - case '^': case '$': case '\\': case '.': case '*': case '+': - case '?': case '(': case ')': case '[': case '{': case '|': - case RegExpParser::kEndMarker: - return false; - default: - return true; - } - } -}; - - -static unibrow::Predicate<SourceCharacter> source_character; - - -static inline bool IsSourceCharacter(uc32 c) { - return source_character.get(c); -} - -#ifdef DEBUG -// Currently only used in an ASSERT. -static bool IsSpecialClassEscape(uc32 c) { - switch (c) { - case 'd': case 'D': - case 's': case 'S': - case 'w': case 'W': - return true; - default: - return false; - } -} -#endif - - -// In order to know whether an escape is a backreference or not we have to scan -// the entire regexp and find the number of capturing parentheses. However we -// don't want to scan the regexp twice unless it is necessary. This mini-parser -// is called when needed. It can see the difference between capturing and -// noncapturing parentheses and can skip character classes and backslash-escaped -// characters. -void RegExpParser::ScanForCaptures() { - // Start with captures started previous to current position - int capture_count = captures_started(); - // Add count of captures after this position. - int n; - while ((n = current()) != kEndMarker) { - Advance(); - switch (n) { - case '\\': - Advance(); - break; - case '[': { - int c; - while ((c = current()) != kEndMarker) { - Advance(); - if (c == '\\') { - Advance(); - } else { - if (c == ']') break; - } - } - break; - } - case '(': - if (current() != '?') capture_count++; - break; - } - } - capture_count_ = capture_count; - is_scanned_for_captures_ = true; -} - - -bool RegExpParser::ParseBackReferenceIndex(int* index_out) { - ASSERT_EQ('\\', current()); - ASSERT('1' <= Next() && Next() <= '9'); - // Try to parse a decimal literal that is no greater than the total number - // of left capturing parentheses in the input. - int start = position(); - int value = Next() - '0'; - Advance(2); - while (true) { - uc32 c = current(); - if (IsDecimalDigit(c)) { - value = 10 * value + (c - '0'); - if (value > kMaxCaptures) { - Reset(start); - return false; - } - Advance(); - } else { - break; - } - } - if (value > captures_started()) { - if (!is_scanned_for_captures_) { - int saved_position = position(); - ScanForCaptures(); - Reset(saved_position); - } - if (value > capture_count_) { - Reset(start); - return false; - } - } - *index_out = value; - return true; -} - - -// QuantifierPrefix :: -// { DecimalDigits } -// { DecimalDigits , } -// { DecimalDigits , DecimalDigits } -// -// Returns true if parsing succeeds, and set the min_out and max_out -// values. Values are truncated to RegExpTree::kInfinity if they overflow. -bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) { - ASSERT_EQ(current(), '{'); - int start = position(); - Advance(); - int min = 0; - if (!IsDecimalDigit(current())) { - Reset(start); - return false; - } - while (IsDecimalDigit(current())) { - int next = current() - '0'; - if (min > (RegExpTree::kInfinity - next) / 10) { - // Overflow. Skip past remaining decimal digits and return -1. - do { - Advance(); - } while (IsDecimalDigit(current())); - min = RegExpTree::kInfinity; - break; - } - min = 10 * min + next; - Advance(); - } - int max = 0; - if (current() == '}') { - max = min; - Advance(); - } else if (current() == ',') { - Advance(); - if (current() == '}') { - max = RegExpTree::kInfinity; - Advance(); - } else { - while (IsDecimalDigit(current())) { - int next = current() - '0'; - if (max > (RegExpTree::kInfinity - next) / 10) { - do { - Advance(); - } while (IsDecimalDigit(current())); - max = RegExpTree::kInfinity; - break; - } - max = 10 * max + next; - Advance(); - } - if (current() != '}') { - Reset(start); - return false; - } - Advance(); - } - } else { - Reset(start); - return false; - } - *min_out = min; - *max_out = max; - return true; -} - - -// Upper and lower case letters differ by one bit. -STATIC_CHECK(('a' ^ 'A') == 0x20); - -uc32 RegExpParser::ParseControlLetterEscape() { - if (!has_more()) - return 'c'; - uc32 letter = current() & ~(0x20); // Collapse upper and lower case letters. - if (letter < 'A' || 'Z' < letter) { - // Non-spec error-correction: "\c" followed by non-control letter is - // interpreted as an IdentityEscape of 'c'. - return 'c'; - } - Advance(); - return letter & 0x1f; // Remainder modulo 32, per specification. -} - - -uc32 RegExpParser::ParseOctalLiteral() { - ASSERT('0' <= current() && current() <= '7'); - // For compatibility with some other browsers (not all), we parse - // up to three octal digits with a value below 256. - uc32 value = current() - '0'; - Advance(); - if ('0' <= current() && current() <= '7') { - value = value * 8 + current() - '0'; - Advance(); - if (value < 32 && '0' <= current() && current() <= '7') { - value = value * 8 + current() - '0'; - Advance(); - } - } - return value; -} - - -bool RegExpParser::ParseHexEscape(int length, uc32 *value) { - int start = position(); - uc32 val = 0; - bool done = false; - for (int i = 0; !done; i++) { - uc32 c = current(); - int d = HexValue(c); - if (d < 0) { - Reset(start); - return false; - } - val = val * 16 + d; - Advance(); - if (i == length - 1) { - done = true; - } - } - *value = val; - return true; -} - - -uc32 RegExpParser::ParseClassCharacterEscape() { - ASSERT(current() == '\\'); - ASSERT(has_next() && !IsSpecialClassEscape(Next())); - Advance(); - switch (current()) { - case 'b': - Advance(); - return '\b'; - // ControlEscape :: one of - // f n r t v - case 'f': - Advance(); - return '\f'; - case 'n': - Advance(); - return '\n'; - case 'r': - Advance(); - return '\r'; - case 't': - Advance(); - return '\t'; - case 'v': - Advance(); - return '\v'; - case 'c': - Advance(); - return ParseControlLetterEscape(); - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': - // For compatibility, we interpret a decimal escape that isn't - // a back reference (and therefore either \0 or not valid according - // to the specification) as a 1..3 digit octal character code. - return ParseOctalLiteral(); - case 'x': { - Advance(); - uc32 value; - if (ParseHexEscape(2, &value)) { - return value; - } - // If \x is not followed by a two-digit hexadecimal, treat it - // as an identity escape. - return 'x'; - } - case 'u': { - Advance(); - uc32 value; - if (ParseHexEscape(4, &value)) { - return value; - } - // If \u is not followed by a four-digit hexadecimal, treat it - // as an identity escape. - return 'u'; - } - default: { - // Extended identity escape. We accept any character that hasn't - // been matched by a more specific case, not just the subset required - // by the ECMAScript specification. - uc32 result = current(); - Advance(); - return result; - } - } - return 0; -} - - -CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) { - ASSERT_EQ(0, *char_class); - uc32 first = current(); - if (first == '\\') { - switch (Next()) { - case 'w': case 'W': case 'd': case 'D': case 's': case 'S': { - *char_class = Next(); - Advance(2); - return CharacterRange::Singleton(0); // Return dummy value. - } - case kEndMarker: - return ReportError(CStrVector("\\ at end of pattern")); - default: - uc32 c = ParseClassCharacterEscape(CHECK_FAILED); - return CharacterRange::Singleton(c); - } - } else { - Advance(); - return CharacterRange::Singleton(first); - } -} - - -RegExpTree* RegExpParser::ParseCharacterClass() { - static const char* kUnterminated = "Unterminated character class"; - static const char* kRangeOutOfOrder = "Range out of order in character class"; - - ASSERT_EQ(current(), '['); - Advance(); - bool is_negated = false; - if (current() == '^') { - is_negated = true; - Advance(); - } - ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); - while (has_more() && current() != ']') { - uc16 char_class = 0; - CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED); - if (char_class) { - CharacterRange::AddClassEscape(char_class, ranges); - continue; - } - if (current() == '-') { - Advance(); - if (current() == kEndMarker) { - // If we reach the end we break out of the loop and let the - // following code report an error. - break; - } else if (current() == ']') { - ranges->Add(first); - ranges->Add(CharacterRange::Singleton('-')); - break; - } - CharacterRange next = ParseClassAtom(&char_class CHECK_FAILED); - if (char_class) { - ranges->Add(first); - ranges->Add(CharacterRange::Singleton('-')); - CharacterRange::AddClassEscape(char_class, ranges); - continue; - } - if (first.from() > next.to()) { - return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED); - } - ranges->Add(CharacterRange::Range(first.from(), next.to())); - } else { - ranges->Add(first); - } - } - if (!has_more()) { - return ReportError(CStrVector(kUnterminated) CHECK_FAILED); - } - Advance(); - if (ranges->length() == 0) { - ranges->Add(CharacterRange::Everything()); - is_negated = !is_negated; - } - return new RegExpCharacterClass(ranges, is_negated); -} - - -// ---------------------------------------------------------------------------- -// The Parser interface. - -// MakeAST() is just a wrapper for the corresponding Parser calls -// so we don't have to expose the entire Parser class in the .h file. - -static bool always_allow_natives_syntax = false; - - -ParserMessage::~ParserMessage() { - for (int i = 0; i < args().length(); i++) - DeleteArray(args()[i]); - DeleteArray(args().start()); -} - - -ScriptDataImpl::~ScriptDataImpl() { - store_.Dispose(); -} - - -int ScriptDataImpl::Length() { - return store_.length(); -} - - -unsigned* ScriptDataImpl::Data() { - return store_.start(); -} - - -ScriptDataImpl* PreParse(Handle<String> source, - unibrow::CharacterStream* stream, - v8::Extension* extension) { - Handle<Script> no_script; - bool allow_natives_syntax = - always_allow_natives_syntax || - FLAG_allow_natives_syntax || - Bootstrapper::IsActive(); - PreParser parser(no_script, allow_natives_syntax, extension); - if (!parser.PreParseProgram(source, stream)) return NULL; - // The list owns the backing store so we need to clone the vector. - // That way, the result will be exactly the right size rather than - // the expected 50% too large. - Vector<unsigned> store = parser.recorder()->store()->ToVector().Clone(); - return new ScriptDataImpl(store); -} - - -bool ParseRegExp(FlatStringReader* input, - bool multiline, - RegExpCompileData* result) { - ASSERT(result != NULL); - RegExpParser parser(input, &result->error, multiline); - RegExpTree* tree = parser.ParsePattern(); - if (parser.failed()) { - ASSERT(tree == NULL); - ASSERT(!result->error.is_null()); - } else { - ASSERT(tree != NULL); - ASSERT(result->error.is_null()); - result->tree = tree; - int capture_count = parser.captures_started(); - result->simple = tree->IsAtom() && parser.simple() && capture_count == 0; - result->contains_anchor = parser.contains_anchor(); - result->capture_count = capture_count; - } - return !parser.failed(); -} - - -FunctionLiteral* MakeAST(bool compile_in_global_context, - Handle<Script> script, - v8::Extension* extension, - ScriptDataImpl* pre_data) { - bool allow_natives_syntax = - always_allow_natives_syntax || - FLAG_allow_natives_syntax || - Bootstrapper::IsActive(); - AstBuildingParser parser(script, allow_natives_syntax, extension, pre_data); - if (pre_data != NULL && pre_data->has_error()) { - Scanner::Location loc = pre_data->MessageLocation(); - const char* message = pre_data->BuildMessage(); - Vector<const char*> args = pre_data->BuildArgs(); - parser.ReportMessageAt(loc, message, args); - DeleteArray(message); - for (int i = 0; i < args.length(); i++) - DeleteArray(args[i]); - DeleteArray(args.start()); - return NULL; - } - Handle<String> source = Handle<String>(String::cast(script->source())); - SafeStringInputBuffer input(source.location()); - FunctionLiteral* result = parser.ParseProgram(source, - &input, compile_in_global_context); - return result; -} - - -FunctionLiteral* MakeLazyAST(Handle<Script> script, - Handle<String> name, - int start_position, - int end_position, - bool is_expression) { - bool allow_natives_syntax_before = always_allow_natives_syntax; - always_allow_natives_syntax = true; - AstBuildingParser parser(script, true, NULL, NULL); // always allow - always_allow_natives_syntax = allow_natives_syntax_before; - // Parse the function by pulling the function source from the script source. - Handle<String> script_source(String::cast(script->source())); - FunctionLiteral* result = - parser.ParseLazy(SubString(script_source, start_position, end_position), - name, - start_position, - is_expression); - return result; -} - - -#undef NEW - - -} } // namespace v8::internal |