objects-visiting.cc
oprofile-agent.cc
parser.cc
+ preparser.cc
+ preparse-data.cc
profile-generator.cc
property.cc
regexp-macro-assembler-irregexp.cc
}
-Vector<unsigned> PartialParserRecorder::ExtractData() {
- int function_size = function_store_.size();
- int total_size = ScriptDataImpl::kHeaderSize + function_size;
- Vector<unsigned> data = Vector<unsigned>::New(total_size);
- preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
- preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
- memcpy(data.start(), preamble_, sizeof(preamble_));
- int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
- if (function_size > 0) {
- function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
- symbol_start));
- }
- return data;
-}
-
-
-void CompleteParserRecorder::LogSymbol(int start, Vector<const char> literal) {
- if (!is_recording_) return;
-
- int hash = vector_hash(literal);
- HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
- int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
- if (id == 0) {
- // Put (symbol_id_ + 1) into entry and increment it.
- id = ++symbol_id_;
- entry->value = reinterpret_cast<void*>(id);
- Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal);
- entry->key = &symbol[0];
- }
- WriteNumber(id - 1);
-}
-
-
-Vector<unsigned> CompleteParserRecorder::ExtractData() {
- int function_size = function_store_.size();
- // Add terminator to symbols, then pad to unsigned size.
- int symbol_size = symbol_store_.size();
- int padding = sizeof(unsigned) - (symbol_size % sizeof(unsigned));
- symbol_store_.AddBlock(padding, ScriptDataImpl::kNumberTerminator);
- symbol_size += padding;
- int total_size = ScriptDataImpl::kHeaderSize + function_size
- + (symbol_size / sizeof(unsigned));
- Vector<unsigned> data = Vector<unsigned>::New(total_size);
- preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
- preamble_[ScriptDataImpl::kSymbolCountOffset] = symbol_id_;
- memcpy(data.start(), preamble_, sizeof(preamble_));
- int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
- if (function_size > 0) {
- function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
- symbol_start));
- }
- if (!has_error()) {
- symbol_store_.WriteTo(
- Vector<byte>::cast(data.SubVector(symbol_start, total_size)));
- }
- return data;
-}
-
-
FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
// The current pre-data entry must be a FunctionEntry with the given
// start position.
bool ScriptDataImpl::SanityCheck() {
// Check that the header data is valid and doesn't specify
// point to positions outside the store.
- if (store_.length() < ScriptDataImpl::kHeaderSize) return false;
- if (magic() != ScriptDataImpl::kMagicNumber) return false;
- if (version() != ScriptDataImpl::kCurrentVersion) return false;
+ if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
+ if (magic() != PreparseDataConstants::kMagicNumber) return false;
+ if (version() != PreparseDataConstants::kCurrentVersion) return false;
if (has_error()) {
// Extra sane sanity check for error message encoding.
- if (store_.length() <= kHeaderSize + kMessageTextPos) return false;
- if (Read(kMessageStartPos) > Read(kMessageEndPos)) return false;
- unsigned arg_count = Read(kMessageArgCountPos);
- int pos = kMessageTextPos;
+ if (store_.length() <= PreparseDataConstants::kHeaderSize
+ + PreparseDataConstants::kMessageTextPos) {
+ return false;
+ }
+ if (Read(PreparseDataConstants::kMessageStartPos) >
+ Read(PreparseDataConstants::kMessageEndPos)) {
+ return false;
+ }
+ unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
+ int pos = PreparseDataConstants::kMessageTextPos;
for (unsigned int i = 0; i <= arg_count; i++) {
- if (store_.length() <= kHeaderSize + pos) return false;
+ if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
+ return false;
+ }
int length = static_cast<int>(Read(pos));
if (length < 0) return false;
pos += 1 + length;
}
- if (store_.length() < kHeaderSize + pos) return false;
+ if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
+ return false;
+ }
return true;
}
// Check that the space allocated for function entries is sane.
int functions_size =
- static_cast<int>(store_[ScriptDataImpl::kFunctionsSizeOffset]);
+ static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
if (functions_size < 0) return false;
if (functions_size % FunctionEntry::kSize != 0) return false;
// Check that the count of symbols is non-negative.
int symbol_count =
- static_cast<int>(store_[ScriptDataImpl::kSymbolCountOffset]);
+ static_cast<int>(store_[PreparseDataConstants::kSymbolCountOffset]);
if (symbol_count < 0) return false;
// Check that the total size has room for header and function entries.
int minimum_size =
- ScriptDataImpl::kHeaderSize + functions_size;
+ PreparseDataConstants::kHeaderSize + functions_size;
if (store_.length() < minimum_size) return false;
return true;
}
-PartialParserRecorder::PartialParserRecorder()
- : function_store_(0),
- is_recording_(true),
- pause_count_(0) {
- preamble_[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber;
- preamble_[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion;
- preamble_[ScriptDataImpl::kHasErrorOffset] = false;
- preamble_[ScriptDataImpl::kFunctionsSizeOffset] = 0;
- preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
- preamble_[ScriptDataImpl::kSizeOffset] = 0;
- ASSERT_EQ(6, ScriptDataImpl::kHeaderSize);
-#ifdef DEBUG
- prev_start_ = -1;
-#endif
-}
-
-
-CompleteParserRecorder::CompleteParserRecorder()
- : PartialParserRecorder(),
- symbol_store_(0),
- symbol_entries_(0),
- symbol_table_(vector_compare),
- symbol_id_(0) {
-}
-
-
-void PartialParserRecorder::WriteString(Vector<const char> str) {
- function_store_.Add(str.length());
- for (int i = 0; i < str.length(); i++) {
- function_store_.Add(str[i]);
- }
-}
-
-
-void CompleteParserRecorder::WriteNumber(int number) {
- ASSERT(number >= 0);
-
- int mask = (1 << 28) - 1;
- for (int i = 28; i > 0; i -= 7) {
- if (number > mask) {
- symbol_store_.Add(static_cast<byte>(number >> i) | 0x80u);
- number &= mask;
- }
- mask >>= 7;
- }
- symbol_store_.Add(static_cast<byte>(number));
-}
-
-
-
const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
int length = start[0];
char* result = NewArray<char>(length + 1);
return result;
}
-
-void PartialParserRecorder::LogMessage(Scanner::Location loc,
- const char* message,
- Vector<const char*> args) {
- if (has_error()) return;
- preamble_[ScriptDataImpl::kHasErrorOffset] = true;
- function_store_.Reset();
- STATIC_ASSERT(ScriptDataImpl::kMessageStartPos == 0);
- function_store_.Add(loc.beg_pos);
- STATIC_ASSERT(ScriptDataImpl::kMessageEndPos == 1);
- function_store_.Add(loc.end_pos);
- STATIC_ASSERT(ScriptDataImpl::kMessageArgCountPos == 2);
- function_store_.Add(args.length());
- STATIC_ASSERT(ScriptDataImpl::kMessageTextPos == 3);
- WriteString(CStrVector(message));
- for (int i = 0; i < args.length(); i++) {
- WriteString(CStrVector(args[i]));
- }
- is_recording_ = false;
-}
-
-
Scanner::Location ScriptDataImpl::MessageLocation() {
- int beg_pos = Read(kMessageStartPos);
- int end_pos = Read(kMessageEndPos);
+ int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
+ int end_pos = Read(PreparseDataConstants::kMessageEndPos);
return Scanner::Location(beg_pos, end_pos);
}
const char* ScriptDataImpl::BuildMessage() {
- unsigned* start = ReadAddress(kMessageTextPos);
+ unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
return ReadString(start, NULL);
}
Vector<const char*> ScriptDataImpl::BuildArgs() {
- int arg_count = Read(kMessageArgCountPos);
+ int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
const char** array = NewArray<const char*>(arg_count);
// Position after text found by skipping past length field and
// length field content words.
- int pos = kMessageTextPos + 1 + Read(kMessageTextPos);
+ int pos = PreparseDataConstants::kMessageTextPos + 1
+ + Read(PreparseDataConstants::kMessageTextPos);
for (int i = 0; i < arg_count; i++) {
int count = 0;
array[i] = ReadString(ReadAddress(pos), &count);
unsigned ScriptDataImpl::Read(int position) {
- return store_[ScriptDataImpl::kHeaderSize + position];
+ return store_[PreparseDataConstants::kHeaderSize + position];
}
unsigned* ScriptDataImpl::ReadAddress(int position) {
- return &store_[ScriptDataImpl::kHeaderSize + position];
+ return &store_[PreparseDataConstants::kHeaderSize + position];
}
void ScriptDataImpl::Initialize() {
// Prepares state for use.
- if (store_.length() >= kHeaderSize) {
- function_index_ = kHeaderSize;
- int symbol_data_offset = kHeaderSize + store_[kFunctionsSizeOffset];
+ if (store_.length() >= PreparseDataConstants::kHeaderSize) {
+ function_index_ = PreparseDataConstants::kHeaderSize;
+ int symbol_data_offset = PreparseDataConstants::kHeaderSize
+ + store_[PreparseDataConstants::kFunctionsSizeOffset];
if (store_.length() > symbol_data_offset) {
symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
} else {
byte* data = *source;
if (data >= symbol_data_end_) return -1;
byte input = *data;
- if (input == kNumberTerminator) {
+ if (input == PreparseDataConstants::kNumberTerminator) {
// End of stream marker.
return -1;
}
static ScriptDataImpl* DoPreParse(Handle<String> source,
unibrow::CharacterStream* stream,
bool allow_lazy,
- PartialParserRecorder* recorder,
+ ParserRecorder* recorder,
int literal_flags) {
V8JavaScriptScanner scanner;
scanner.Initialize(source, stream, literal_flags);
- preparser::PreParser<JavaScriptScanner, PartialParserRecorder> preparser;
+ preparser::PreParser preparser;
if (!preparser.PreParseProgram(&scanner, recorder, allow_lazy)) {
Top::StackOverflow();
return NULL;
#include "ast.h"
#include "scanner.h"
#include "scopes.h"
+#include "preparse-data.h"
namespace v8 {
namespace internal {
Vector<const char*> BuildArgs();
int symbol_count() {
- return (store_.length() > kHeaderSize) ? store_[kSymbolCountOffset] : 0;
+ return (store_.length() > PreparseDataConstants::kHeaderSize)
+ ? store_[PreparseDataConstants::kSymbolCountOffset]
+ : 0;
}
// The following functions should only be called if SanityCheck has
// returned true.
- bool has_error() { return store_[kHasErrorOffset]; }
- unsigned magic() { return store_[kMagicOffset]; }
- unsigned version() { return store_[kVersionOffset]; }
-
- static const unsigned kMagicNumber = 0xBadDead;
- static const unsigned kCurrentVersion = 5;
-
- static const int kMagicOffset = 0;
- static const int kVersionOffset = 1;
- static const int kHasErrorOffset = 2;
- static const int kFunctionsSizeOffset = 3;
- static const int kSymbolCountOffset = 4;
- static const int kSizeOffset = 5;
- static const int kHeaderSize = 6;
-
- // If encoding a message, the following positions are fixed.
- static const int kMessageStartPos = 0;
- static const int kMessageEndPos = 1;
- static const int kMessageArgCountPos = 2;
- static const int kMessageTextPos = 3;
-
- static const byte kNumberTerminator = 0x80u;
+ bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; }
+ unsigned magic() { return store_[PreparseDataConstants::kMagicOffset]; }
+ unsigned version() { return store_[PreparseDataConstants::kVersionOffset]; }
private:
Vector<unsigned> store_;
};
-// Record only functions.
-class PartialParserRecorder {
- public:
- PartialParserRecorder();
- virtual ~PartialParserRecorder() {}
-
- void LogFunction(int start, int end, int literals, int properties) {
- function_store_.Add(start);
- function_store_.Add(end);
- function_store_.Add(literals);
- function_store_.Add(properties);
- }
-
- virtual void LogSymbol(int start, const char* symbol, int length) { }
-
- // Logs an error message and marks the log as containing an error.
- // Further logging will be ignored, and ExtractData will return a vector
- // representing the error only.
- void LogMessage(int start,
- int end,
- const char* message,
- const char* argument_opt) {
- Scanner::Location location(start, end);
- Vector<const char*> arguments;
- if (argument_opt != NULL) {
- arguments = Vector<const char*>(&argument_opt, 1);
- }
- this->LogMessage(location, message, arguments);
- }
-
- int function_position() { return function_store_.size(); }
-
- void LogMessage(Scanner::Location loc,
- const char* message,
- Vector<const char*> args);
-
- virtual Vector<unsigned> ExtractData();
-
- void PauseRecording() {
- pause_count_++;
- is_recording_ = false;
- }
-
- void ResumeRecording() {
- ASSERT(pause_count_ > 0);
- if (--pause_count_ == 0) is_recording_ = !has_error();
- }
-
- int symbol_position() { return 0; }
- int symbol_ids() { return 0; }
-
- protected:
- bool has_error() {
- return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
- }
-
- bool is_recording() {
- return is_recording_;
- }
-
- void WriteString(Vector<const char> str);
-
- Collector<unsigned> function_store_;
- unsigned preamble_[ScriptDataImpl::kHeaderSize];
- bool is_recording_;
- int pause_count_;
-
-#ifdef DEBUG
- int prev_start_;
-#endif
-};
-
-
-// Record both functions and symbols.
-class CompleteParserRecorder: public PartialParserRecorder {
- public:
- CompleteParserRecorder();
- virtual ~CompleteParserRecorder() { }
-
- void LogSymbol(int start, Vector<const char> literal);
-
- virtual void LogSymbol(int start, const char* symbol, int length) {
- LogSymbol(start, Vector<const char>(symbol, length));
- }
-
- virtual Vector<unsigned> ExtractData();
-
- int symbol_position() { return symbol_store_.size(); }
- int symbol_ids() { return symbol_id_; }
-
- private:
- static int vector_hash(Vector<const char> string) {
- int hash = 0;
- for (int i = 0; i < string.length(); i++) {
- int c = string[i];
- hash += c;
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
- return hash;
- }
-
- static bool vector_compare(void* a, void* b) {
- Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
- Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
- int length = string1->length();
- if (string2->length() != length) return false;
- return memcmp(string1->start(), string2->start(), length) == 0;
- }
-
- // Write a non-negative number to the symbol store.
- void WriteNumber(int number);
-
- Collector<byte> symbol_store_;
- Collector<Vector<const char> > symbol_entries_;
- HashMap symbol_table_;
- int symbol_id_;
-};
-
-
-
class ParserApi {
public:
// Parses the source code represented by the compilation info and sets its
--- /dev/null
+// Copyright 2010 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 "../include/v8stdint.h"
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "utils.h"
+#include "list-inl.h"
+#include "hashmap.h"
+#include "preparse-data.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// FunctionLoggingParserRecorder
+
+FunctionLoggingParserRecorder::FunctionLoggingParserRecorder()
+ : function_store_(0),
+ is_recording_(true),
+ pause_count_(0) {
+ preamble_[PreparseDataConstants::kMagicOffset] =
+ PreparseDataConstants::kMagicNumber;
+ preamble_[PreparseDataConstants::kVersionOffset] =
+ PreparseDataConstants::kCurrentVersion;
+ preamble_[PreparseDataConstants::kHasErrorOffset] = false;
+ preamble_[PreparseDataConstants::kFunctionsSizeOffset] = 0;
+ preamble_[PreparseDataConstants::kSymbolCountOffset] = 0;
+ preamble_[PreparseDataConstants::kSizeOffset] = 0;
+ ASSERT_EQ(6, PreparseDataConstants::kHeaderSize);
+#ifdef DEBUG
+ prev_start_ = -1;
+#endif
+}
+
+
+void FunctionLoggingParserRecorder::LogMessage(int start_pos,
+ int end_pos,
+ const char* message,
+ const char* arg_opt) {
+ if (has_error()) return;
+ preamble_[PreparseDataConstants::kHasErrorOffset] = true;
+ function_store_.Reset();
+ STATIC_ASSERT(PreparseDataConstants::kMessageStartPos == 0);
+ function_store_.Add(start_pos);
+ STATIC_ASSERT(PreparseDataConstants::kMessageEndPos == 1);
+ function_store_.Add(end_pos);
+ STATIC_ASSERT(PreparseDataConstants::kMessageArgCountPos == 2);
+ function_store_.Add((arg_opt == NULL) ? 0 : 1);
+ STATIC_ASSERT(PreparseDataConstants::kMessageTextPos == 3);
+ WriteString(CStrVector(message));
+ if (arg_opt) WriteString(CStrVector(arg_opt));
+ is_recording_ = false;
+}
+
+
+void FunctionLoggingParserRecorder::WriteString(Vector<const char> str) {
+ function_store_.Add(str.length());
+ for (int i = 0; i < str.length(); i++) {
+ function_store_.Add(str[i]);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// PartialParserRecorder - Record both function entries and symbols.
+
+Vector<unsigned> PartialParserRecorder::ExtractData() {
+ int function_size = function_store_.size();
+ int total_size = PreparseDataConstants::kHeaderSize + function_size;
+ Vector<unsigned> data = Vector<unsigned>::New(total_size);
+ preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
+ preamble_[PreparseDataConstants::kSymbolCountOffset] = 0;
+ memcpy(data.start(), preamble_, sizeof(preamble_));
+ int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
+ if (function_size > 0) {
+ function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
+ symbol_start));
+ }
+ return data;
+}
+
+
+// ----------------------------------------------------------------------------
+// CompleteParserRecorder - Record both function entries and symbols.
+
+CompleteParserRecorder::CompleteParserRecorder()
+ : FunctionLoggingParserRecorder(),
+ symbol_store_(0),
+ symbol_entries_(0),
+ symbol_table_(vector_compare),
+ symbol_id_(0) {
+}
+
+
+void CompleteParserRecorder::LogSymbol(
+ int start, const char* literal_chars, int length) {
+ if (!is_recording_) return;
+
+ Vector<const char> literal(literal_chars, length);
+ int hash = vector_hash(literal);
+ HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
+ int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
+ if (id == 0) {
+ // Put (symbol_id_ + 1) into entry and increment it.
+ id = ++symbol_id_;
+ entry->value = reinterpret_cast<void*>(id);
+ Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal);
+ entry->key = &symbol[0];
+ }
+ WriteNumber(id - 1);
+}
+
+
+Vector<unsigned> CompleteParserRecorder::ExtractData() {
+ int function_size = function_store_.size();
+ // Add terminator to symbols, then pad to unsigned size.
+ int symbol_size = symbol_store_.size();
+ int padding = sizeof(unsigned) - (symbol_size % sizeof(unsigned));
+ symbol_store_.AddBlock(padding, PreparseDataConstants::kNumberTerminator);
+ symbol_size += padding;
+ int total_size = PreparseDataConstants::kHeaderSize + function_size
+ + (symbol_size / sizeof(unsigned));
+ Vector<unsigned> data = Vector<unsigned>::New(total_size);
+ preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
+ preamble_[PreparseDataConstants::kSymbolCountOffset] = symbol_id_;
+ memcpy(data.start(), preamble_, sizeof(preamble_));
+ int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
+ if (function_size > 0) {
+ function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
+ symbol_start));
+ }
+ if (!has_error()) {
+ symbol_store_.WriteTo(
+ Vector<byte>::cast(data.SubVector(symbol_start, total_size)));
+ }
+ return data;
+}
+
+
+void CompleteParserRecorder::WriteNumber(int number) {
+ ASSERT(number >= 0);
+
+ int mask = (1 << 28) - 1;
+ for (int i = 28; i > 0; i -= 7) {
+ if (number > mask) {
+ symbol_store_.Add(static_cast<byte>(number >> i) | 0x80u);
+ number &= mask;
+ }
+ mask >>= 7;
+ }
+ symbol_store_.Add(static_cast<byte>(number));
+}
+
+
+} } // namespace v8::internal.
--- /dev/null
+// Copyright 2010 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.
+
+#ifndef V8_PREPARSER_DATA_H_
+#define V8_PREPARSER_DATA_H_
+
+#include "hashmap.h"
+
+namespace v8 {
+namespace internal {
+
+// Generic and general data used by preparse data recorders and readers.
+
+class PreparseDataConstants : public AllStatic {
+ public:
+ // Layout and constants of the preparse data exchange format.
+ static const unsigned kMagicNumber = 0xBadDead;
+ static const unsigned kCurrentVersion = 5;
+
+ static const int kMagicOffset = 0;
+ static const int kVersionOffset = 1;
+ static const int kHasErrorOffset = 2;
+ static const int kFunctionsSizeOffset = 3;
+ static const int kSymbolCountOffset = 4;
+ static const int kSizeOffset = 5;
+ static const int kHeaderSize = 6;
+
+ // If encoding a message, the following positions are fixed.
+ static const int kMessageStartPos = 0;
+ static const int kMessageEndPos = 1;
+ static const int kMessageArgCountPos = 2;
+ static const int kMessageTextPos = 3;
+
+ static const byte kNumberTerminator = 0x80u;
+};
+
+
+// ----------------------------------------------------------------------------
+// ParserRecorder - Logging of preparser data.
+
+// Abstract interface for preparse data recorder.
+class ParserRecorder {
+ public:
+ ParserRecorder() { }
+ virtual ~ParserRecorder() { }
+
+ // Logs the scope and some details of a function literal in the source.
+ virtual void LogFunction(int start,
+ int end,
+ int literals,
+ int properties) = 0;
+
+ // Logs a symbol creation of a literal or identifier.
+ virtual void LogSymbol(int start, const char* symbol, int length) = 0;
+
+ // Logs an error message and marks the log as containing an error.
+ // Further logging will be ignored, and ExtractData will return a vector
+ // representing the error only.
+ virtual void LogMessage(int start,
+ int end,
+ const char* message,
+ const char* argument_opt) = 0;
+
+ virtual int function_position() = 0;
+
+ virtual int symbol_position() = 0;
+
+ virtual int symbol_ids() = 0;
+
+ virtual Vector<unsigned> ExtractData() = 0;
+
+ virtual void PauseRecording() = 0;
+
+ virtual void ResumeRecording() = 0;
+};
+
+
+// ----------------------------------------------------------------------------
+// FunctionLoggingParserRecorder - Record only function entries
+
+class FunctionLoggingParserRecorder : public ParserRecorder {
+ public:
+ FunctionLoggingParserRecorder();
+ virtual ~FunctionLoggingParserRecorder() {}
+
+ virtual void LogFunction(int start, int end, int literals, int properties) {
+ function_store_.Add(start);
+ function_store_.Add(end);
+ function_store_.Add(literals);
+ function_store_.Add(properties);
+ }
+
+ // Logs an error message and marks the log as containing an error.
+ // Further logging will be ignored, and ExtractData will return a vector
+ // representing the error only.
+ virtual void LogMessage(int start,
+ int end,
+ const char* message,
+ const char* argument_opt);
+
+ virtual int function_position() { return function_store_.size(); }
+
+
+ virtual Vector<unsigned> ExtractData() = 0;
+
+ virtual void PauseRecording() {
+ pause_count_++;
+ is_recording_ = false;
+ }
+
+ virtual void ResumeRecording() {
+ ASSERT(pause_count_ > 0);
+ if (--pause_count_ == 0) is_recording_ = !has_error();
+ }
+
+ protected:
+ bool has_error() {
+ return static_cast<bool>(preamble_[PreparseDataConstants::kHasErrorOffset]);
+ }
+
+ bool is_recording() {
+ return is_recording_;
+ }
+
+ void WriteString(Vector<const char> str);
+
+ Collector<unsigned> function_store_;
+ unsigned preamble_[PreparseDataConstants::kHeaderSize];
+ bool is_recording_;
+ int pause_count_;
+
+#ifdef DEBUG
+ int prev_start_;
+#endif
+};
+
+
+// ----------------------------------------------------------------------------
+// PartialParserRecorder - Record only function entries
+
+class PartialParserRecorder : public FunctionLoggingParserRecorder {
+ public:
+ PartialParserRecorder() : FunctionLoggingParserRecorder() { }
+ virtual void LogSymbol(int start, const char* symbol, int length) { }
+ virtual ~PartialParserRecorder() { }
+ virtual Vector<unsigned> ExtractData();
+ virtual int symbol_position() { return 0; }
+ virtual int symbol_ids() { return 0; }
+};
+
+
+// ----------------------------------------------------------------------------
+// CompleteParserRecorder - Record both function entries and symbols.
+
+class CompleteParserRecorder: public FunctionLoggingParserRecorder {
+ public:
+ CompleteParserRecorder();
+ virtual ~CompleteParserRecorder() { }
+
+ virtual void LogSymbol(int start, const char* symbol, int length);
+
+ virtual Vector<unsigned> ExtractData();
+
+ virtual int symbol_position() { return symbol_store_.size(); }
+ virtual int symbol_ids() { return symbol_id_; }
+
+ private:
+ static int vector_hash(Vector<const char> string) {
+ int hash = 0;
+ for (int i = 0; i < string.length(); i++) {
+ int c = string[i];
+ hash += c;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ return hash;
+ }
+
+ static bool vector_compare(void* a, void* b) {
+ Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
+ Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
+ int length = string1->length();
+ if (string2->length() != length) return false;
+ return memcmp(string1->start(), string2->start(), length) == 0;
+ }
+
+ // Write a non-negative number to the symbol store.
+ void WriteNumber(int number);
+
+ Collector<byte> symbol_store_;
+ Collector<Vector<const char> > symbol_entries_;
+ HashMap symbol_table_;
+ int symbol_id_;
+};
+
+
+} } // namespace v8::internal.
+
+#endif // V8_PREPARSER_DATA_H_
--- /dev/null
+// Copyright 2010 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 "../include/v8stdint.h"
+#include "unicode.h"
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "utils.h"
+#include "list.h"
+#include "scanner-base.h"
+#include "preparse-data.h"
+#include "preparser.h"
+
+namespace v8 {
+namespace preparser {
+
+// Preparsing checks a JavaScript program and emits preparse-data that helps
+// a later parsing to be faster.
+// See preparser-data.h for the data.
+
+// The PreParser checks that the syntax follows the grammar for JavaScript,
+// and collects some information about the program along the way.
+// The grammar check is only performed in order to understand the program
+// sufficiently to deduce some information about it, that can be used
+// to speed up later parsing. Finding errors is not the goal of pre-parsing,
+// rather it is to speed up properly written and correct programs.
+// That means that contextual checks (like a label being declared where
+// it is used) are generally omitted.
+
+namespace i = ::v8::internal;
+
+#define CHECK_OK ok); \
+ if (!*ok) return -1; \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
+
+void PreParser::ReportUnexpectedToken(i::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 == i::Token::ILLEGAL && scanner_->stack_overflow()) {
+ return;
+ }
+ i::JavaScriptScanner::Location source_location = scanner_->location();
+
+ // Four of the tokens are treated specially
+ switch (token) {
+ case i::Token::EOS:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_eos", NULL);
+ case i::Token::NUMBER:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token_number", NULL);
+ case i::Token::STRING:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token_string", NULL);
+ case i::Token::IDENTIFIER:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token_identifier", NULL);
+ default:
+ const char* name = i::Token::String(token);
+ ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token", name);
+ }
+}
+
+
+SourceElements PreParser::ParseSourceElements(int end_token,
+ bool* ok) {
+ // SourceElements ::
+ // (Statement)* <end_token>
+
+ while (peek() != end_token) {
+ ParseStatement(CHECK_OK);
+ }
+ return kUnknownSourceElements;
+}
+
+
+Statement PreParser::ParseStatement(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
+ switch (peek()) {
+ case i::Token::LBRACE:
+ return ParseBlock(ok);
+
+ case i::Token::CONST:
+ case i::Token::VAR:
+ return ParseVariableStatement(ok);
+
+ case i::Token::SEMICOLON:
+ Next();
+ return kUnknownStatement;
+
+ case i::Token::IF:
+ return ParseIfStatement(ok);
+
+ case i::Token::DO:
+ return ParseDoWhileStatement(ok);
+
+ case i::Token::WHILE:
+ return ParseWhileStatement(ok);
+
+ case i::Token::FOR:
+ return ParseForStatement(ok);
+
+ case i::Token::CONTINUE:
+ return ParseContinueStatement(ok);
+
+ case i::Token::BREAK:
+ return ParseBreakStatement(ok);
+
+ case i::Token::RETURN:
+ return ParseReturnStatement(ok);
+
+ case i::Token::WITH:
+ return ParseWithStatement(ok);
+
+ case i::Token::SWITCH:
+ return ParseSwitchStatement(ok);
+
+ case i::Token::THROW:
+ return ParseThrowStatement(ok);
+
+ case i::Token::TRY:
+ return ParseTryStatement(ok);
+
+ case i::Token::FUNCTION:
+ return ParseFunctionDeclaration(ok);
+
+ case i::Token::NATIVE:
+ return ParseNativeDeclaration(ok);
+
+ case i::Token::DEBUGGER:
+ return ParseDebuggerStatement(ok);
+
+ default:
+ return ParseExpressionOrLabelledStatement(ok);
+ }
+}
+
+
+Statement PreParser::ParseFunctionDeclaration(bool* ok) {
+ // FunctionDeclaration ::
+ // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+ Expect(i::Token::FUNCTION, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ ParseFunctionLiteral(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+// 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 PreParser::ParseNativeDeclaration(bool* ok) {
+ Expect(i::Token::NATIVE, CHECK_OK);
+ Expect(i::Token::FUNCTION, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
+ while (!done) {
+ ParseIdentifier(CHECK_OK);
+ done = (peek() == i::Token::RPAREN);
+ if (!done) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+ Expect(i::Token::SEMICOLON, CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseBlock(bool* ok) {
+ // Block ::
+ // '{' Statement* '}'
+
+ // Note that a Block does not introduce a new execution scope!
+ // (ECMA-262, 3rd, 12.2)
+ //
+ Expect(i::Token::LBRACE, CHECK_OK);
+ while (peek() != i::Token::RBRACE) {
+ ParseStatement(CHECK_OK);
+ }
+ Expect(i::Token::RBRACE, CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseVariableStatement(bool* ok) {
+ // VariableStatement ::
+ // VariableDeclarations ';'
+
+ Statement result = ParseVariableDeclarations(true, NULL, 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 also used for the parsing
+// of 'for-in' loops.
+Statement PreParser::ParseVariableDeclarations(bool accept_IN,
+ int* num_decl,
+ bool* ok) {
+ // VariableDeclarations ::
+ // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
+
+ if (peek() == i::Token::VAR) {
+ Consume(i::Token::VAR);
+ } else if (peek() == i::Token::CONST) {
+ Consume(i::Token::CONST);
+ } else {
+ *ok = false;
+ return 0;
+ }
+
+ // The scope of a variable/const declared anywhere inside a function
+ // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). .
+ int nvars = 0; // the number of variables declared
+ do {
+ // Parse variable name.
+ if (nvars > 0) Consume(i::Token::COMMA);
+ ParseIdentifier(CHECK_OK);
+ nvars++;
+ if (peek() == i::Token::ASSIGN) {
+ Expect(i::Token::ASSIGN, CHECK_OK);
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+ }
+ } while (peek() == i::Token::COMMA);
+
+ if (num_decl != NULL) *num_decl = nvars;
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseExpressionOrLabelledStatement(
+ bool* ok) {
+ // ExpressionStatement | LabelledStatement ::
+ // Expression ';'
+ // Identifier ':' Statement
+
+ Expression expr = ParseExpression(true, CHECK_OK);
+ if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
+ Consume(i::Token::COLON);
+ return ParseStatement(ok);
+ }
+ // Parsed expression statement.
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseIfStatement(bool* ok) {
+ // IfStatement ::
+ // 'if' '(' Expression ')' Statement ('else' Statement)?
+
+ Expect(i::Token::IF, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ ParseStatement(CHECK_OK);
+ if (peek() == i::Token::ELSE) {
+ Next();
+ ParseStatement(CHECK_OK);
+ }
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseContinueStatement(bool* ok) {
+ // ContinueStatement ::
+ // 'continue' [no line terminator] Identifier? ';'
+
+ Expect(i::Token::CONTINUE, CHECK_OK);
+ i::Token::Value tok = peek();
+ if (!scanner_->has_line_terminator_before_next() &&
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
+ ParseIdentifier(CHECK_OK);
+ }
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseBreakStatement(bool* ok) {
+ // BreakStatement ::
+ // 'break' [no line terminator] Identifier? ';'
+
+ Expect(i::Token::BREAK, CHECK_OK);
+ i::Token::Value tok = peek();
+ if (!scanner_->has_line_terminator_before_next() &&
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
+ ParseIdentifier(CHECK_OK);
+ }
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseReturnStatement(bool* ok) {
+ // ReturnStatement ::
+ // 'return' [no line terminator] 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(i::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.
+ // This is not handled during preparsing.
+
+ i::Token::Value tok = peek();
+ if (!scanner_->has_line_terminator_before_next() &&
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
+ ParseExpression(true, CHECK_OK);
+ }
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseWithStatement(bool* ok) {
+ // WithStatement ::
+ // 'with' '(' Expression ')' Statement
+ Expect(i::Token::WITH, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ scope_->EnterWith();
+ ParseStatement(CHECK_OK);
+ scope_->LeaveWith();
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseSwitchStatement(bool* ok) {
+ // SwitchStatement ::
+ // 'switch' '(' Expression ')' '{' CaseClause* '}'
+
+ Expect(i::Token::SWITCH, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ Expect(i::Token::LBRACE, CHECK_OK);
+ i::Token::Value token = peek();
+ while (token != i::Token::RBRACE) {
+ if (token == i::Token::CASE) {
+ Expect(i::Token::CASE, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::COLON, CHECK_OK);
+ } else if (token == i::Token::DEFAULT) {
+ Expect(i::Token::DEFAULT, CHECK_OK);
+ Expect(i::Token::COLON, CHECK_OK);
+ } else {
+ ParseStatement(CHECK_OK);
+ }
+ token = peek();
+ }
+ Expect(i::Token::RBRACE, CHECK_OK);
+
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseDoWhileStatement(bool* ok) {
+ // DoStatement ::
+ // 'do' Statement 'while' '(' Expression ')' ';'
+
+ Expect(i::Token::DO, CHECK_OK);
+ ParseStatement(CHECK_OK);
+ Expect(i::Token::WHILE, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseWhileStatement(bool* ok) {
+ // WhileStatement ::
+ // 'while' '(' Expression ')' Statement
+
+ Expect(i::Token::WHILE, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseForStatement(bool* ok) {
+ // ForStatement ::
+ // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
+
+ Expect(i::Token::FOR, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ if (peek() != i::Token::SEMICOLON) {
+ if (peek() == i::Token::VAR || peek() == i::Token::CONST) {
+ int decl_count;
+ ParseVariableDeclarations(false, &decl_count, CHECK_OK);
+ if (peek() == i::Token::IN && decl_count == 1) {
+ Expect(i::Token::IN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+ }
+ } else {
+ ParseExpression(false, CHECK_OK);
+ if (peek() == i::Token::IN) {
+ Expect(i::Token::IN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+ }
+ }
+ }
+
+ // Parsed initializer at this point.
+ Expect(i::Token::SEMICOLON, CHECK_OK);
+
+ if (peek() != i::Token::SEMICOLON) {
+ ParseExpression(true, CHECK_OK);
+ }
+ Expect(i::Token::SEMICOLON, CHECK_OK);
+
+ if (peek() != i::Token::RPAREN) {
+ ParseExpression(true, CHECK_OK);
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseThrowStatement(bool* ok) {
+ // ThrowStatement ::
+ // 'throw' [no line terminator] Expression ';'
+
+ Expect(i::Token::THROW, CHECK_OK);
+ if (scanner_->has_line_terminator_before_next()) {
+ i::JavaScriptScanner::Location pos = scanner_->location();
+ ReportMessageAt(pos.beg_pos, pos.end_pos,
+ "newline_after_throw", NULL);
+ *ok = false;
+ return kUnknownStatement;
+ }
+ ParseExpression(true, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseTryStatement(bool* ok) {
+ // TryStatement ::
+ // 'try' Block Catch
+ // 'try' Block Finally
+ // 'try' Block Catch Finally
+ //
+ // Catch ::
+ // 'catch' '(' Identifier ')' Block
+ //
+ // Finally ::
+ // 'finally' Block
+
+ // In preparsing, allow any number of catch/finally blocks, including zero
+ // of both.
+
+ Expect(i::Token::TRY, CHECK_OK);
+
+ ParseBlock(CHECK_OK);
+
+ bool catch_or_finally_seen = false;
+ if (peek() == i::Token::CATCH) {
+ Consume(i::Token::CATCH);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ scope_->EnterWith();
+ ParseBlock(ok);
+ scope_->LeaveWith();
+ if (!*ok) return kUnknownStatement;
+ catch_or_finally_seen = true;
+ }
+ if (peek() == i::Token::FINALLY) {
+ Consume(i::Token::FINALLY);
+ ParseBlock(CHECK_OK);
+ catch_or_finally_seen = true;
+ }
+ if (!catch_or_finally_seen) {
+ *ok = false;
+ }
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::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 if a
+ // break point is present.
+ // DebuggerStatement ::
+ // 'debugger' ';'
+
+ Expect(i::Token::DEBUGGER, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+// Precedence = 1
+Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
+ // Expression ::
+ // AssignmentExpression
+ // Expression ',' AssignmentExpression
+
+ Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ while (peek() == i::Token::COMMA) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+ result = kUnknownExpression;
+ }
+ return result;
+}
+
+
+// Precedence = 2
+Expression PreParser::ParseAssignmentExpression(bool accept_IN,
+ bool* ok) {
+ // AssignmentExpression ::
+ // ConditionalExpression
+ // LeftHandSideExpression AssignmentOperator AssignmentExpression
+
+ Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
+
+ if (!i::Token::IsAssignmentOp(peek())) {
+ // Parsed conditional expression only (no assignment).
+ return expression;
+ }
+
+ i::Token::Value op = Next(); // Get assignment operator.
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+
+ if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
+ scope_->AddProperty();
+ }
+
+ return kUnknownExpression;
+}
+
+
+// Precedence = 3
+Expression PreParser::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() != i::Token::CONDITIONAL) return expression;
+ Consume(i::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.
+ ParseAssignmentExpression(true, CHECK_OK);
+ Expect(i::Token::COLON, CHECK_OK);
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+ return kUnknownExpression;
+}
+
+
+int PreParser::Precedence(i::Token::Value tok, bool accept_IN) {
+ if (tok == i::Token::IN && !accept_IN)
+ return 0; // 0 precedence will terminate binary expression parsing
+
+ return i::Token::Precedence(tok);
+}
+
+
+// Precedence >= 4
+Expression PreParser::ParseBinaryExpression(int prec,
+ bool accept_IN,
+ bool* ok) {
+ Expression result = ParseUnaryExpression(CHECK_OK);
+ for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
+ // prec1 >= 4
+ while (Precedence(peek(), accept_IN) == prec1) {
+ Next();
+ ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
+ result = kUnknownExpression;
+ }
+ }
+ return result;
+}
+
+
+Expression PreParser::ParseUnaryExpression(bool* ok) {
+ // UnaryExpression ::
+ // PostfixExpression
+ // 'delete' UnaryExpression
+ // 'void' UnaryExpression
+ // 'typeof' UnaryExpression
+ // '++' UnaryExpression
+ // '--' UnaryExpression
+ // '+' UnaryExpression
+ // '-' UnaryExpression
+ // '~' UnaryExpression
+ // '!' UnaryExpression
+
+ i::Token::Value op = peek();
+ if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
+ op = Next();
+ ParseUnaryExpression(ok);
+ return kUnknownExpression;
+ } else {
+ return ParsePostfixExpression(ok);
+ }
+}
+
+
+Expression PreParser::ParsePostfixExpression(bool* ok) {
+ // PostfixExpression ::
+ // LeftHandSideExpression ('++' | '--')?
+
+ Expression expression = ParseLeftHandSideExpression(CHECK_OK);
+ if (!scanner_->has_line_terminator_before_next() &&
+ i::Token::IsCountOp(peek())) {
+ Next();
+ return kUnknownExpression;
+ }
+ return expression;
+}
+
+
+Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
+ // LeftHandSideExpression ::
+ // (NewExpression | MemberExpression) ...
+
+ Expression result;
+ if (peek() == i::Token::NEW) {
+ result = ParseNewExpression(CHECK_OK);
+ } else {
+ result = ParseMemberExpression(CHECK_OK);
+ }
+
+ while (true) {
+ switch (peek()) {
+ case i::Token::LBRACK: {
+ Consume(i::Token::LBRACK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RBRACK, CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+
+ case i::Token::LPAREN: {
+ ParseArguments(CHECK_OK);
+ result = kUnknownExpression;
+ break;
+ }
+
+ case i::Token::PERIOD: {
+ Consume(i::Token::PERIOD);
+ ParseIdentifierName(CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+
+ default:
+ return result;
+ }
+ }
+}
+
+
+Expression PreParser::ParseNewExpression(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
+ unsigned new_count = 0;
+ do {
+ Consume(i::Token::NEW);
+ new_count++;
+ } while (peek() == i::Token::NEW);
+
+ return ParseMemberWithNewPrefixesExpression(new_count, ok);
+}
+
+
+Expression PreParser::ParseMemberExpression(bool* ok) {
+ return ParseMemberWithNewPrefixesExpression(0, ok);
+}
+
+
+Expression PreParser::ParseMemberWithNewPrefixesExpression(
+ unsigned new_count, bool* ok) {
+ // MemberExpression ::
+ // (PrimaryExpression | FunctionLiteral)
+ // ('[' Expression ']' | '.' Identifier | Arguments)*
+
+ // Parse the initial primary or function expression.
+ Expression result = kUnknownExpression;
+ if (peek() == i::Token::FUNCTION) {
+ Consume(i::Token::FUNCTION);
+ if (peek() == i::Token::IDENTIFIER) {
+ ParseIdentifier(CHECK_OK);
+ }
+ result = ParseFunctionLiteral(CHECK_OK);
+ } else {
+ result = ParsePrimaryExpression(CHECK_OK);
+ }
+
+ while (true) {
+ switch (peek()) {
+ case i::Token::LBRACK: {
+ Consume(i::Token::LBRACK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RBRACK, CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+ case i::Token::PERIOD: {
+ Consume(i::Token::PERIOD);
+ ParseIdentifierName(CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+ case i::Token::LPAREN: {
+ if (new_count == 0) return result;
+ // Consume one of the new prefixes (already parsed).
+ ParseArguments(CHECK_OK);
+ new_count--;
+ result = kUnknownExpression;
+ break;
+ }
+ default:
+ return result;
+ }
+ }
+}
+
+
+Expression PreParser::ParsePrimaryExpression(bool* ok) {
+ // PrimaryExpression ::
+ // 'this'
+ // 'null'
+ // 'true'
+ // 'false'
+ // Identifier
+ // Number
+ // String
+ // ArrayLiteral
+ // ObjectLiteral
+ // RegExpLiteral
+ // '(' Expression ')'
+
+ Expression result = kUnknownExpression;
+ switch (peek()) {
+ case i::Token::THIS: {
+ Next();
+ result = kThisExpression;
+ break;
+ }
+
+ case i::Token::IDENTIFIER: {
+ ParseIdentifier(CHECK_OK);
+ result = kIdentifierExpression;
+ break;
+ }
+
+ case i::Token::NULL_LITERAL:
+ case i::Token::TRUE_LITERAL:
+ case i::Token::FALSE_LITERAL:
+ case i::Token::NUMBER: {
+ Next();
+ break;
+ }
+ case i::Token::STRING: {
+ Next();
+ result = GetStringSymbol();
+ break;
+ }
+
+ case i::Token::ASSIGN_DIV:
+ result = ParseRegExpLiteral(true, CHECK_OK);
+ break;
+
+ case i::Token::DIV:
+ result = ParseRegExpLiteral(false, CHECK_OK);
+ break;
+
+ case i::Token::LBRACK:
+ result = ParseArrayLiteral(CHECK_OK);
+ break;
+
+ case i::Token::LBRACE:
+ result = ParseObjectLiteral(CHECK_OK);
+ break;
+
+ case i::Token::LPAREN:
+ Consume(i::Token::LPAREN);
+ result = ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ if (result == kIdentifierExpression) result = kUnknownExpression;
+ break;
+
+ case i::Token::MOD:
+ result = ParseV8Intrinsic(CHECK_OK);
+ break;
+
+ default: {
+ Next();
+ *ok = false;
+ return kUnknownExpression;
+ }
+ }
+
+ return result;
+}
+
+
+Expression PreParser::ParseArrayLiteral(bool* ok) {
+ // ArrayLiteral ::
+ // '[' Expression? (',' Expression?)* ']'
+ Expect(i::Token::LBRACK, CHECK_OK);
+ while (peek() != i::Token::RBRACK) {
+ if (peek() != i::Token::COMMA) {
+ ParseAssignmentExpression(true, CHECK_OK);
+ }
+ if (peek() != i::Token::RBRACK) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ }
+ Expect(i::Token::RBRACK, CHECK_OK);
+
+ scope_->NextMaterializedLiteralIndex();
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::ParseObjectLiteral(bool* ok) {
+ // ObjectLiteral ::
+ // '{' (
+ // ((IdentifierName | String | Number) ':' AssignmentExpression)
+ // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
+ // )*[','] '}'
+
+ Expect(i::Token::LBRACE, CHECK_OK);
+ while (peek() != i::Token::RBRACE) {
+ i::Token::Value next = peek();
+ switch (next) {
+ case i::Token::IDENTIFIER: {
+ bool is_getter = false;
+ bool is_setter = false;
+ ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+ if ((is_getter || is_setter) && peek() != i::Token::COLON) {
+ i::Token::Value name = Next();
+ if (name != i::Token::IDENTIFIER &&
+ name != i::Token::NUMBER &&
+ name != i::Token::STRING &&
+ !i::Token::IsKeyword(name)) {
+ *ok = false;
+ return kUnknownExpression;
+ }
+ ParseFunctionLiteral(CHECK_OK);
+ if (peek() != i::Token::RBRACE) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ continue; // restart the while
+ }
+ break;
+ }
+ case i::Token::STRING:
+ Consume(next);
+ GetStringSymbol();
+ break;
+ case i::Token::NUMBER:
+ Consume(next);
+ break;
+ default:
+ if (i::Token::IsKeyword(next)) {
+ Consume(next);
+ } else {
+ // Unexpected token.
+ *ok = false;
+ return kUnknownExpression;
+ }
+ }
+
+ Expect(i::Token::COLON, CHECK_OK);
+ ParseAssignmentExpression(true, CHECK_OK);
+
+ // TODO(1240767): Consider allowing trailing comma.
+ if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
+ }
+ Expect(i::Token::RBRACE, CHECK_OK);
+
+ scope_->NextMaterializedLiteralIndex();
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::ParseRegExpLiteral(bool seen_equal,
+ bool* ok) {
+ if (!scanner_->ScanRegExpPattern(seen_equal)) {
+ Next();
+ i::JavaScriptScanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "unterminated_regexp", NULL);
+ *ok = false;
+ return kUnknownExpression;
+ }
+
+ scope_->NextMaterializedLiteralIndex();
+
+ if (!scanner_->ScanRegExpFlags()) {
+ Next();
+ i::JavaScriptScanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "invalid_regexp_flags", NULL);
+ *ok = false;
+ return kUnknownExpression;
+ }
+ Next();
+ return kUnknownExpression;
+}
+
+
+Arguments PreParser::ParseArguments(bool* ok) {
+ // Arguments ::
+ // '(' (AssignmentExpression)*[','] ')'
+
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
+ int argc = 0;
+ while (!done) {
+ ParseAssignmentExpression(true, CHECK_OK);
+ argc++;
+ done = (peek() == i::Token::RPAREN);
+ if (!done) Expect(i::Token::COMMA, CHECK_OK);
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+ return argc;
+}
+
+
+Expression PreParser::ParseFunctionLiteral(bool* ok) {
+ // Function ::
+ // '(' FormalParameterList? ')' '{' FunctionBody '}'
+
+ // Parse function body.
+ ScopeType outer_scope_type = scope_->type();
+ bool inside_with = scope_->IsInsideWith();
+ Scope function_scope(&scope_, kFunctionScope);
+
+ // FormalParameterList ::
+ // '(' (Identifier)*[','] ')'
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
+ while (!done) {
+ ParseIdentifier(CHECK_OK);
+ done = (peek() == i::Token::RPAREN);
+ if (!done) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ Expect(i::Token::LBRACE, CHECK_OK);
+ int function_block_pos = scanner_->location().beg_pos;
+
+ // Determine if the function will be lazily compiled.
+ // Currently only happens to top-level functions.
+ // Optimistically assume that all top-level functions are lazily compiled.
+ bool is_lazily_compiled =
+ (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_);
+
+ if (is_lazily_compiled) {
+ log_->PauseRecording();
+ ParseSourceElements(i::Token::RBRACE, ok);
+ log_->ResumeRecording();
+ if (!*ok) return kUnknownExpression;
+
+ Expect(i::Token::RBRACE, CHECK_OK);
+
+ int end_pos = scanner_->location().end_pos;
+ log_->LogFunction(function_block_pos, end_pos,
+ function_scope.materialized_literal_count(),
+ function_scope.expected_properties());
+ } else {
+ ParseSourceElements(i::Token::RBRACE, CHECK_OK);
+ Expect(i::Token::RBRACE, CHECK_OK);
+ }
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::ParseV8Intrinsic(bool* ok) {
+ // CallRuntime ::
+ // '%' Identifier Arguments
+
+ Expect(i::Token::MOD, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ ParseArguments(CHECK_OK);
+
+ return kUnknownExpression;
+}
+
+
+void PreParser::ExpectSemicolon(bool* ok) {
+ // Check for automatic semicolon insertion according to
+ // the rules given in ECMA-262, section 7.9, page 21.
+ i::Token::Value tok = peek();
+ if (tok == i::Token::SEMICOLON) {
+ Next();
+ return;
+ }
+ if (scanner_->has_line_terminator_before_next() ||
+ tok == i::Token::RBRACE ||
+ tok == i::Token::EOS) {
+ return;
+ }
+ Expect(i::Token::SEMICOLON, ok);
+}
+
+
+Identifier PreParser::GetIdentifierSymbol() {
+ const char* literal_chars = scanner_->literal_string();
+ int literal_length = scanner_->literal_length();
+ int identifier_pos = scanner_->location().beg_pos;
+
+ log_->LogSymbol(identifier_pos, literal_chars, literal_length);
+
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::GetStringSymbol() {
+ const char* literal_chars = scanner_->literal_string();
+ int literal_length = scanner_->literal_length();
+
+ int literal_position = scanner_->location().beg_pos;
+ log_->LogSymbol(literal_position, literal_chars, literal_length);
+
+ return kUnknownExpression;
+}
+
+
+Identifier PreParser::ParseIdentifier(bool* ok) {
+ Expect(i::Token::IDENTIFIER, ok);
+ if (!*ok) return kUnknownIdentifier;
+ return GetIdentifierSymbol();
+}
+
+
+Identifier PreParser::ParseIdentifierName(bool* ok) {
+ i::Token::Value next = Next();
+ if (i::Token::IsKeyword(next)) {
+ int pos = scanner_->location().beg_pos;
+ const char* keyword = i::Token::String(next);
+ log_->LogSymbol(pos, keyword, i::StrLength(keyword));
+ return kUnknownExpression;
+ }
+ if (next == i::Token::IDENTIFIER) {
+ return GetIdentifierSymbol();
+ }
+ *ok = false;
+ return kUnknownIdentifier;
+}
+
+
+// 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.
+Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
+ bool* is_set,
+ bool* ok) {
+ Expect(i::Token::IDENTIFIER, CHECK_OK);
+ if (scanner_->literal_length() == 3) {
+ const char* token = scanner_->literal_string();
+ *is_get = strncmp(token, "get", 3) == 0;
+ *is_set = !*is_get && strncmp(token, "set", 3) == 0;
+ }
+ return GetIdentifierSymbol();
+}
+
+#undef CHECK_OK
+} } // v8::preparser
#ifndef V8_PREPARSER_H
#define V8_PREPARSER_H
-#include "unicode.h"
-#include "utils.h"
-
namespace v8 {
namespace preparser {
// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
-// See preparser-data.h for the data.
+// See preparse-data.h for the data.
// The PreParser checks that the syntax follows the grammar for JavaScript,
// and collects some information about the program along the way.
typedef int Arguments;
-template <typename Scanner, typename PreParserLog>
class PreParser {
public:
PreParser() : scope_(NULL), allow_lazy_(true) { }
// success (even if parsing failed, the pre-parse data successfully
// captured the syntax error), and false if a stack-overflow happened
// during parsing.
- bool PreParseProgram(Scanner* scanner,
- PreParserLog* log,
+ bool PreParseProgram(i::JavaScriptScanner* scanner,
+ i::ParserRecorder* log,
bool allow_lazy) {
allow_lazy_ = allow_lazy;
scanner_ = scanner;
static int Precedence(i::Token::Value tok, bool accept_IN);
- Scanner* scanner_;
- PreParserLog* log_;
+ i::JavaScriptScanner* scanner_;
+ i::ParserRecorder* log_;
Scope* scope_;
bool allow_lazy_;
};
-
-
-#define CHECK_OK ok); \
- if (!*ok) return -1; \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
-
-
-template <typename Scanner, typename Log>
-void PreParser<Scanner, Log>::ReportUnexpectedToken(i::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 == i::Token::ILLEGAL && scanner_->stack_overflow()) {
- return;
- }
- typename Scanner::Location source_location = scanner_->location();
-
- // Four of the tokens are treated specially
- switch (token) {
- case i::Token::EOS:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_eos", NULL);
- case i::Token::NUMBER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_number", NULL);
- case i::Token::STRING:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_string", NULL);
- case i::Token::IDENTIFIER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_identifier", NULL);
- default:
- const char* name = i::Token::String(token);
- ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token", name);
- }
-}
-
-
-template <typename Scanner, typename Log>
-SourceElements PreParser<Scanner, Log>::ParseSourceElements(int end_token,
- bool* ok) {
- // SourceElements ::
- // (Statement)* <end_token>
-
- while (peek() != end_token) {
- ParseStatement(CHECK_OK);
- }
- return kUnknownSourceElements;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseStatement(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
- switch (peek()) {
- case i::Token::LBRACE:
- return ParseBlock(ok);
-
- case i::Token::CONST:
- case i::Token::VAR:
- return ParseVariableStatement(ok);
-
- case i::Token::SEMICOLON:
- Next();
- return kUnknownStatement;
-
- case i::Token::IF:
- return ParseIfStatement(ok);
-
- case i::Token::DO:
- return ParseDoWhileStatement(ok);
-
- case i::Token::WHILE:
- return ParseWhileStatement(ok);
-
- case i::Token::FOR:
- return ParseForStatement(ok);
-
- case i::Token::CONTINUE:
- return ParseContinueStatement(ok);
-
- case i::Token::BREAK:
- return ParseBreakStatement(ok);
-
- case i::Token::RETURN:
- return ParseReturnStatement(ok);
-
- case i::Token::WITH:
- return ParseWithStatement(ok);
-
- case i::Token::SWITCH:
- return ParseSwitchStatement(ok);
-
- case i::Token::THROW:
- return ParseThrowStatement(ok);
-
- case i::Token::TRY:
- return ParseTryStatement(ok);
-
- case i::Token::FUNCTION:
- return ParseFunctionDeclaration(ok);
-
- case i::Token::NATIVE:
- return ParseNativeDeclaration(ok);
-
- case i::Token::DEBUGGER:
- return ParseDebuggerStatement(ok);
-
- default:
- return ParseExpressionOrLabelledStatement(ok);
- }
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseFunctionDeclaration(bool* ok) {
- // FunctionDeclaration ::
- // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
- Expect(i::Token::FUNCTION, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- ParseFunctionLiteral(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-// 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.
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseNativeDeclaration(bool* ok) {
- Expect(i::Token::NATIVE, CHECK_OK);
- Expect(i::Token::FUNCTION, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- bool done = (peek() == i::Token::RPAREN);
- while (!done) {
- ParseIdentifier(CHECK_OK);
- done = (peek() == i::Token::RPAREN);
- if (!done) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- }
- Expect(i::Token::RPAREN, CHECK_OK);
- Expect(i::Token::SEMICOLON, CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseBlock(bool* ok) {
- // Block ::
- // '{' Statement* '}'
-
- // Note that a Block does not introduce a new execution scope!
- // (ECMA-262, 3rd, 12.2)
- //
- Expect(i::Token::LBRACE, CHECK_OK);
- while (peek() != i::Token::RBRACE) {
- ParseStatement(CHECK_OK);
- }
- Expect(i::Token::RBRACE, CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseVariableStatement(bool* ok) {
- // VariableStatement ::
- // VariableDeclarations ';'
-
- Statement result = ParseVariableDeclarations(true, NULL, 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 also used for the parsing
-// of 'for-in' loops.
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseVariableDeclarations(bool accept_IN,
- int* num_decl,
- bool* ok) {
- // VariableDeclarations ::
- // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
-
- if (peek() == i::Token::VAR) {
- Consume(i::Token::VAR);
- } else if (peek() == i::Token::CONST) {
- Consume(i::Token::CONST);
- } else {
- *ok = false;
- return 0;
- }
-
- // The scope of a variable/const declared anywhere inside a function
- // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). .
- int nvars = 0; // the number of variables declared
- do {
- // Parse variable name.
- if (nvars > 0) Consume(i::Token::COMMA);
- ParseIdentifier(CHECK_OK);
- nvars++;
- if (peek() == i::Token::ASSIGN) {
- Expect(i::Token::ASSIGN, CHECK_OK);
- ParseAssignmentExpression(accept_IN, CHECK_OK);
- }
- } while (peek() == i::Token::COMMA);
-
- if (num_decl != NULL) *num_decl = nvars;
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseExpressionOrLabelledStatement(
- bool* ok) {
- // ExpressionStatement | LabelledStatement ::
- // Expression ';'
- // Identifier ':' Statement
-
- Expression expr = ParseExpression(true, CHECK_OK);
- if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
- Consume(i::Token::COLON);
- return ParseStatement(ok);
- }
- // Parsed expression statement.
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseIfStatement(bool* ok) {
- // IfStatement ::
- // 'if' '(' Expression ')' Statement ('else' Statement)?
-
- Expect(i::Token::IF, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
- if (peek() == i::Token::ELSE) {
- Next();
- ParseStatement(CHECK_OK);
- }
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseContinueStatement(bool* ok) {
- // ContinueStatement ::
- // 'continue' [no line terminator] Identifier? ';'
-
- Expect(i::Token::CONTINUE, CHECK_OK);
- i::Token::Value tok = peek();
- if (!scanner_->has_line_terminator_before_next() &&
- tok != i::Token::SEMICOLON &&
- tok != i::Token::RBRACE &&
- tok != i::Token::EOS) {
- ParseIdentifier(CHECK_OK);
- }
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseBreakStatement(bool* ok) {
- // BreakStatement ::
- // 'break' [no line terminator] Identifier? ';'
-
- Expect(i::Token::BREAK, CHECK_OK);
- i::Token::Value tok = peek();
- if (!scanner_->has_line_terminator_before_next() &&
- tok != i::Token::SEMICOLON &&
- tok != i::Token::RBRACE &&
- tok != i::Token::EOS) {
- ParseIdentifier(CHECK_OK);
- }
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseReturnStatement(bool* ok) {
- // ReturnStatement ::
- // 'return' [no line terminator] 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(i::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.
- // This is not handled during preparsing.
-
- i::Token::Value tok = peek();
- if (!scanner_->has_line_terminator_before_next() &&
- tok != i::Token::SEMICOLON &&
- tok != i::Token::RBRACE &&
- tok != i::Token::EOS) {
- ParseExpression(true, CHECK_OK);
- }
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseWithStatement(bool* ok) {
- // WithStatement ::
- // 'with' '(' Expression ')' Statement
- Expect(i::Token::WITH, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- scope_->EnterWith();
- ParseStatement(CHECK_OK);
- scope_->LeaveWith();
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseSwitchStatement(bool* ok) {
- // SwitchStatement ::
- // 'switch' '(' Expression ')' '{' CaseClause* '}'
-
- Expect(i::Token::SWITCH, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- Expect(i::Token::LBRACE, CHECK_OK);
- i::Token::Value token = peek();
- while (token != i::Token::RBRACE) {
- if (token == i::Token::CASE) {
- Expect(i::Token::CASE, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::COLON, CHECK_OK);
- } else if (token == i::Token::DEFAULT) {
- Expect(i::Token::DEFAULT, CHECK_OK);
- Expect(i::Token::COLON, CHECK_OK);
- } else {
- ParseStatement(CHECK_OK);
- }
- token = peek();
- }
- Expect(i::Token::RBRACE, CHECK_OK);
-
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseDoWhileStatement(bool* ok) {
- // DoStatement ::
- // 'do' Statement 'while' '(' Expression ')' ';'
-
- Expect(i::Token::DO, CHECK_OK);
- ParseStatement(CHECK_OK);
- Expect(i::Token::WHILE, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseWhileStatement(bool* ok) {
- // WhileStatement ::
- // 'while' '(' Expression ')' Statement
-
- Expect(i::Token::WHILE, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseForStatement(bool* ok) {
- // ForStatement ::
- // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
-
- Expect(i::Token::FOR, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- if (peek() != i::Token::SEMICOLON) {
- if (peek() == i::Token::VAR || peek() == i::Token::CONST) {
- int decl_count;
- ParseVariableDeclarations(false, &decl_count, CHECK_OK);
- if (peek() == i::Token::IN && decl_count == 1) {
- Expect(i::Token::IN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
- }
- } else {
- ParseExpression(false, CHECK_OK);
- if (peek() == i::Token::IN) {
- Expect(i::Token::IN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
- }
- }
- }
-
- // Parsed initializer at this point.
- Expect(i::Token::SEMICOLON, CHECK_OK);
-
- if (peek() != i::Token::SEMICOLON) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(i::Token::SEMICOLON, CHECK_OK);
-
- if (peek() != i::Token::RPAREN) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(i::Token::RPAREN, CHECK_OK);
-
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseThrowStatement(bool* ok) {
- // ThrowStatement ::
- // 'throw' [no line terminator] Expression ';'
-
- Expect(i::Token::THROW, CHECK_OK);
- if (scanner_->has_line_terminator_before_next()) {
- typename Scanner::Location pos = scanner_->location();
- ReportMessageAt(pos.beg_pos, pos.end_pos,
- "newline_after_throw", NULL);
- *ok = false;
- return kUnknownStatement;
- }
- ParseExpression(true, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
-
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseTryStatement(bool* ok) {
- // TryStatement ::
- // 'try' Block Catch
- // 'try' Block Finally
- // 'try' Block Catch Finally
- //
- // Catch ::
- // 'catch' '(' Identifier ')' Block
- //
- // Finally ::
- // 'finally' Block
-
- // In preparsing, allow any number of catch/finally blocks, including zero
- // of both.
-
- Expect(i::Token::TRY, CHECK_OK);
-
- ParseBlock(CHECK_OK);
-
- bool catch_or_finally_seen = false;
- if (peek() == i::Token::CATCH) {
- Consume(i::Token::CATCH);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- scope_->EnterWith();
- ParseBlock(ok);
- scope_->LeaveWith();
- if (!*ok) return kUnknownStatement;
- catch_or_finally_seen = true;
- }
- if (peek() == i::Token::FINALLY) {
- Consume(i::Token::FINALLY);
- ParseBlock(CHECK_OK);
- catch_or_finally_seen = true;
- }
- if (!catch_or_finally_seen) {
- *ok = false;
- }
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::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 if a
- // break point is present.
- // DebuggerStatement ::
- // 'debugger' ';'
-
- Expect(i::Token::DEBUGGER, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-// Precedence = 1
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseExpression(bool accept_IN, bool* ok) {
- // Expression ::
- // AssignmentExpression
- // Expression ',' AssignmentExpression
-
- Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
- while (peek() == i::Token::COMMA) {
- Expect(i::Token::COMMA, CHECK_OK);
- ParseAssignmentExpression(accept_IN, CHECK_OK);
- result = kUnknownExpression;
- }
- return result;
-}
-
-
-// Precedence = 2
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseAssignmentExpression(bool accept_IN,
- bool* ok) {
- // AssignmentExpression ::
- // ConditionalExpression
- // LeftHandSideExpression AssignmentOperator AssignmentExpression
-
- Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
-
- if (!i::Token::IsAssignmentOp(peek())) {
- // Parsed conditional expression only (no assignment).
- return expression;
- }
-
- i::Token::Value op = Next(); // Get assignment operator.
- ParseAssignmentExpression(accept_IN, CHECK_OK);
-
- if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
- scope_->AddProperty();
- }
-
- return kUnknownExpression;
-}
-
-
-// Precedence = 3
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::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() != i::Token::CONDITIONAL) return expression;
- Consume(i::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.
- ParseAssignmentExpression(true, CHECK_OK);
- Expect(i::Token::COLON, CHECK_OK);
- ParseAssignmentExpression(accept_IN, CHECK_OK);
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-int PreParser<Scanner, Log>::Precedence(i::Token::Value tok, bool accept_IN) {
- if (tok == i::Token::IN && !accept_IN)
- return 0; // 0 precedence will terminate binary expression parsing
-
- return i::Token::Precedence(tok);
-}
-
-
-// Precedence >= 4
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseBinaryExpression(int prec,
- bool accept_IN,
- bool* ok) {
- Expression result = ParseUnaryExpression(CHECK_OK);
- for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
- // prec1 >= 4
- while (Precedence(peek(), accept_IN) == prec1) {
- Next();
- ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
- result = kUnknownExpression;
- }
- }
- return result;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseUnaryExpression(bool* ok) {
- // UnaryExpression ::
- // PostfixExpression
- // 'delete' UnaryExpression
- // 'void' UnaryExpression
- // 'typeof' UnaryExpression
- // '++' UnaryExpression
- // '--' UnaryExpression
- // '+' UnaryExpression
- // '-' UnaryExpression
- // '~' UnaryExpression
- // '!' UnaryExpression
-
- i::Token::Value op = peek();
- if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
- op = Next();
- ParseUnaryExpression(ok);
- return kUnknownExpression;
- } else {
- return ParsePostfixExpression(ok);
- }
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParsePostfixExpression(bool* ok) {
- // PostfixExpression ::
- // LeftHandSideExpression ('++' | '--')?
-
- Expression expression = ParseLeftHandSideExpression(CHECK_OK);
- if (!scanner_->has_line_terminator_before_next() &&
- i::Token::IsCountOp(peek())) {
- Next();
- return kUnknownExpression;
- }
- return expression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseLeftHandSideExpression(bool* ok) {
- // LeftHandSideExpression ::
- // (NewExpression | MemberExpression) ...
-
- Expression result;
- if (peek() == i::Token::NEW) {
- result = ParseNewExpression(CHECK_OK);
- } else {
- result = ParseMemberExpression(CHECK_OK);
- }
-
- while (true) {
- switch (peek()) {
- case i::Token::LBRACK: {
- Consume(i::Token::LBRACK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RBRACK, CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
-
- case i::Token::LPAREN: {
- ParseArguments(CHECK_OK);
- result = kUnknownExpression;
- break;
- }
-
- case i::Token::PERIOD: {
- Consume(i::Token::PERIOD);
- ParseIdentifierName(CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
-
- default:
- return result;
- }
- }
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseNewExpression(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
- unsigned new_count = 0;
- do {
- Consume(i::Token::NEW);
- new_count++;
- } while (peek() == i::Token::NEW);
-
- return ParseMemberWithNewPrefixesExpression(new_count, ok);
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseMemberExpression(bool* ok) {
- return ParseMemberWithNewPrefixesExpression(0, ok);
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseMemberWithNewPrefixesExpression(
- unsigned new_count, bool* ok) {
- // MemberExpression ::
- // (PrimaryExpression | FunctionLiteral)
- // ('[' Expression ']' | '.' Identifier | Arguments)*
-
- // Parse the initial primary or function expression.
- Expression result = kUnknownExpression;
- if (peek() == i::Token::FUNCTION) {
- Consume(i::Token::FUNCTION);
- if (peek() == i::Token::IDENTIFIER) {
- ParseIdentifier(CHECK_OK);
- }
- result = ParseFunctionLiteral(CHECK_OK);
- } else {
- result = ParsePrimaryExpression(CHECK_OK);
- }
-
- while (true) {
- switch (peek()) {
- case i::Token::LBRACK: {
- Consume(i::Token::LBRACK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RBRACK, CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
- case i::Token::PERIOD: {
- Consume(i::Token::PERIOD);
- ParseIdentifierName(CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
- case i::Token::LPAREN: {
- if (new_count == 0) return result;
- // Consume one of the new prefixes (already parsed).
- ParseArguments(CHECK_OK);
- new_count--;
- result = kUnknownExpression;
- break;
- }
- default:
- return result;
- }
- }
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParsePrimaryExpression(bool* ok) {
- // PrimaryExpression ::
- // 'this'
- // 'null'
- // 'true'
- // 'false'
- // Identifier
- // Number
- // String
- // ArrayLiteral
- // ObjectLiteral
- // RegExpLiteral
- // '(' Expression ')'
-
- Expression result = kUnknownExpression;
- switch (peek()) {
- case i::Token::THIS: {
- Next();
- result = kThisExpression;
- break;
- }
-
- case i::Token::IDENTIFIER: {
- ParseIdentifier(CHECK_OK);
- result = kIdentifierExpression;
- break;
- }
-
- case i::Token::NULL_LITERAL:
- case i::Token::TRUE_LITERAL:
- case i::Token::FALSE_LITERAL:
- case i::Token::NUMBER: {
- Next();
- break;
- }
- case i::Token::STRING: {
- Next();
- result = GetStringSymbol();
- break;
- }
-
- case i::Token::ASSIGN_DIV:
- result = ParseRegExpLiteral(true, CHECK_OK);
- break;
-
- case i::Token::DIV:
- result = ParseRegExpLiteral(false, CHECK_OK);
- break;
-
- case i::Token::LBRACK:
- result = ParseArrayLiteral(CHECK_OK);
- break;
-
- case i::Token::LBRACE:
- result = ParseObjectLiteral(CHECK_OK);
- break;
-
- case i::Token::LPAREN:
- Consume(i::Token::LPAREN);
- result = ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- if (result == kIdentifierExpression) result = kUnknownExpression;
- break;
-
- case i::Token::MOD:
- result = ParseV8Intrinsic(CHECK_OK);
- break;
-
- default: {
- Next();
- *ok = false;
- return kUnknownExpression;
- }
- }
-
- return result;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseArrayLiteral(bool* ok) {
- // ArrayLiteral ::
- // '[' Expression? (',' Expression?)* ']'
- Expect(i::Token::LBRACK, CHECK_OK);
- while (peek() != i::Token::RBRACK) {
- if (peek() != i::Token::COMMA) {
- ParseAssignmentExpression(true, CHECK_OK);
- }
- if (peek() != i::Token::RBRACK) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- }
- Expect(i::Token::RBRACK, CHECK_OK);
-
- scope_->NextMaterializedLiteralIndex();
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseObjectLiteral(bool* ok) {
- // ObjectLiteral ::
- // '{' (
- // ((IdentifierName | String | Number) ':' AssignmentExpression)
- // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
- // )*[','] '}'
-
- Expect(i::Token::LBRACE, CHECK_OK);
- while (peek() != i::Token::RBRACE) {
- i::Token::Value next = peek();
- switch (next) {
- case i::Token::IDENTIFIER: {
- bool is_getter = false;
- bool is_setter = false;
- ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
- if ((is_getter || is_setter) && peek() != i::Token::COLON) {
- i::Token::Value name = Next();
- if (name != i::Token::IDENTIFIER &&
- name != i::Token::NUMBER &&
- name != i::Token::STRING &&
- !i::Token::IsKeyword(name)) {
- *ok = false;
- return kUnknownExpression;
- }
- ParseFunctionLiteral(CHECK_OK);
- if (peek() != i::Token::RBRACE) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- continue; // restart the while
- }
- break;
- }
- case i::Token::STRING:
- Consume(next);
- GetStringSymbol();
- break;
- case i::Token::NUMBER:
- Consume(next);
- break;
- default:
- if (i::Token::IsKeyword(next)) {
- Consume(next);
- } else {
- // Unexpected token.
- *ok = false;
- return kUnknownExpression;
- }
- }
-
- Expect(i::Token::COLON, CHECK_OK);
- ParseAssignmentExpression(true, CHECK_OK);
-
- // TODO(1240767): Consider allowing trailing comma.
- if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
- }
- Expect(i::Token::RBRACE, CHECK_OK);
-
- scope_->NextMaterializedLiteralIndex();
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseRegExpLiteral(bool seen_equal,
- bool* ok) {
- if (!scanner_->ScanRegExpPattern(seen_equal)) {
- Next();
- typename Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "unterminated_regexp", NULL);
- *ok = false;
- return kUnknownExpression;
- }
-
- scope_->NextMaterializedLiteralIndex();
-
- if (!scanner_->ScanRegExpFlags()) {
- Next();
- typename Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "invalid_regexp_flags", NULL);
- *ok = false;
- return kUnknownExpression;
- }
- Next();
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Arguments PreParser<Scanner, Log>::ParseArguments(bool* ok) {
- // Arguments ::
- // '(' (AssignmentExpression)*[','] ')'
-
- Expect(i::Token::LPAREN, CHECK_OK);
- bool done = (peek() == i::Token::RPAREN);
- int argc = 0;
- while (!done) {
- ParseAssignmentExpression(true, CHECK_OK);
- argc++;
- done = (peek() == i::Token::RPAREN);
- if (!done) Expect(i::Token::COMMA, CHECK_OK);
- }
- Expect(i::Token::RPAREN, CHECK_OK);
- return argc;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseFunctionLiteral(bool* ok) {
- // Function ::
- // '(' FormalParameterList? ')' '{' FunctionBody '}'
-
- // Parse function body.
- ScopeType outer_scope_type = scope_->type();
- bool inside_with = scope_->IsInsideWith();
- Scope function_scope(&scope_, kFunctionScope);
-
- // FormalParameterList ::
- // '(' (Identifier)*[','] ')'
- Expect(i::Token::LPAREN, CHECK_OK);
- bool done = (peek() == i::Token::RPAREN);
- while (!done) {
- ParseIdentifier(CHECK_OK);
- done = (peek() == i::Token::RPAREN);
- if (!done) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- }
- Expect(i::Token::RPAREN, CHECK_OK);
-
- Expect(i::Token::LBRACE, CHECK_OK);
- int function_block_pos = scanner_->location().beg_pos;
-
- // Determine if the function will be lazily compiled.
- // Currently only happens to top-level functions.
- // Optimistically assume that all top-level functions are lazily compiled.
- bool is_lazily_compiled =
- (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_);
-
- if (is_lazily_compiled) {
- log_->PauseRecording();
- ParseSourceElements(i::Token::RBRACE, ok);
- log_->ResumeRecording();
- if (!*ok) return kUnknownExpression;
-
- Expect(i::Token::RBRACE, CHECK_OK);
-
- int end_pos = scanner_->location().end_pos;
- log_->LogFunction(function_block_pos, end_pos,
- function_scope.materialized_literal_count(),
- function_scope.expected_properties());
- } else {
- ParseSourceElements(i::Token::RBRACE, CHECK_OK);
- Expect(i::Token::RBRACE, CHECK_OK);
- }
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseV8Intrinsic(bool* ok) {
- // CallRuntime ::
- // '%' Identifier Arguments
-
- Expect(i::Token::MOD, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- ParseArguments(CHECK_OK);
-
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-void PreParser<Scanner, Log>::ExpectSemicolon(bool* ok) {
- // Check for automatic semicolon insertion according to
- // the rules given in ECMA-262, section 7.9, page 21.
- i::Token::Value tok = peek();
- if (tok == i::Token::SEMICOLON) {
- Next();
- return;
- }
- if (scanner_->has_line_terminator_before_next() ||
- tok == i::Token::RBRACE ||
- tok == i::Token::EOS) {
- return;
- }
- Expect(i::Token::SEMICOLON, ok);
-}
-
-
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::GetIdentifierSymbol() {
- const char* literal_chars = scanner_->literal_string();
- int literal_length = scanner_->literal_length();
- int identifier_pos = scanner_->location().beg_pos;
-
- log_->LogSymbol(identifier_pos, literal_chars, literal_length);
-
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::GetStringSymbol() {
- const char* literal_chars = scanner_->literal_string();
- int literal_length = scanner_->literal_length();
-
- int literal_position = scanner_->location().beg_pos;
- log_->LogSymbol(literal_position, literal_chars, literal_length);
-
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::ParseIdentifier(bool* ok) {
- Expect(i::Token::IDENTIFIER, ok);
- if (!*ok) return kUnknownIdentifier;
- return GetIdentifierSymbol();
-}
-
-
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::ParseIdentifierName(bool* ok) {
- i::Token::Value next = Next();
- if (i::Token::IsKeyword(next)) {
- int pos = scanner_->location().beg_pos;
- const char* keyword = i::Token::String(next);
- log_->LogSymbol(pos, keyword, i::StrLength(keyword));
- return kUnknownExpression;
- }
- if (next == i::Token::IDENTIFIER) {
- return GetIdentifierSymbol();
- }
- *ok = false;
- return kUnknownIdentifier;
-}
-
-
-// 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.
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::ParseIdentifierOrGetOrSet(bool* is_get,
- bool* is_set,
- bool* ok) {
- Expect(i::Token::IDENTIFIER, CHECK_OK);
- if (scanner_->literal_length() == 3) {
- const char* token = scanner_->literal_string();
- *is_get = strncmp(token, "get", 3) == 0;
- *is_set = !*is_get && strncmp(token, "set", 3) == 0;
- }
- return GetIdentifierSymbol();
-}
-
-#undef CHECK_OK
} } // v8::preparser
#endif // V8_PREPARSER_H
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK(!sd->HasError());
// ScriptDataImpl private implementation details
- const int kHeaderSize = i::ScriptDataImpl::kHeaderSize;
+ const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
const int kFunctionEntrySize = i::FunctionEntry::kSize;
const int kFunctionEntryStartOffset = 0;
const int kFunctionEntryEndOffset = 1;
i::CompleteParserRecorder log;
i::V8JavaScriptScanner scanner;
scanner.Initialize(i::Handle<i::String>::null(), &stream);
- v8::preparser::PreParser<i::V8JavaScriptScanner,
- i::CompleteParserRecorder> preparser;
+ v8::preparser::PreParser preparser;
bool result = preparser.PreParseProgram(&scanner, &log, true);
CHECK(result);
i::ScriptDataImpl data(log.ExtractData());
>
</File>
<File
+ RelativePath="..\..\src\preparser.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\preparser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\preparse-data.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\preparse-data.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\profile-generator.cc"
>
</File>