Commit 1a169aa3 authored by lrn@chromium.org's avatar lrn@chromium.org

Strict mode detection in preparser.

Handle octal escapes in everything but RegExps.
Extend preparser test suite to test whether the preparser reports
exceptions to throw.

TEST=preparser/*

Review URL: http://codereview.chromium.org/6927075

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7804 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent cf191792
...@@ -66,7 +66,8 @@ ...@@ -66,7 +66,8 @@
namespace v8 { namespace v8 {
// The result of preparsing is either a stack overflow error, or an opaque
// blob of data that can be passed back into the parser.
class V8EXPORT PreParserData { class V8EXPORT PreParserData {
public: public:
PreParserData(size_t size, const uint8_t* data) PreParserData(size_t size, const uint8_t* data)
......
...@@ -28,16 +28,29 @@ ...@@ -28,16 +28,29 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "../include/v8stdint.h" #include "../include/v8stdint.h"
#include "../include/v8-preparser.h" #include "../include/v8-preparser.h"
#include "../src/preparse-data-format.h"
namespace i = v8::internal;
// This file is only used for testing the stand-alone preparser // This file is only used for testing the stand-alone preparser
// library. // library.
// The first (and only) argument must be the path of a JavaScript file. // The first argument must be the path of a JavaScript source file.
// This file is preparsed and the resulting preparser data is written // Optionally this can be followed by the word "throws" (case sensitive),
// to stdout. Diagnostic output is output on stderr. // which signals that the parsing is expected to throw - the default is
// The file must contain only ASCII characters (UTF-8 isn't supported). // to expect the parsing to not throw.
// The command line can further be followed by a message text (the
// *type* of the exception to throw), and even more optionally, the
// start and end position reported with the exception.
//
// This source file is preparsed and tested against the expectations, and if
// successful, the resulting preparser data is written to stdout.
// Diagnostic output is output on stderr.
// The source file must contain only ASCII characters (UTF-8 isn't supported).
// The file is read into memory, so it should have a reasonable size. // The file is read into memory, so it should have a reasonable size.
...@@ -97,6 +110,69 @@ bool WriteBuffer(FILE* dest, const void* buffer, size_t length) { ...@@ -97,6 +110,69 @@ bool WriteBuffer(FILE* dest, const void* buffer, size_t length) {
} }
class PreparseDataInterpreter {
public:
PreparseDataInterpreter(const uint8_t* data, int length)
: data_(data), length_(length), message_(NULL) { }
~PreparseDataInterpreter() {
if (message_ != NULL) delete[] message_;
}
bool valid() {
int header_length =
i::PreparseDataConstants::kHeaderSize * sizeof(int); // NOLINT
return length_ >= header_length;
}
bool throws() {
return valid() &&
word(i::PreparseDataConstants::kHasErrorOffset) != 0;
}
const char* message() {
if (message_ != NULL) return message_;
if (!throws()) return NULL;
int text_pos = i::PreparseDataConstants::kHeaderSize +
i::PreparseDataConstants::kMessageTextPos;
int length = word(text_pos);
char* buffer = new char[length + 1];
for (int i = 1; i <= length; i++) {
int character = word(text_pos + i);
buffer[i - 1] = character;
}
buffer[length] = '\0';
message_ = buffer;
return buffer;
}
int beg_pos() {
if (!throws()) return -1;
return word(i::PreparseDataConstants::kHeaderSize +
i::PreparseDataConstants::kMessageStartPos);
}
int end_pos() {
if (!throws()) return -1;
return word(i::PreparseDataConstants::kHeaderSize +
i::PreparseDataConstants::kMessageEndPos);
}
private:
int word(int offset) {
const int* word_data = reinterpret_cast<const int*>(data_);
if (word_data + offset < reinterpret_cast<const int*>(data_ + length_)) {
return word_data[offset];
}
return -1;
}
const uint8_t* const data_;
const int length_;
const char* message_;
};
template <typename T> template <typename T>
class ScopedPointer { class ScopedPointer {
public: public:
...@@ -109,15 +185,93 @@ class ScopedPointer { ...@@ -109,15 +185,93 @@ class ScopedPointer {
}; };
void fail(v8::PreParserData* data, const char* message, ...) {
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
fflush(stderr);
// Print preparser data to stdout.
uint32_t size = data->size();
fprintf(stderr, "LOG: data size: %u\n", size);
if (!WriteBuffer(stdout, data->data(), size)) {
perror("ERROR: Writing data");
fflush(stderr);
}
exit(EXIT_FAILURE);
};
void CheckException(v8::PreParserData* data,
bool throws,
const char* message,
int beg_pos,
int end_pos) {
PreparseDataInterpreter reader(data->data(), data->size());
if (throws) {
if (!reader.throws()) {
if (message == NULL) {
fail(data, "Didn't throw as expected\n");
} else {
fail(data, "Didn't throw \"%s\" as expected\n", message);
}
}
if (message != NULL) {
const char* actual_message = reader.message();
if (strcmp(message, actual_message)) {
fail(data, "Wrong error message. Expected <%s>, found <%s>\n",
message, actual_message);
}
}
if (beg_pos >= 0) {
if (beg_pos != reader.beg_pos()) {
fail(data, "Wrong error start position: Expected %i, found %i\n",
beg_pos, reader.beg_pos());
}
}
if (end_pos >= 0) {
if (end_pos != reader.end_pos()) {
fail(data, "Wrong error end position: Expected %i, found %i\n",
end_pos, reader.end_pos());
}
}
} else if (reader.throws()) {
const char* message = reader.message();
fail(data, "Throws unexpectedly with message: %s\n",
message);
}
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Check for filename argument. // Check for filename argument.
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "ERROR: No filename on command line.\n"); fail(NULL, "ERROR: No filename on command line.\n");
fflush(stderr);
return EXIT_FAILURE;
} }
const char* filename = argv[1]; const char* filename = argv[1];
// Parse expectations.
bool throws = false;
const char* throws_message = NULL;
int throws_beg_pos = -1;
int throws_end_pos = -1;
// Check for throws argument.
if (argc > 2) {
if (strncmp("throws", argv[2], 6)) {
fail(NULL, "ERROR: Extra arguments not prefixed by \"throws\".\n");
}
throws = true;
if (argc > 3) {
throws_message = argv[3];
}
if (argc > 4) {
throws_beg_pos = atoi(argv[4]);
}
if (argc > 5) {
throws_end_pos = atoi(argv[5]);
}
}
// Open JS file. // Open JS file.
FILE* input = fopen(filename, "rb"); FILE* input = fopen(filename, "rb");
if (input == NULL) { if (input == NULL) {
...@@ -151,19 +305,13 @@ int main(int argc, char* argv[]) { ...@@ -151,19 +305,13 @@ int main(int argc, char* argv[]) {
// Fail if stack overflow. // Fail if stack overflow.
if (data.stack_overflow()) { if (data.stack_overflow()) {
fprintf(stderr, "ERROR: Stack overflow\n"); fail(&data, "ERROR: Stack overflow\n");
fflush(stderr);
return EXIT_FAILURE;
} }
// Print preparser data to stdout. // Check that the expected exception is thrown, if an exception is
uint32_t size = data.size(); // expected.
fprintf(stderr, "LOG: Success, data size: %u\n", size); CheckException(&data, throws, throws_message,
fflush(stderr); throws_beg_pos, throws_end_pos);
if (!WriteBuffer(stdout, data.data(), size)) {
perror("ERROR: Writing data");
return EXIT_FAILURE;
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
...@@ -3543,9 +3543,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, ...@@ -3543,9 +3543,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
// '(' (Identifier)*[','] ')' // '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
start_pos = scanner().location().beg_pos; start_pos = scanner().location().beg_pos;
Scanner::Location name_loc = Scanner::NoLocation(); Scanner::Location name_loc = Scanner::Location::invalid();
Scanner::Location dupe_loc = Scanner::NoLocation(); Scanner::Location dupe_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::NoLocation(); Scanner::Location reserved_loc = Scanner::Location::invalid();
bool done = (peek() == Token::RPAREN); bool done = (peek() == Token::RPAREN);
while (!done) { while (!done) {
...@@ -3864,12 +3864,14 @@ void Parser::CheckStrictModeLValue(Expression* expression, ...@@ -3864,12 +3864,14 @@ void Parser::CheckStrictModeLValue(Expression* expression,
} }
// Checks whether octal literal last seen is between beg_pos and end_pos. // Checks whether an octal literal was last seen between beg_pos and end_pos.
// If so, reports an error. // If so, reports an error. Only called for strict mode.
void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
int octal = scanner().octal_position(); Scanner::Location octal = scanner().octal_position();
if (beg_pos <= octal && octal <= end_pos) { if (octal.IsValid() &&
ReportMessageAt(Scanner::Location(octal, octal + 1), "strict_octal_literal", beg_pos <= octal.beg_pos &&
octal.end_pos <= end_pos) {
ReportMessageAt(octal, "strict_octal_literal",
Vector<const char*>::empty()); Vector<const char*>::empty());
scanner().clear_octal_position(); scanner().clear_octal_position();
*ok = false; *ok = false;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "ast.h" #include "ast.h"
#include "scanner.h" #include "scanner.h"
#include "scopes.h" #include "scopes.h"
#include "preparse-data-format.h"
#include "preparse-data.h" #include "preparse-data.h"
namespace v8 { namespace v8 {
......
// 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_PREPARSE_DATA_FORMAT_H_
#define V8_PREPARSE_DATA_FORMAT_H_
namespace v8 {
namespace internal {
// Generic and general data used by preparse data recorders and readers.
struct PreparseDataConstants {
public:
// Layout and constants of the preparse data exchange format.
static const unsigned kMagicNumber = 0xBadDead;
static const unsigned kCurrentVersion = 6;
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 unsigned char kNumberTerminator = 0x80u;
};
} } // namespace v8::internal.
#endif // V8_PREPARSE_DATA_FORMAT_H_
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "../include/v8stdint.h" #include "../include/v8stdint.h"
#include "preparse-data-format.h"
#include "preparse-data.h" #include "preparse-data.h"
#include "checks.h" #include "checks.h"
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_PREPARSER_DATA_H_ #ifndef V8_PREPARSE_DATA_H_
#define V8_PREPARSER_DATA_H_ #define V8_PREPARSE_DATA_H_
#include "allocation.h" #include "allocation.h"
#include "hashmap.h" #include "hashmap.h"
...@@ -35,32 +35,6 @@ ...@@ -35,32 +35,6 @@
namespace v8 { namespace v8 {
namespace internal { 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 = 6;
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. // ParserRecorder - Logging of preparser data.
...@@ -248,4 +222,4 @@ class CompleteParserRecorder: public FunctionLoggingParserRecorder { ...@@ -248,4 +222,4 @@ class CompleteParserRecorder: public FunctionLoggingParserRecorder {
} } // namespace v8::internal. } } // namespace v8::internal.
#endif // V8_PREPARSER_DATA_H_ #endif // V8_PREPARSE_DATA_H_
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "utils.h" #include "utils.h"
#include "list.h" #include "list.h"
#include "scanner-base.h" #include "scanner-base.h"
#include "preparse-data-format.h"
#include "preparse-data.h" #include "preparse-data.h"
#include "preparser.h" #include "preparser.h"
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "list.h" #include "list.h"
#include "scanner-base.h" #include "scanner-base.h"
#include "preparse-data-format.h"
#include "preparse-data.h" #include "preparse-data.h"
#include "preparser.h" #include "preparser.h"
...@@ -94,13 +95,33 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) { ...@@ -94,13 +95,33 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
} }
// Checks whether octal literal last seen is between beg_pos and end_pos.
// If so, reports an error.
void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
i::Scanner::Location octal = scanner_->octal_position();
if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL);
scanner_->clear_octal_position();
*ok = false;
}
}
PreParser::SourceElements PreParser::ParseSourceElements(int end_token, PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
bool* ok) { bool* ok) {
// SourceElements :: // SourceElements ::
// (Statement)* <end_token> // (Statement)* <end_token>
bool allow_directive_prologue = true;
while (peek() != end_token) { while (peek() != end_token) {
ParseStatement(CHECK_OK); Statement statement = ParseStatement(CHECK_OK);
if (allow_directive_prologue) {
if (statement == kUseStrictExpressionStatement) {
set_strict_mode();
} else if (statement != kStringLiteralExpressionStatement) {
allow_directive_prologue = false;
}
}
} }
return kUnknownSourceElements; return kUnknownSourceElements;
} }
...@@ -299,10 +320,17 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement( ...@@ -299,10 +320,17 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
Expression expr = ParseExpression(true, CHECK_OK); Expression expr = ParseExpression(true, CHECK_OK);
if (peek() == i::Token::COLON && expr == kIdentifierExpression) { if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
Consume(i::Token::COLON); Consume(i::Token::COLON);
return ParseStatement(ok); ParseStatement(ok);
return kUnknownStatement;
} }
// Parsed expression statement. // Parsed expression statement.
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
if (expr == kStringLiteralExpression) {
return kStringLiteralExpressionStatement;
}
if (expr == kUseStrictString) {
return kUseStrictExpressionStatement;
}
return kUnknownStatement; return kUnknownStatement;
} }
...@@ -1057,10 +1085,10 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) { ...@@ -1057,10 +1085,10 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
ScopeType outer_scope_type = scope_->type(); ScopeType outer_scope_type = scope_->type();
bool inside_with = scope_->IsInsideWith(); bool inside_with = scope_->IsInsideWith();
Scope function_scope(&scope_, kFunctionScope); Scope function_scope(&scope_, kFunctionScope);
// FormalParameterList :: // FormalParameterList ::
// '(' (Identifier)*[','] ')' // '(' (Identifier)*[','] ')'
Expect(i::Token::LPAREN, CHECK_OK); Expect(i::Token::LPAREN, CHECK_OK);
int start_position = scanner_->location().beg_pos;
bool done = (peek() == i::Token::RPAREN); bool done = (peek() == i::Token::RPAREN);
while (!done) { while (!done) {
ParseIdentifier(CHECK_OK); ParseIdentifier(CHECK_OK);
...@@ -1099,6 +1127,12 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) { ...@@ -1099,6 +1127,12 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
ParseSourceElements(i::Token::RBRACE, CHECK_OK); ParseSourceElements(i::Token::RBRACE, CHECK_OK);
Expect(i::Token::RBRACE, CHECK_OK); Expect(i::Token::RBRACE, CHECK_OK);
} }
if (scope_->is_strict()) {
int end_position = scanner_->location().end_pos;
CheckOctalLiteral(start_position, end_position, CHECK_OK);
}
return kUnknownExpression; return kUnknownExpression;
} }
...@@ -1149,8 +1183,17 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() { ...@@ -1149,8 +1183,17 @@ PreParser::Identifier PreParser::GetIdentifierSymbol() {
PreParser::Expression PreParser::GetStringSymbol() { PreParser::Expression PreParser::GetStringSymbol() {
const int kUseStrictLength = 10;
const char* kUseStrictChars = "use strict";
LogSymbol(); LogSymbol();
return kUnknownExpression; if (scanner_->is_literal_ascii() &&
scanner_->literal_length() == kUseStrictLength &&
!scanner_->literal_contains_escapes() &&
!strncmp(scanner_->literal_ascii_string().start(), kUseStrictChars,
kUseStrictLength)) {
return kUseStrictString;
}
return kStringLiteralExpression;
} }
......
...@@ -33,7 +33,7 @@ namespace preparser { ...@@ -33,7 +33,7 @@ namespace preparser {
// Preparsing checks a JavaScript program and emits preparse-data that helps // Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster. // a later parsing to be faster.
// See preparse-data.h for the data. // See preparse-data-format.h for the data format.
// The PreParser checks that the syntax follows the grammar for JavaScript, // The PreParser checks that the syntax follows the grammar for JavaScript,
// and collects some information about the program along the way. // and collects some information about the program along the way.
...@@ -80,14 +80,18 @@ class PreParser { ...@@ -80,14 +80,18 @@ class PreParser {
// simple this-property assignments. // simple this-property assignments.
enum StatementType { enum StatementType {
kUnknownStatement kUnknownStatement,
kStringLiteralExpressionStatement,
kUseStrictExpressionStatement
}; };
enum ExpressionType { enum ExpressionType {
kUnknownExpression, kUnknownExpression,
kIdentifierExpression, // Used to detect labels. kIdentifierExpression, // Used to detect labels.
kThisExpression, kThisExpression,
kThisPropertyExpression kThisPropertyExpression,
kStringLiteralExpression,
kUseStrictString
}; };
enum IdentifierType { enum IdentifierType {
...@@ -95,7 +99,9 @@ class PreParser { ...@@ -95,7 +99,9 @@ class PreParser {
}; };
enum SourceElementTypes { enum SourceElementTypes {
kUnknownSourceElements kUnknownSourceElements,
kDirectivePrologue,
kUseStrictDirective
}; };
typedef int SourceElements; typedef int SourceElements;
...@@ -112,7 +118,8 @@ class PreParser { ...@@ -112,7 +118,8 @@ class PreParser {
type_(type), type_(type),
materialized_literal_count_(0), materialized_literal_count_(0),
expected_properties_(0), expected_properties_(0),
with_nesting_count_(0) { with_nesting_count_(0),
strict_((prev_ != NULL) && prev_->is_strict()) {
*variable = this; *variable = this;
} }
~Scope() { *variable_ = prev_; } ~Scope() { *variable_ = prev_; }
...@@ -122,6 +129,8 @@ class PreParser { ...@@ -122,6 +129,8 @@ class PreParser {
int expected_properties() { return expected_properties_; } int expected_properties() { return expected_properties_; }
int materialized_literal_count() { return materialized_literal_count_; } int materialized_literal_count() { return materialized_literal_count_; }
bool IsInsideWith() { return with_nesting_count_ != 0; } bool IsInsideWith() { return with_nesting_count_ != 0; }
bool is_strict() { return strict_; }
void set_strict() { strict_ = true; }
void EnterWith() { with_nesting_count_++; } void EnterWith() { with_nesting_count_++; }
void LeaveWith() { with_nesting_count_--; } void LeaveWith() { with_nesting_count_--; }
...@@ -132,6 +141,7 @@ class PreParser { ...@@ -132,6 +141,7 @@ class PreParser {
int materialized_literal_count_; int materialized_literal_count_;
int expected_properties_; int expected_properties_;
int with_nesting_count_; int with_nesting_count_;
bool strict_;
}; };
// Private constructor only used in PreParseProgram. // Private constructor only used in PreParseProgram.
...@@ -152,10 +162,13 @@ class PreParser { ...@@ -152,10 +162,13 @@ class PreParser {
PreParseResult PreParse() { PreParseResult PreParse() {
Scope top_scope(&scope_, kTopLevelScope); Scope top_scope(&scope_, kTopLevelScope);
bool ok = true; bool ok = true;
int start_position = scanner_->peek_location().beg_pos;
ParseSourceElements(i::Token::EOS, &ok); ParseSourceElements(i::Token::EOS, &ok);
if (stack_overflow_) return kPreParseStackOverflow; if (stack_overflow_) return kPreParseStackOverflow;
if (!ok) { if (!ok) {
ReportUnexpectedToken(scanner_->current_token()); ReportUnexpectedToken(scanner_->current_token());
} else if (scope_->is_strict()) {
CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
} }
return kPreParseSuccess; return kPreParseSuccess;
} }
...@@ -169,6 +182,8 @@ class PreParser { ...@@ -169,6 +182,8 @@ class PreParser {
log_->LogMessage(start_pos, end_pos, type, name_opt); log_->LogMessage(start_pos, end_pos, type, name_opt);
} }
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
// All ParseXXX functions take as the last argument an *ok parameter // All ParseXXX functions take as the last argument an *ok parameter
// which is set to false if parsing failed; it is unchanged otherwise. // which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check // By making the 'exception handling' explicit, we are forced to check
...@@ -245,6 +260,12 @@ class PreParser { ...@@ -245,6 +260,12 @@ class PreParser {
bool peek_any_identifier(); bool peek_any_identifier();
void set_strict_mode() {
scope_->set_strict();
}
bool is_strict_mode() { return scope_->is_strict(); }
void Consume(i::Token::Value token) { Next(); } void Consume(i::Token::Value token) { Next(); }
void Expect(i::Token::Value token, bool* ok) { void Expect(i::Token::Value token, bool* ok) {
......
...@@ -38,8 +38,7 @@ namespace internal { ...@@ -38,8 +38,7 @@ namespace internal {
// Scanner // Scanner
Scanner::Scanner(UnicodeCache* unicode_cache) Scanner::Scanner(UnicodeCache* unicode_cache)
: unicode_cache_(unicode_cache), : unicode_cache_(unicode_cache) { }
octal_pos_(kNoOctalLocation) { }
uc32 Scanner::ScanHexEscape(uc32 c, int length) { uc32 Scanner::ScanHexEscape(uc32 c, int length) {
...@@ -70,34 +69,12 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) { ...@@ -70,34 +69,12 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) {
} }
// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
// ECMA-262. Other JS VMs support them.
uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
uc32 x = c - '0';
int i = 0;
for (; i < length; i++) {
int d = c0_ - '0';
if (d < 0 || d > 7) break;
int nx = x * 8 + d;
if (nx >= 256) break;
x = nx;
Advance();
}
// Anything excelt '\0' is an octal escape sequence, illegal in strict mode.
// Remember the position of octal escape sequences so that better error
// can be reported later (in strict mode).
if (c != '0' || i > 0) {
octal_pos_ = source_pos() - i - 1; // Already advanced
}
return x;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// JavaScriptScanner // JavaScriptScanner
JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants) JavaScriptScanner::JavaScriptScanner(UnicodeCache* scanner_contants)
: Scanner(scanner_contants) { } : Scanner(scanner_contants), octal_pos_(Location::invalid()) { }
Token::Value JavaScriptScanner::Next() { Token::Value JavaScriptScanner::Next() {
...@@ -518,6 +495,31 @@ void JavaScriptScanner::ScanEscape() { ...@@ -518,6 +495,31 @@ void JavaScriptScanner::ScanEscape() {
} }
// Octal escapes of the forms '\0xx' and '\xxx' are not a part of
// ECMA-262. Other JS VMs support them.
uc32 JavaScriptScanner::ScanOctalEscape(uc32 c, int length) {
uc32 x = c - '0';
int i = 0;
for (; i < length; i++) {
int d = c0_ - '0';
if (d < 0 || d > 7) break;
int nx = x * 8 + d;
if (nx >= 256) break;
x = nx;
Advance();
}
// Anything except '\0' is an octal escape sequence, illegal in strict mode.
// Remember the position of octal escape sequences so that an error
// can be reported later (in strict mode).
// We don't report the error immediately, because the octal escape can
// occur before the "use strict" directive.
if (c != '0' || i > 0) {
octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
}
return x;
}
Token::Value JavaScriptScanner::ScanString() { Token::Value JavaScriptScanner::ScanString() {
uc32 quote = c0_; uc32 quote = c0_;
Advance(); // consume quote Advance(); // consume quote
...@@ -586,7 +588,7 @@ Token::Value JavaScriptScanner::ScanNumber(bool seen_period) { ...@@ -586,7 +588,7 @@ Token::Value JavaScriptScanner::ScanNumber(bool seen_period) {
} }
if (c0_ < '0' || '7' < c0_) { if (c0_ < '0' || '7' < c0_) {
// Octal literal finished. // Octal literal finished.
octal_pos_ = next_.location.beg_pos; octal_pos_ = next_.location;
break; break;
} }
AddLiteralCharAdvance(); AddLiteralCharAdvance();
...@@ -729,6 +731,9 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) { ...@@ -729,6 +731,9 @@ bool JavaScriptScanner::ScanRegExpPattern(bool seen_equal) {
// worrying whether the following characters are part of the escape // worrying whether the following characters are part of the escape
// or not, since any '/', '\\' or '[' is guaranteed to not be part // or not, since any '/', '\\' or '[' is guaranteed to not be part
// of the escape sequence. // of the escape sequence.
// TODO(896): At some point, parse RegExps more throughly to capture
// octal esacpes in strict mode.
} else { // Unescaped character. } else { // Unescaped character.
if (c0_ == '[') in_character_class = true; if (c0_ == '[') in_character_class = true;
if (c0_ == ']') in_character_class = false; if (c0_ == ']') in_character_class = false;
......
...@@ -286,23 +286,17 @@ class Scanner { ...@@ -286,23 +286,17 @@ class Scanner {
return beg_pos >= 0 && end_pos >= beg_pos; return beg_pos >= 0 && end_pos >= beg_pos;
} }
static Location invalid() { return Location(-1, -1); }
int beg_pos; int beg_pos;
int end_pos; int end_pos;
}; };
static Location NoLocation() {
return Location(-1, -1);
}
// Returns the location information for the current token // Returns the location information for the current token
// (the token returned by Next()). // (the token returned by Next()).
Location location() const { return current_.location; } Location location() const { return current_.location; }
Location peek_location() const { return next_.location; } Location peek_location() const { return next_.location; }
// Returns the location of the last seen octal literal
int octal_position() const { return octal_pos_; }
void clear_octal_position() { octal_pos_ = -1; }
// Returns the literal string, if any, for the current token (the // Returns the literal string, if any, for the current token (the
// token returned by Next()). The string is 0-terminated and in // token returned by Next()). The string is 0-terminated and in
// UTF-8 format; they may contain 0-characters. Literal strings are // UTF-8 format; they may contain 0-characters. Literal strings are
...@@ -326,6 +320,16 @@ class Scanner { ...@@ -326,6 +320,16 @@ class Scanner {
return current_.literal_chars->length(); return current_.literal_chars->length();
} }
bool literal_contains_escapes() const {
Location location = current_.location;
int source_length = (location.end_pos - location.beg_pos);
if (current_.token == Token::STRING) {
// Subtract delimiters.
source_length -= 2;
}
return current_.literal_chars->length() != source_length;
}
// Returns the literal string for the next token (the token that // Returns the literal string for the next token (the token that
// would be returned if Next() were called). // would be returned if Next() were called).
bool is_next_literal_ascii() { bool is_next_literal_ascii() {
...@@ -417,9 +421,6 @@ class Scanner { ...@@ -417,9 +421,6 @@ class Scanner {
uc32 ScanHexEscape(uc32 c, int length); uc32 ScanHexEscape(uc32 c, int length);
// Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
uc32 ScanOctalEscape(uc32 c, int length);
// Return the current source position. // Return the current source position.
int source_pos() { int source_pos() {
return source_->pos() - kCharacterLookaheadBufferSize; return source_->pos() - kCharacterLookaheadBufferSize;
...@@ -437,9 +438,6 @@ class Scanner { ...@@ -437,9 +438,6 @@ class Scanner {
// Input stream. Must be initialized to an UC16CharacterStream. // Input stream. Must be initialized to an UC16CharacterStream.
UC16CharacterStream* source_; UC16CharacterStream* source_;
// Start position of the octal literal last scanned.
int octal_pos_;
// One Unicode character look-ahead; c0_ < 0 at the end of the input. // One Unicode character look-ahead; c0_ < 0 at the end of the input.
uc32 c0_; uc32 c0_;
}; };
...@@ -492,6 +490,13 @@ class JavaScriptScanner : public Scanner { ...@@ -492,6 +490,13 @@ class JavaScriptScanner : public Scanner {
// Used for checking if a property name is an identifier. // Used for checking if a property name is an identifier.
static bool IsIdentifier(unibrow::CharacterStream* buffer); static bool IsIdentifier(unibrow::CharacterStream* buffer);
// Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
uc32 ScanOctalEscape(uc32 c, int length);
// Returns the location of the last seen octal literal
Location octal_position() const { return octal_pos_; }
void clear_octal_position() { octal_pos_ = Location::invalid(); }
// Seek forward to the given position. This operation does not // Seek forward to the given position. This operation does not
// work in general, for instance when there are pushed back // work in general, for instance when there are pushed back
// characters, but works for seeking forward until simple delimiter // characters, but works for seeking forward until simple delimiter
...@@ -521,6 +526,9 @@ class JavaScriptScanner : public Scanner { ...@@ -521,6 +526,9 @@ class JavaScriptScanner : public Scanner {
// If the escape sequence cannot be decoded the result is kBadChar. // If the escape sequence cannot be decoded the result is kBadChar.
uc32 ScanIdentifierUnicodeEscape(); uc32 ScanIdentifierUnicodeEscape();
// Start position of the octal literal last scanned.
Location octal_pos_;
bool has_line_terminator_before_next_; bool has_line_terminator_before_next_;
}; };
......
// Copyright 2011 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.
// A string looking like "use strict", but with a hex escape in it,
// doesn't trigger strict mode.
function foo() {
"use\x20strict";
var x = "hello\040world";
return x;
}
\ No newline at end of file
// Copyright 2011 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.
// A string looking like "use strict", but with an octal escape in it,
// doesn't trigger strict mode.
function foo() {
"use\040strict";
var x = "hello\040world";
return x;
}
\ No newline at end of file
// Copyright 2011 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.
// A string looking like "use strict", but with a long hex escape in it,
// doesn't trigger strict mode.
function foo() {
"use\u0020strict";
var x = "hello\040world";
return x;
}
\ No newline at end of file
# Expectations for preparser tests.
# Only mentions tests that throw SyntaxError, and optionally specifies
# the message and location expected in the exception.
# Format:
# testname[:message[:beg_pos,end_pos]]
strict-octal-string:strict_octal_literal
strict-octal-regexp:strict_octal_literal
strict-octal-directive-before:strict_octal_literal
strict-octal-directive-after:strict_octal_literal
strict-octal-use-strict-after:strict_octal_literal
strict-octal-use-strict-before:strict_octal_literal
# Copyright 2011 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.
prefix preparser
# We don't parse RegExps at scanning time, so we can't fail on octal
# escapes (we need to parse to distinguish octal escapes from valid
# back-references).
strict-octal-regexp: FAIL
##############################################################################
[ $arch == mips ]
# Skip all tests on MIPS.
*: SKIP
// Copyright 2011 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.
// Strict mode with octal escape in string/directive prologue after
// "use strict" directive.
function foo() {
"use strict";
"use hello\040world";
return true;
}
\ No newline at end of file
// Copyright 2011 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.
// Strict mode with octal escape in string/directive prologue prior to
// "use strict" directive.
function foo() {
"use hello\040world";
"use strict";
return true;
}
\ No newline at end of file
// Copyright 2011 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.
// Strict mode with call to RegExp containing octal escape:
function foo() {
"use strict";
var re = RegExp("Hello\\040World");
return re;
}
\ No newline at end of file
// Copyright 2011 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.
// Strict mode with octal escape in RegExp literal.
function foo() {
"use strict";
var re = /hello\040world/;
return re;
}
\ No newline at end of file
// Copyright 2011 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.
// Strict mode with octal escape in string literal.
function foo() {
"use strict";
var x = "hello\040world";
return x;
}
\ No newline at end of file
// Copyright 2011 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.
// Strict mode with octal escape in string/directive prologue looking like
// "use strict", after "use strict" directive.
function foo() {
"use strict";
"use\040strict";
return true;
}
\ No newline at end of file
// Copyright 2011 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.
// Strict mode with octal escape in string/directive prologue looking like
// "use strict, before "use strict" directive.
function foo() {
"use\040strict";
"use strict";
return true;
}
\ No newline at end of file
...@@ -30,14 +30,15 @@ import os ...@@ -30,14 +30,15 @@ import os
from os.path import join, dirname, exists from os.path import join, dirname, exists
import platform import platform
import utils import utils
import re
class PreparserTestCase(test.TestCase): class PreparserTestCase(test.TestCase):
def __init__(self, root, path, executable, mode, context): def __init__(self, root, path, executable, mode, throws, context):
super(PreparserTestCase, self).__init__(context, path, mode) super(PreparserTestCase, self).__init__(context, path, mode)
self.executable = executable self.executable = executable
self.root = root self.root = root
self.throws = throws
def GetLabel(self): def GetLabel(self):
return "%s %s %s" % (self.mode, self.path[-2], self.path[-1]) return "%s %s %s" % (self.mode, self.path[-2], self.path[-1])
...@@ -48,6 +49,8 @@ class PreparserTestCase(test.TestCase): ...@@ -48,6 +49,8 @@ class PreparserTestCase(test.TestCase):
def BuildCommand(self, path): def BuildCommand(self, path):
testfile = join(self.root, self.GetName()) + ".js" testfile = join(self.root, self.GetName()) + ".js"
result = [self.executable, testfile] result = [self.executable, testfile]
if (self.throws):
result += ['throws'] + self.throws
return result return result
def GetCommand(self): def GetCommand(self):
...@@ -65,19 +68,41 @@ class PreparserTestConfiguration(test.TestConfiguration): ...@@ -65,19 +68,41 @@ class PreparserTestConfiguration(test.TestConfiguration):
def GetBuildRequirements(self): def GetBuildRequirements(self):
return ['preparser'] return ['preparser']
def GetExpectations(self):
expects_file = join(self.root, 'preparser.expectation')
map = {}
if exists(expects_file):
rule_regex = re.compile("^([\w\-]+)(?::([\w\-]+))?(?::(\d+),(\d+))?$")
for line in utils.ReadLinesFrom(expects_file):
if (line[0] == '#'): continue
rule_match = rule_regex.match(line)
if rule_match:
expects = []
if (rule_match.group(2)):
expects = expects + [rule_match.group(2)]
if (rule_match.group(3)):
expects = expects + [rule_match.group(3), rule_match.group(4)]
map[rule_match.group(1)] = expects
return map;
def ListTests(self, current_path, path, mode, variant_flags): def ListTests(self, current_path, path, mode, variant_flags):
executable = join('obj', 'preparser', mode, 'preparser') executable = join('obj', 'preparser', mode, 'preparser')
if utils.IsWindows(): if utils.IsWindows():
executable += '.exe' executable += '.exe'
executable = join(self.context.buildspace, executable) executable = join(self.context.buildspace, executable)
expectations = self.GetExpectations()
# Find all .js files in tests/preparser directory. # Find all .js files in tests/preparser directory.
filenames = [f[:-3] for f in os.listdir(self.root) if f.endswith(".js")] filenames = [f[:-3] for f in os.listdir(self.root) if f.endswith(".js")]
filenames.sort() filenames.sort()
result = [] result = []
for file in filenames: for file in filenames:
throws = None;
if (file in expectations):
throws = expectations[file]
result.append(PreparserTestCase(self.root, result.append(PreparserTestCase(self.root,
current_path + [file], executable, current_path + [file], executable,
mode, self.context)) mode, throws, self.context))
return result return result
def GetTestStatus(self, sections, defs): def GetTestStatus(self, sections, defs):
......
...@@ -526,6 +526,7 @@ ...@@ -526,6 +526,7 @@
'../../src/platform-tls-win32.h', '../../src/platform-tls-win32.h',
'../../src/platform-tls.h', '../../src/platform-tls.h',
'../../src/platform.h', '../../src/platform.h',
'../../src/preparse-data-format.h',
'../../src/preparse-data.cc', '../../src/preparse-data.cc',
'../../src/preparse-data.h', '../../src/preparse-data.h',
'../../src/preparser.cc', '../../src/preparser.cc',
...@@ -591,7 +592,7 @@ ...@@ -591,7 +592,7 @@
'../../src/unicode-inl.h', '../../src/unicode-inl.h',
'../../src/unicode.cc', '../../src/unicode.cc',
'../../src/unicode.h', '../../src/unicode.h',
'../../src/utils-inl.h', '../../src/utils-inl.h',
'../../src/utils.cc', '../../src/utils.cc',
'../../src/utils.h', '../../src/utils.h',
'../../src/v8-counters.cc', '../../src/v8-counters.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment