84f2f5ee90
No scons target yet. Review URL: http://codereview.chromium.org/5295004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5899 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
272 lines
9.3 KiB
C++
272 lines
9.3 KiB
C++
// 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) { }
|
|
|
|
// 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);
|
|
|
|
Identifier GetIdentifierSymbol();
|
|
unsigned int HexDigitValue(char digit);
|
|
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();
|
|
}
|
|
|
|
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_;
|
|
};
|
|
} } // v8::preparser
|
|
|
|
#endif // V8_PREPARSER_H
|