summaryrefslogtreecommitdiffstats
path: root/V8Binding/v8/src/parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'V8Binding/v8/src/parser.cc')
-rw-r--r--V8Binding/v8/src/parser.cc4835
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 &empty;
-}
-
-
-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