// 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_H
#define V8_PREPARSER_H
namespace v8 {
namespace preparser {
// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
// 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.
// 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;
class PreParser {
public:
enum PreParseResult {
kPreParseStackOverflow,
kPreParseSuccess
};
~PreParser() { }
// Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully
// captured the syntax error), and false if a stack-overflow happened
// during parsing.
static PreParseResult PreParseProgram(i::JavaScriptScanner* scanner,
i::ParserRecorder* log,
bool allow_lazy,
uintptr_t stack_limit) {
return PreParser(scanner, log, stack_limit, allow_lazy).PreParse();
}
private:
enum ScopeType {
kTopLevelScope,
kFunctionScope
};
// Types that allow us to recognize simple this-property assignments.
// A simple this-property assignment is a statement on the form
// "this.propertyName = {primitive constant or function parameter name);"
// where propertyName isn't "__proto__".
// The result is only relevant if the function body contains only
// simple this-property assignments.
enum StatementType {
kUnknownStatement
};
enum ExpressionType {
kUnknownExpression,
kIdentifierExpression, // Used to detect labels.
kThisExpression,
kThisPropertyExpression
};
enum IdentifierType {
kUnknownIdentifier
};
enum SourceElementTypes {
kUnknownSourceElements
};
typedef int SourceElements;
typedef int Expression;
typedef int Statement;
typedef int Identifier;
typedef int Arguments;
class Scope {
public:
Scope(Scope** variable, ScopeType type)
: variable_(variable),
prev_(*variable),
type_(type),
materialized_literal_count_(0),
expected_properties_(0),
with_nesting_count_(0) {
*variable = this;
}
~Scope() { *variable_ = prev_; }
void NextMaterializedLiteralIndex() { materialized_literal_count_++; }
void AddProperty() { expected_properties_++; }
ScopeType type() { return type_; }
int expected_properties() { return expected_properties_; }
int materialized_literal_count() { return materialized_literal_count_; }
bool IsInsideWith() { return with_nesting_count_ != 0; }
void EnterWith() { with_nesting_count_++; }
void LeaveWith() { with_nesting_count_--; }
private:
Scope** const variable_;
Scope* const prev_;
const ScopeType type_;
int materialized_literal_count_;
int expected_properties_;
int with_nesting_count_;
};
// Private constructor only used in PreParseProgram.
PreParser(i::JavaScriptScanner* scanner,
i::ParserRecorder* log,
uintptr_t stack_limit,
bool allow_lazy)
: scanner_(scanner),
log_(log),
scope_(NULL),
stack_limit_(stack_limit),
stack_overflow_(false),
allow_lazy_(true),
parenthesized_function_(false) { }
// Preparse the program. Only called in PreParseProgram after creating
// the instance.
PreParseResult PreParse() {
Scope top_scope(&scope_, kTopLevelScope);
bool ok = true;
ParseSourceElements(i::Token::EOS, &ok);
if (stack_overflow_) return kPreParseStackOverflow;
if (!ok) {
ReportUnexpectedToken(scanner_->current_token());
}
return kPreParseSuccess;
}
// Report syntax error
void ReportUnexpectedToken(i::Token::Value token);
void ReportMessageAt(int start_pos,
int end_pos,
const char* type,
const char* name_opt) {
log_->LogMessage(start_pos, end_pos, type, name_opt);
}
// All ParseXXX functions take as the last argument an *ok parameter
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
SourceElements ParseSourceElements(int end_token, bool* ok);
Statement ParseStatement(bool* ok);
Statement ParseFunctionDeclaration(bool* ok);
Statement ParseNativeDeclaration(bool* ok);
Statement ParseBlock(bool* ok);
Statement ParseVariableStatement(bool* ok);
Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok);
Statement ParseExpressionOrLabelledStatement(bool* ok);
Statement ParseIfStatement(bool* ok);
Statement ParseContinueStatement(bool* ok);
Statement ParseBreakStatement(bool* ok);
Statement ParseReturnStatement(bool* ok);
Statement ParseWithStatement(bool* ok);
Statement ParseSwitchStatement(bool* ok);
Statement ParseDoWhileStatement(bool* ok);
Statement ParseWhileStatement(bool* ok);
Statement ParseForStatement(bool* ok);
Statement ParseThrowStatement(bool* ok);
Statement ParseTryStatement(bool* ok);
Statement ParseDebuggerStatement(bool* ok);
Expression ParseExpression(bool accept_IN, bool* ok);
Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok);
Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
Expression ParseUnaryExpression(bool* ok);
Expression ParsePostfixExpression(bool* ok);
Expression ParseLeftHandSideExpression(bool* ok);
Expression ParseNewExpression(bool* ok);
Expression ParseMemberExpression(bool* ok);
Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
Expression ParsePrimaryExpression(bool* ok);
Expression ParseArrayLiteral(bool* ok);
Expression ParseObjectLiteral(bool* ok);
Expression ParseRegExpLiteral(bool seen_equal, bool* ok);
Expression ParseV8Intrinsic(bool* ok);
Arguments ParseArguments(bool* ok);
Expression ParseFunctionLiteral(bool* ok);
Identifier ParseIdentifier(bool* ok);
Identifier ParseIdentifierName(bool* ok);
Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok);
// Logs the currently parsed literal as a symbol in the preparser data.
void LogSymbol();
// Log the currently parsed identifier.
Identifier GetIdentifierSymbol();
// Log the currently parsed string literal.
Expression GetStringSymbol();
i::Token::Value peek() {
if (stack_overflow_) return i::Token::ILLEGAL;
return scanner_->peek();
}
i::Token::Value Next() {
if (stack_overflow_) return i::Token::ILLEGAL;
{
int marker;
if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
// Further calls to peek/Next will return illegal token.
// The current one will still be returned. It might already
// have been seen using peek.
stack_overflow_ = true;
}
}
return scanner_->Next();
}
bool peek_any_identifier();
void Consume(i::Token::Value token) { Next(); }
void Expect(i::Token::Value token, bool* ok) {
if (Next() != token) {
*ok = false;
}
}
bool Check(i::Token::Value token) {
i::Token::Value next = peek();
if (next == token) {
Consume(next);
return true;
}
return false;
}
void ExpectSemicolon(bool* ok);
static int Precedence(i::Token::Value tok, bool accept_IN);
i::JavaScriptScanner* scanner_;
i::ParserRecorder* log_;
Scope* scope_;
uintptr_t stack_limit_;
bool stack_overflow_;
bool allow_lazy_;
bool parenthesized_function_;
};
} } // v8::preparser
#endif // V8_PREPARSER_H