mirror of https://github.com/lukechilds/node.git
Ryan Dahl
13 years ago
60 changed files with 3961 additions and 2776 deletions
File diff suppressed because it is too large
@ -1,562 +0,0 @@ |
|||
// 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.
|
|||
|
|||
// Features shared by parsing and pre-parsing scanners.
|
|||
|
|||
#ifndef V8_SCANNER_BASE_H_ |
|||
#define V8_SCANNER_BASE_H_ |
|||
|
|||
#include "allocation.h" |
|||
#include "char-predicates.h" |
|||
#include "checks.h" |
|||
#include "globals.h" |
|||
#include "token.h" |
|||
#include "unicode-inl.h" |
|||
#include "utils.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
// Returns the value (0 .. 15) of a hexadecimal character c.
|
|||
// If c is not a legal hexadecimal character, returns a value < 0.
|
|||
inline int HexValue(uc32 c) { |
|||
c -= '0'; |
|||
if (static_cast<unsigned>(c) <= 9) return c; |
|||
c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
|
|||
if (static_cast<unsigned>(c) <= 5) return c + 10; |
|||
return -1; |
|||
} |
|||
|
|||
|
|||
// ---------------------------------------------------------------------
|
|||
// Buffered stream of characters, using an internal UC16 buffer.
|
|||
|
|||
class UC16CharacterStream { |
|||
public: |
|||
UC16CharacterStream() : pos_(0) { } |
|||
virtual ~UC16CharacterStream() { } |
|||
|
|||
// Returns and advances past the next UC16 character in the input
|
|||
// stream. If there are no more characters, it returns a negative
|
|||
// value.
|
|||
inline uc32 Advance() { |
|||
if (buffer_cursor_ < buffer_end_ || ReadBlock()) { |
|||
pos_++; |
|||
return static_cast<uc32>(*(buffer_cursor_++)); |
|||
} |
|||
// Note: currently the following increment is necessary to avoid a
|
|||
// parser problem! The scanner treats the final kEndOfInput as
|
|||
// a character with a position, and does math relative to that
|
|||
// position.
|
|||
pos_++; |
|||
|
|||
return kEndOfInput; |
|||
} |
|||
|
|||
// Return the current position in the character stream.
|
|||
// Starts at zero.
|
|||
inline unsigned pos() const { return pos_; } |
|||
|
|||
// Skips forward past the next character_count UC16 characters
|
|||
// in the input, or until the end of input if that comes sooner.
|
|||
// Returns the number of characters actually skipped. If less
|
|||
// than character_count,
|
|||
inline unsigned SeekForward(unsigned character_count) { |
|||
unsigned buffered_chars = |
|||
static_cast<unsigned>(buffer_end_ - buffer_cursor_); |
|||
if (character_count <= buffered_chars) { |
|||
buffer_cursor_ += character_count; |
|||
pos_ += character_count; |
|||
return character_count; |
|||
} |
|||
return SlowSeekForward(character_count); |
|||
} |
|||
|
|||
// Pushes back the most recently read UC16 character (or negative
|
|||
// value if at end of input), i.e., the value returned by the most recent
|
|||
// call to Advance.
|
|||
// Must not be used right after calling SeekForward.
|
|||
virtual void PushBack(int32_t character) = 0; |
|||
|
|||
protected: |
|||
static const uc32 kEndOfInput = -1; |
|||
|
|||
// Ensures that the buffer_cursor_ points to the character at
|
|||
// position pos_ of the input, if possible. If the position
|
|||
// is at or after the end of the input, return false. If there
|
|||
// are more characters available, return true.
|
|||
virtual bool ReadBlock() = 0; |
|||
virtual unsigned SlowSeekForward(unsigned character_count) = 0; |
|||
|
|||
const uc16* buffer_cursor_; |
|||
const uc16* buffer_end_; |
|||
unsigned pos_; |
|||
}; |
|||
|
|||
|
|||
class UnicodeCache { |
|||
// ---------------------------------------------------------------------
|
|||
// Caching predicates used by scanners.
|
|||
public: |
|||
UnicodeCache() {} |
|||
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder; |
|||
|
|||
StaticResource<Utf8Decoder>* utf8_decoder() { |
|||
return &utf8_decoder_; |
|||
} |
|||
|
|||
bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); } |
|||
bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); } |
|||
bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); } |
|||
bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); } |
|||
|
|||
private: |
|||
|
|||
unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart; |
|||
unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart; |
|||
unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator; |
|||
unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace; |
|||
StaticResource<Utf8Decoder> utf8_decoder_; |
|||
|
|||
DISALLOW_COPY_AND_ASSIGN(UnicodeCache); |
|||
}; |
|||
|
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// LiteralBuffer - Collector of chars of literals.
|
|||
|
|||
class LiteralBuffer { |
|||
public: |
|||
LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { } |
|||
|
|||
~LiteralBuffer() { |
|||
if (backing_store_.length() > 0) { |
|||
backing_store_.Dispose(); |
|||
} |
|||
} |
|||
|
|||
inline void AddChar(uc16 character) { |
|||
if (position_ >= backing_store_.length()) ExpandBuffer(); |
|||
if (is_ascii_) { |
|||
if (character < kMaxAsciiCharCodeU) { |
|||
backing_store_[position_] = static_cast<byte>(character); |
|||
position_ += kASCIISize; |
|||
return; |
|||
} |
|||
ConvertToUC16(); |
|||
} |
|||
*reinterpret_cast<uc16*>(&backing_store_[position_]) = character; |
|||
position_ += kUC16Size; |
|||
} |
|||
|
|||
bool is_ascii() { return is_ascii_; } |
|||
|
|||
Vector<const uc16> uc16_literal() { |
|||
ASSERT(!is_ascii_); |
|||
ASSERT((position_ & 0x1) == 0); |
|||
return Vector<const uc16>( |
|||
reinterpret_cast<const uc16*>(backing_store_.start()), |
|||
position_ >> 1); |
|||
} |
|||
|
|||
Vector<const char> ascii_literal() { |
|||
ASSERT(is_ascii_); |
|||
return Vector<const char>( |
|||
reinterpret_cast<const char*>(backing_store_.start()), |
|||
position_); |
|||
} |
|||
|
|||
int length() { |
|||
return is_ascii_ ? position_ : (position_ >> 1); |
|||
} |
|||
|
|||
void Reset() { |
|||
position_ = 0; |
|||
is_ascii_ = true; |
|||
} |
|||
private: |
|||
static const int kInitialCapacity = 16; |
|||
static const int kGrowthFactory = 4; |
|||
static const int kMinConversionSlack = 256; |
|||
static const int kMaxGrowth = 1 * MB; |
|||
inline int NewCapacity(int min_capacity) { |
|||
int capacity = Max(min_capacity, backing_store_.length()); |
|||
int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth); |
|||
return new_capacity; |
|||
} |
|||
|
|||
void ExpandBuffer() { |
|||
Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity)); |
|||
memcpy(new_store.start(), backing_store_.start(), position_); |
|||
backing_store_.Dispose(); |
|||
backing_store_ = new_store; |
|||
} |
|||
|
|||
void ConvertToUC16() { |
|||
ASSERT(is_ascii_); |
|||
Vector<byte> new_store; |
|||
int new_content_size = position_ * kUC16Size; |
|||
if (new_content_size >= backing_store_.length()) { |
|||
// Ensure room for all currently read characters as UC16 as well
|
|||
// as the character about to be stored.
|
|||
new_store = Vector<byte>::New(NewCapacity(new_content_size)); |
|||
} else { |
|||
new_store = backing_store_; |
|||
} |
|||
char* src = reinterpret_cast<char*>(backing_store_.start()); |
|||
uc16* dst = reinterpret_cast<uc16*>(new_store.start()); |
|||
for (int i = position_ - 1; i >= 0; i--) { |
|||
dst[i] = src[i]; |
|||
} |
|||
if (new_store.start() != backing_store_.start()) { |
|||
backing_store_.Dispose(); |
|||
backing_store_ = new_store; |
|||
} |
|||
position_ = new_content_size; |
|||
is_ascii_ = false; |
|||
} |
|||
|
|||
bool is_ascii_; |
|||
int position_; |
|||
Vector<byte> backing_store_; |
|||
|
|||
DISALLOW_COPY_AND_ASSIGN(LiteralBuffer); |
|||
}; |
|||
|
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// Scanner base-class.
|
|||
|
|||
// Generic functionality used by both JSON and JavaScript scanners.
|
|||
class Scanner { |
|||
public: |
|||
// -1 is outside of the range of any real source code.
|
|||
static const int kNoOctalLocation = -1; |
|||
|
|||
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder; |
|||
|
|||
class LiteralScope { |
|||
public: |
|||
explicit LiteralScope(Scanner* self); |
|||
~LiteralScope(); |
|||
void Complete(); |
|||
|
|||
private: |
|||
Scanner* scanner_; |
|||
bool complete_; |
|||
}; |
|||
|
|||
explicit Scanner(UnicodeCache* scanner_contants); |
|||
|
|||
// Returns the current token again.
|
|||
Token::Value current_token() { return current_.token; } |
|||
|
|||
// One token look-ahead (past the token returned by Next()).
|
|||
Token::Value peek() const { return next_.token; } |
|||
|
|||
struct Location { |
|||
Location(int b, int e) : beg_pos(b), end_pos(e) { } |
|||
Location() : beg_pos(0), end_pos(0) { } |
|||
|
|||
bool IsValid() const { |
|||
return beg_pos >= 0 && end_pos >= beg_pos; |
|||
} |
|||
|
|||
static Location invalid() { return Location(-1, -1); } |
|||
|
|||
int beg_pos; |
|||
int end_pos; |
|||
}; |
|||
|
|||
// Returns the location information for the current token
|
|||
// (the token returned by Next()).
|
|||
Location location() const { return current_.location; } |
|||
Location peek_location() const { return next_.location; } |
|||
|
|||
// Returns the literal string, if any, for the current token (the
|
|||
// token returned by Next()). The string is 0-terminated and in
|
|||
// UTF-8 format; they may contain 0-characters. Literal strings are
|
|||
// collected for identifiers, strings, and numbers.
|
|||
// These functions only give the correct result if the literal
|
|||
// was scanned between calls to StartLiteral() and TerminateLiteral().
|
|||
bool is_literal_ascii() { |
|||
ASSERT_NOT_NULL(current_.literal_chars); |
|||
return current_.literal_chars->is_ascii(); |
|||
} |
|||
Vector<const char> literal_ascii_string() { |
|||
ASSERT_NOT_NULL(current_.literal_chars); |
|||
return current_.literal_chars->ascii_literal(); |
|||
} |
|||
Vector<const uc16> literal_uc16_string() { |
|||
ASSERT_NOT_NULL(current_.literal_chars); |
|||
return current_.literal_chars->uc16_literal(); |
|||
} |
|||
int literal_length() const { |
|||
ASSERT_NOT_NULL(current_.literal_chars); |
|||
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
|
|||
// would be returned if Next() were called).
|
|||
bool is_next_literal_ascii() { |
|||
ASSERT_NOT_NULL(next_.literal_chars); |
|||
return next_.literal_chars->is_ascii(); |
|||
} |
|||
Vector<const char> next_literal_ascii_string() { |
|||
ASSERT_NOT_NULL(next_.literal_chars); |
|||
return next_.literal_chars->ascii_literal(); |
|||
} |
|||
Vector<const uc16> next_literal_uc16_string() { |
|||
ASSERT_NOT_NULL(next_.literal_chars); |
|||
return next_.literal_chars->uc16_literal(); |
|||
} |
|||
int next_literal_length() const { |
|||
ASSERT_NOT_NULL(next_.literal_chars); |
|||
return next_.literal_chars->length(); |
|||
} |
|||
|
|||
static const int kCharacterLookaheadBufferSize = 1; |
|||
|
|||
protected: |
|||
// The current and look-ahead token.
|
|||
struct TokenDesc { |
|||
Token::Value token; |
|||
Location location; |
|||
LiteralBuffer* literal_chars; |
|||
}; |
|||
|
|||
// Call this after setting source_ to the input.
|
|||
void Init() { |
|||
// Set c0_ (one character ahead)
|
|||
STATIC_ASSERT(kCharacterLookaheadBufferSize == 1); |
|||
Advance(); |
|||
// Initialize current_ to not refer to a literal.
|
|||
current_.literal_chars = NULL; |
|||
} |
|||
|
|||
// Literal buffer support
|
|||
inline void StartLiteral() { |
|||
LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ? |
|||
&literal_buffer2_ : &literal_buffer1_; |
|||
free_buffer->Reset(); |
|||
next_.literal_chars = free_buffer; |
|||
} |
|||
|
|||
inline void AddLiteralChar(uc32 c) { |
|||
ASSERT_NOT_NULL(next_.literal_chars); |
|||
next_.literal_chars->AddChar(c); |
|||
} |
|||
|
|||
// Complete scanning of a literal.
|
|||
inline void TerminateLiteral() { |
|||
// Does nothing in the current implementation.
|
|||
} |
|||
|
|||
// Stops scanning of a literal and drop the collected characters,
|
|||
// e.g., due to an encountered error.
|
|||
inline void DropLiteral() { |
|||
next_.literal_chars = NULL; |
|||
} |
|||
|
|||
inline void AddLiteralCharAdvance() { |
|||
AddLiteralChar(c0_); |
|||
Advance(); |
|||
} |
|||
|
|||
// Low-level scanning support.
|
|||
void Advance() { c0_ = source_->Advance(); } |
|||
void PushBack(uc32 ch) { |
|||
source_->PushBack(c0_); |
|||
c0_ = ch; |
|||
} |
|||
|
|||
inline Token::Value Select(Token::Value tok) { |
|||
Advance(); |
|||
return tok; |
|||
} |
|||
|
|||
inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) { |
|||
Advance(); |
|||
if (c0_ == next) { |
|||
Advance(); |
|||
return then; |
|||
} else { |
|||
return else_; |
|||
} |
|||
} |
|||
|
|||
uc32 ScanHexNumber(int expected_length); |
|||
|
|||
// Return the current source position.
|
|||
int source_pos() { |
|||
return source_->pos() - kCharacterLookaheadBufferSize; |
|||
} |
|||
|
|||
UnicodeCache* unicode_cache_; |
|||
|
|||
// Buffers collecting literal strings, numbers, etc.
|
|||
LiteralBuffer literal_buffer1_; |
|||
LiteralBuffer literal_buffer2_; |
|||
|
|||
TokenDesc current_; // desc for current token (as returned by Next())
|
|||
TokenDesc next_; // desc for next token (one token look-ahead)
|
|||
|
|||
// Input stream. Must be initialized to an UC16CharacterStream.
|
|||
UC16CharacterStream* source_; |
|||
|
|||
// One Unicode character look-ahead; c0_ < 0 at the end of the input.
|
|||
uc32 c0_; |
|||
}; |
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// JavaScriptScanner - base logic for JavaScript scanning.
|
|||
|
|||
class JavaScriptScanner : public Scanner { |
|||
public: |
|||
// A LiteralScope that disables recording of some types of JavaScript
|
|||
// literals. If the scanner is configured to not record the specific
|
|||
// type of literal, the scope will not call StartLiteral.
|
|||
class LiteralScope { |
|||
public: |
|||
explicit LiteralScope(JavaScriptScanner* self) |
|||
: scanner_(self), complete_(false) { |
|||
scanner_->StartLiteral(); |
|||
} |
|||
~LiteralScope() { |
|||
if (!complete_) scanner_->DropLiteral(); |
|||
} |
|||
void Complete() { |
|||
scanner_->TerminateLiteral(); |
|||
complete_ = true; |
|||
} |
|||
|
|||
private: |
|||
JavaScriptScanner* scanner_; |
|||
bool complete_; |
|||
}; |
|||
|
|||
explicit JavaScriptScanner(UnicodeCache* scanner_contants); |
|||
|
|||
void Initialize(UC16CharacterStream* source); |
|||
|
|||
// Returns the next token.
|
|||
Token::Value Next(); |
|||
|
|||
// Returns true if there was a line terminator before the peek'ed token,
|
|||
// possibly inside a multi-line comment.
|
|||
bool HasAnyLineTerminatorBeforeNext() const { |
|||
return has_line_terminator_before_next_ || |
|||
has_multiline_comment_before_next_; |
|||
} |
|||
|
|||
// Scans the input as a regular expression pattern, previous
|
|||
// character(s) must be /(=). Returns true if a pattern is scanned.
|
|||
bool ScanRegExpPattern(bool seen_equal); |
|||
// Returns true if regexp flags are scanned (always since flags can
|
|||
// be empty).
|
|||
bool ScanRegExpFlags(); |
|||
|
|||
// Tells whether the buffer contains an identifier (no escapes).
|
|||
// Used for checking if a property name is an identifier.
|
|||
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
|
|||
// work in general, for instance when there are pushed back
|
|||
// characters, but works for seeking forward until simple delimiter
|
|||
// tokens, which is what it is used for.
|
|||
void SeekForward(int pos); |
|||
|
|||
bool HarmonyBlockScoping() const { |
|||
return harmony_block_scoping_; |
|||
} |
|||
void SetHarmonyBlockScoping(bool block_scoping) { |
|||
harmony_block_scoping_ = block_scoping; |
|||
} |
|||
|
|||
|
|||
protected: |
|||
bool SkipWhiteSpace(); |
|||
Token::Value SkipSingleLineComment(); |
|||
Token::Value SkipMultiLineComment(); |
|||
|
|||
// Scans a single JavaScript token.
|
|||
void Scan(); |
|||
|
|||
void ScanDecimalDigits(); |
|||
Token::Value ScanNumber(bool seen_period); |
|||
Token::Value ScanIdentifierOrKeyword(); |
|||
Token::Value ScanIdentifierSuffix(LiteralScope* literal); |
|||
|
|||
void ScanEscape(); |
|||
Token::Value ScanString(); |
|||
|
|||
// Scans a possible HTML comment -- begins with '<!'.
|
|||
Token::Value ScanHtmlComment(); |
|||
|
|||
// Decodes a unicode escape-sequence which is part of an identifier.
|
|||
// If the escape sequence cannot be decoded the result is kBadChar.
|
|||
uc32 ScanIdentifierUnicodeEscape(); |
|||
// Recognizes a uniocde escape-sequence and adds its characters,
|
|||
// uninterpreted, to the current literal. Used for parsing RegExp
|
|||
// flags.
|
|||
bool ScanLiteralUnicodeEscape(); |
|||
|
|||
// Start position of the octal literal last scanned.
|
|||
Location octal_pos_; |
|||
|
|||
// Whether there is a line terminator whitespace character after
|
|||
// the current token, and before the next. Does not count newlines
|
|||
// inside multiline comments.
|
|||
bool has_line_terminator_before_next_; |
|||
// Whether there is a multi-line comment that contains a
|
|||
// line-terminator after the current token, and before the next.
|
|||
bool has_multiline_comment_before_next_; |
|||
// Whether we scan 'let' as a keyword for harmony block scoped
|
|||
// let bindings.
|
|||
bool harmony_block_scoping_; |
|||
}; |
|||
|
|||
} } // namespace v8::internal
|
|||
|
|||
#endif // V8_SCANNER_BASE_H_
|
@ -0,0 +1,328 @@ |
|||
// 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.
|
|||
|
|||
#include "v8.h" |
|||
|
|||
#include "scanner-character-streams.h" |
|||
|
|||
#include "ast.h" |
|||
#include "handles.h" |
|||
#include "unicode-inl.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// BufferedUC16CharacterStreams
|
|||
|
|||
BufferedUC16CharacterStream::BufferedUC16CharacterStream() |
|||
: UC16CharacterStream(), |
|||
pushback_limit_(NULL) { |
|||
// Initialize buffer as being empty. First read will fill the buffer.
|
|||
buffer_cursor_ = buffer_; |
|||
buffer_end_ = buffer_; |
|||
} |
|||
|
|||
BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { } |
|||
|
|||
void BufferedUC16CharacterStream::PushBack(uc32 character) { |
|||
if (character == kEndOfInput) { |
|||
pos_--; |
|||
return; |
|||
} |
|||
if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) { |
|||
// buffer_ is writable, buffer_cursor_ is const pointer.
|
|||
buffer_[--buffer_cursor_ - buffer_] = static_cast<uc16>(character); |
|||
pos_--; |
|||
return; |
|||
} |
|||
SlowPushBack(static_cast<uc16>(character)); |
|||
} |
|||
|
|||
|
|||
void BufferedUC16CharacterStream::SlowPushBack(uc16 character) { |
|||
// In pushback mode, the end of the buffer contains pushback,
|
|||
// and the start of the buffer (from buffer start to pushback_limit_)
|
|||
// contains valid data that comes just after the pushback.
|
|||
// We NULL the pushback_limit_ if pushing all the way back to the
|
|||
// start of the buffer.
|
|||
|
|||
if (pushback_limit_ == NULL) { |
|||
// Enter pushback mode.
|
|||
pushback_limit_ = buffer_end_; |
|||
buffer_end_ = buffer_ + kBufferSize; |
|||
buffer_cursor_ = buffer_end_; |
|||
} |
|||
// Ensure that there is room for at least one pushback.
|
|||
ASSERT(buffer_cursor_ > buffer_); |
|||
ASSERT(pos_ > 0); |
|||
buffer_[--buffer_cursor_ - buffer_] = character; |
|||
if (buffer_cursor_ == buffer_) { |
|||
pushback_limit_ = NULL; |
|||
} else if (buffer_cursor_ < pushback_limit_) { |
|||
pushback_limit_ = buffer_cursor_; |
|||
} |
|||
pos_--; |
|||
} |
|||
|
|||
|
|||
bool BufferedUC16CharacterStream::ReadBlock() { |
|||
buffer_cursor_ = buffer_; |
|||
if (pushback_limit_ != NULL) { |
|||
// Leave pushback mode.
|
|||
buffer_end_ = pushback_limit_; |
|||
pushback_limit_ = NULL; |
|||
// If there were any valid characters left at the
|
|||
// start of the buffer, use those.
|
|||
if (buffer_cursor_ < buffer_end_) return true; |
|||
// Otherwise read a new block.
|
|||
} |
|||
unsigned length = FillBuffer(pos_, kBufferSize); |
|||
buffer_end_ = buffer_ + length; |
|||
return length > 0; |
|||
} |
|||
|
|||
|
|||
unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) { |
|||
// Leave pushback mode (i.e., ignore that there might be valid data
|
|||
// in the buffer before the pushback_limit_ point).
|
|||
pushback_limit_ = NULL; |
|||
return BufferSeekForward(delta); |
|||
} |
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// GenericStringUC16CharacterStream
|
|||
|
|||
|
|||
GenericStringUC16CharacterStream::GenericStringUC16CharacterStream( |
|||
Handle<String> data, |
|||
unsigned start_position, |
|||
unsigned end_position) |
|||
: string_(data), |
|||
length_(end_position) { |
|||
ASSERT(end_position >= start_position); |
|||
buffer_cursor_ = buffer_; |
|||
buffer_end_ = buffer_; |
|||
pos_ = start_position; |
|||
} |
|||
|
|||
|
|||
GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { } |
|||
|
|||
|
|||
unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) { |
|||
unsigned old_pos = pos_; |
|||
pos_ = Min(pos_ + delta, length_); |
|||
ReadBlock(); |
|||
return pos_ - old_pos; |
|||
} |
|||
|
|||
|
|||
unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos, |
|||
unsigned length) { |
|||
if (from_pos >= length_) return 0; |
|||
if (from_pos + length > length_) { |
|||
length = length_ - from_pos; |
|||
} |
|||
String::WriteToFlat<uc16>(*string_, buffer_, from_pos, from_pos + length); |
|||
return length; |
|||
} |
|||
|
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// Utf8ToUC16CharacterStream
|
|||
Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data, |
|||
unsigned length) |
|||
: BufferedUC16CharacterStream(), |
|||
raw_data_(data), |
|||
raw_data_length_(length), |
|||
raw_data_pos_(0), |
|||
raw_character_position_(0) { |
|||
ReadBlock(); |
|||
} |
|||
|
|||
|
|||
Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { } |
|||
|
|||
|
|||
unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) { |
|||
unsigned old_pos = pos_; |
|||
unsigned target_pos = pos_ + delta; |
|||
SetRawPosition(target_pos); |
|||
pos_ = raw_character_position_; |
|||
ReadBlock(); |
|||
return pos_ - old_pos; |
|||
} |
|||
|
|||
|
|||
unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position, |
|||
unsigned length) { |
|||
static const unibrow::uchar kMaxUC16Character = 0xffff; |
|||
SetRawPosition(char_position); |
|||
if (raw_character_position_ != char_position) { |
|||
// char_position was not a valid position in the stream (hit the end
|
|||
// while spooling to it).
|
|||
return 0u; |
|||
} |
|||
unsigned i = 0; |
|||
while (i < length) { |
|||
if (raw_data_pos_ == raw_data_length_) break; |
|||
unibrow::uchar c = raw_data_[raw_data_pos_]; |
|||
if (c <= unibrow::Utf8::kMaxOneByteChar) { |
|||
raw_data_pos_++; |
|||
} else { |
|||
c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_, |
|||
raw_data_length_ - raw_data_pos_, |
|||
&raw_data_pos_); |
|||
// Don't allow characters outside of the BMP.
|
|||
if (c > kMaxUC16Character) { |
|||
c = unibrow::Utf8::kBadChar; |
|||
} |
|||
} |
|||
buffer_[i++] = static_cast<uc16>(c); |
|||
} |
|||
raw_character_position_ = char_position + i; |
|||
return i; |
|||
} |
|||
|
|||
|
|||
static const byte kUtf8MultiByteMask = 0xC0; |
|||
static const byte kUtf8MultiByteCharStart = 0xC0; |
|||
static const byte kUtf8MultiByteCharFollower = 0x80; |
|||
|
|||
|
|||
#ifdef DEBUG |
|||
static bool IsUtf8MultiCharacterStart(byte first_byte) { |
|||
return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart; |
|||
} |
|||
#endif |
|||
|
|||
|
|||
static bool IsUtf8MultiCharacterFollower(byte later_byte) { |
|||
return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower; |
|||
} |
|||
|
|||
|
|||
// Move the cursor back to point at the preceding UTF-8 character start
|
|||
// in the buffer.
|
|||
static inline void Utf8CharacterBack(const byte* buffer, unsigned* cursor) { |
|||
byte character = buffer[--*cursor]; |
|||
if (character > unibrow::Utf8::kMaxOneByteChar) { |
|||
ASSERT(IsUtf8MultiCharacterFollower(character)); |
|||
// Last byte of a multi-byte character encoding. Step backwards until
|
|||
// pointing to the first byte of the encoding, recognized by having the
|
|||
// top two bits set.
|
|||
while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { } |
|||
ASSERT(IsUtf8MultiCharacterStart(buffer[*cursor])); |
|||
} |
|||
} |
|||
|
|||
|
|||
// Move the cursor forward to point at the next following UTF-8 character start
|
|||
// in the buffer.
|
|||
static inline void Utf8CharacterForward(const byte* buffer, unsigned* cursor) { |
|||
byte character = buffer[(*cursor)++]; |
|||
if (character > unibrow::Utf8::kMaxOneByteChar) { |
|||
// First character of a multi-byte character encoding.
|
|||
// The number of most-significant one-bits determines the length of the
|
|||
// encoding:
|
|||
// 110..... - (0xCx, 0xDx) one additional byte (minimum).
|
|||
// 1110.... - (0xEx) two additional bytes.
|
|||
// 11110... - (0xFx) three additional bytes (maximum).
|
|||
ASSERT(IsUtf8MultiCharacterStart(character)); |
|||
// Additional bytes is:
|
|||
// 1 if value in range 0xC0 .. 0xDF.
|
|||
// 2 if value in range 0xE0 .. 0xEF.
|
|||
// 3 if value in range 0xF0 .. 0xF7.
|
|||
// Encode that in a single value.
|
|||
unsigned additional_bytes = |
|||
((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03; |
|||
*cursor += additional_bytes; |
|||
ASSERT(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes])); |
|||
} |
|||
} |
|||
|
|||
|
|||
void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) { |
|||
if (raw_character_position_ > target_position) { |
|||
// Spool backwards in utf8 buffer.
|
|||
do { |
|||
Utf8CharacterBack(raw_data_, &raw_data_pos_); |
|||
raw_character_position_--; |
|||
} while (raw_character_position_ > target_position); |
|||
return; |
|||
} |
|||
// Spool forwards in the utf8 buffer.
|
|||
while (raw_character_position_ < target_position) { |
|||
if (raw_data_pos_ == raw_data_length_) return; |
|||
Utf8CharacterForward(raw_data_, &raw_data_pos_); |
|||
raw_character_position_++; |
|||
} |
|||
} |
|||
|
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// ExternalTwoByteStringUC16CharacterStream
|
|||
|
|||
ExternalTwoByteStringUC16CharacterStream:: |
|||
~ExternalTwoByteStringUC16CharacterStream() { } |
|||
|
|||
|
|||
ExternalTwoByteStringUC16CharacterStream |
|||
::ExternalTwoByteStringUC16CharacterStream( |
|||
Handle<ExternalTwoByteString> data, |
|||
int start_position, |
|||
int end_position) |
|||
: UC16CharacterStream(), |
|||
source_(data), |
|||
raw_data_(data->GetTwoByteData(start_position)) { |
|||
buffer_cursor_ = raw_data_, |
|||
buffer_end_ = raw_data_ + (end_position - start_position); |
|||
pos_ = start_position; |
|||
} |
|||
|
|||
|
|||
// ----------------------------------------------------------------------------
|
|||
// Scanner::LiteralScope
|
|||
|
|||
Scanner::LiteralScope::LiteralScope(Scanner* self) |
|||
: scanner_(self), complete_(false) { |
|||
self->StartLiteral(); |
|||
} |
|||
|
|||
|
|||
Scanner::LiteralScope::~LiteralScope() { |
|||
if (!complete_) scanner_->DropLiteral(); |
|||
} |
|||
|
|||
|
|||
void Scanner::LiteralScope::Complete() { |
|||
scanner_->TerminateLiteral(); |
|||
complete_ = true; |
|||
} |
|||
|
|||
} } // namespace v8::internal
|
@ -0,0 +1,129 @@ |
|||
// 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.
|
|||
|
|||
#ifndef V8_SCANNER_CHARACTER_STREAMS_H_ |
|||
#define V8_SCANNER_CHARACTER_STREAMS_H_ |
|||
|
|||
#include "scanner.h" |
|||
|
|||
namespace v8 { |
|||
namespace internal { |
|||
|
|||
// A buffered character stream based on a random access character
|
|||
// source (ReadBlock can be called with pos_ pointing to any position,
|
|||
// even positions before the current).
|
|||
class BufferedUC16CharacterStream: public UC16CharacterStream { |
|||
public: |
|||
BufferedUC16CharacterStream(); |
|||
virtual ~BufferedUC16CharacterStream(); |
|||
|
|||
virtual void PushBack(uc32 character); |
|||
|
|||
protected: |
|||
static const unsigned kBufferSize = 512; |
|||
static const unsigned kPushBackStepSize = 16; |
|||
|
|||
virtual unsigned SlowSeekForward(unsigned delta); |
|||
virtual bool ReadBlock(); |
|||
virtual void SlowPushBack(uc16 character); |
|||
|
|||
virtual unsigned BufferSeekForward(unsigned delta) = 0; |
|||
virtual unsigned FillBuffer(unsigned position, unsigned length) = 0; |
|||
|
|||
const uc16* pushback_limit_; |
|||
uc16 buffer_[kBufferSize]; |
|||
}; |
|||
|
|||
|
|||
// Generic string stream.
|
|||
class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream { |
|||
public: |
|||
GenericStringUC16CharacterStream(Handle<String> data, |
|||
unsigned start_position, |
|||
unsigned end_position); |
|||
virtual ~GenericStringUC16CharacterStream(); |
|||
|
|||
protected: |
|||
virtual unsigned BufferSeekForward(unsigned delta); |
|||
virtual unsigned FillBuffer(unsigned position, unsigned length); |
|||
|
|||
Handle<String> string_; |
|||
unsigned start_position_; |
|||
unsigned length_; |
|||
}; |
|||
|
|||
|
|||
// UC16 stream based on a literal UTF-8 string.
|
|||
class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream { |
|||
public: |
|||
Utf8ToUC16CharacterStream(const byte* data, unsigned length); |
|||
virtual ~Utf8ToUC16CharacterStream(); |
|||
|
|||
protected: |
|||
virtual unsigned BufferSeekForward(unsigned delta); |
|||
virtual unsigned FillBuffer(unsigned char_position, unsigned length); |
|||
void SetRawPosition(unsigned char_position); |
|||
|
|||
const byte* raw_data_; |
|||
unsigned raw_data_length_; // Measured in bytes, not characters.
|
|||
unsigned raw_data_pos_; |
|||
// The character position of the character at raw_data[raw_data_pos_].
|
|||
// Not necessarily the same as pos_.
|
|||
unsigned raw_character_position_; |
|||
}; |
|||
|
|||
|
|||
// UTF16 buffer to read characters from an external string.
|
|||
class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream { |
|||
public: |
|||
ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data, |
|||
int start_position, |
|||
int end_position); |
|||
virtual ~ExternalTwoByteStringUC16CharacterStream(); |
|||
|
|||
virtual void PushBack(uc32 character) { |
|||
ASSERT(buffer_cursor_ > raw_data_); |
|||
buffer_cursor_--; |
|||
pos_--; |
|||
} |
|||
|
|||
protected: |
|||
virtual unsigned SlowSeekForward(unsigned delta) { |
|||
// Fast case always handles seeking.
|
|||
return 0; |
|||
} |
|||
virtual bool ReadBlock() { |
|||
// Entire string is read at start.
|
|||
return false; |
|||
} |
|||
Handle<ExternalTwoByteString> source_; |
|||
const uc16* raw_data_; // Pointer to the actual array of characters.
|
|||
}; |
|||
|
|||
} } // namespace v8::internal
|
|||
|
|||
#endif // V8_SCANNER_CHARACTER_STREAMS_H_
|
File diff suppressed because it is too large
@ -0,0 +1,106 @@ |
|||
// 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.
|
|||
|
|||
// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
|
|||
// refer to The Open Group Base Specification for specification of the correct
|
|||
// semantics for these functions.
|
|||
// (http://www.opengroup.org/onlinepubs/000095399/)
|
|||
#ifdef _MSC_VER |
|||
|
|||
#undef V8_WIN32_LEAN_AND_MEAN |
|||
#define V8_WIN32_HEADERS_FULL |
|||
#include "win32-headers.h" |
|||
#include <limits.h> // Required for INT_MAX etc. |
|||
#include <math.h> |
|||
#include <float.h> // Required for DBL_MAX and on Win32 for finite() |
|||
#include "win32-math.h" |
|||
|
|||
#include "checks.h" |
|||
|
|||
namespace v8 { |
|||
|
|||
// Test for finite value - usually defined in math.h
|
|||
int isfinite(double x) { |
|||
return _finite(x); |
|||
} |
|||
|
|||
} // namespace v8
|
|||
|
|||
|
|||
// Test for a NaN (not a number) value - usually defined in math.h
|
|||
int isnan(double x) { |
|||
return _isnan(x); |
|||
} |
|||
|
|||
|
|||
// Test for infinity - usually defined in math.h
|
|||
int isinf(double x) { |
|||
return (_fpclass(x) & (_FPCLASS_PINF | _FPCLASS_NINF)) != 0; |
|||
} |
|||
|
|||
|
|||
// Test if x is less than y and both nominal - usually defined in math.h
|
|||
int isless(double x, double y) { |
|||
return isnan(x) || isnan(y) ? 0 : x < y; |
|||
} |
|||
|
|||
|
|||
// Test if x is greater than y and both nominal - usually defined in math.h
|
|||
int isgreater(double x, double y) { |
|||
return isnan(x) || isnan(y) ? 0 : x > y; |
|||
} |
|||
|
|||
|
|||
// Classify floating point number - usually defined in math.h
|
|||
int fpclassify(double x) { |
|||
// Use the MS-specific _fpclass() for classification.
|
|||
int flags = _fpclass(x); |
|||
|
|||
// Determine class. We cannot use a switch statement because
|
|||
// the _FPCLASS_ constants are defined as flags.
|
|||
if (flags & (_FPCLASS_PN | _FPCLASS_NN)) return FP_NORMAL; |
|||
if (flags & (_FPCLASS_PZ | _FPCLASS_NZ)) return FP_ZERO; |
|||
if (flags & (_FPCLASS_PD | _FPCLASS_ND)) return FP_SUBNORMAL; |
|||
if (flags & (_FPCLASS_PINF | _FPCLASS_NINF)) return FP_INFINITE; |
|||
|
|||
// All cases should be covered by the code above.
|
|||
ASSERT(flags & (_FPCLASS_SNAN | _FPCLASS_QNAN)); |
|||
return FP_NAN; |
|||
} |
|||
|
|||
|
|||
// Test sign - usually defined in math.h
|
|||
int signbit(double x) { |
|||
// We need to take care of the special case of both positive
|
|||
// and negative versions of zero.
|
|||
if (x == 0) |
|||
return _fpclass(x) & _FPCLASS_NZ; |
|||
else |
|||
return x < 0; |
|||
} |
|||
|
|||
#endif // _MSC_VER
|
@ -0,0 +1,61 @@ |
|||
// 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.
|
|||
|
|||
// Extra POSIX/ANSI routines for Win32 when using Visual Studio C++. Please
|
|||
// refer to The Open Group Base Specification for specification of the correct
|
|||
// semantics for these functions.
|
|||
// (http://www.opengroup.org/onlinepubs/000095399/)
|
|||
|
|||
#ifndef V8_WIN32_MATH_H_ |
|||
#define V8_WIN32_MATH_H_ |
|||
|
|||
#ifndef _MSC_VER |
|||
#error Wrong environment, expected MSVC. |
|||
#endif // _MSC_VER
|
|||
|
|||
enum { |
|||
FP_NAN, |
|||
FP_INFINITE, |
|||
FP_ZERO, |
|||
FP_SUBNORMAL, |
|||
FP_NORMAL |
|||
}; |
|||
|
|||
namespace v8 { |
|||
|
|||
int isfinite(double x); |
|||
|
|||
} // namespace v8
|
|||
|
|||
int isnan(double x); |
|||
int isinf(double x); |
|||
int isless(double x, double y); |
|||
int isgreater(double x, double y); |
|||
int fpclassify(double x); |
|||
int signbit(double x); |
|||
|
|||
#endif // V8_WIN32_MATH_H_
|
@ -0,0 +1,90 @@ |
|||
# 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. |
|||
|
|||
# Templatated tests with duplicate parameter names. |
|||
|
|||
# ---------------------------------------------------------------------- |
|||
# Constants and utility functions |
|||
|
|||
# A template that performs the same strict-mode test in different |
|||
# scopes (global scope, function scope, and nested function scope), |
|||
# and in non-strict mode too. |
|||
def DuplicateParameterTest(name, source): |
|||
expectation = "strict_param_dupe" |
|||
non_selfstrict = {"selfstrict":"", "id":"selfnormal"} |
|||
|
|||
Template(name, '"use strict";\n' + source)(non_selfstrict, expectation) |
|||
Template(name + '-infunc', |
|||
'function foo() {\n "use strict";\n' + source +'\n}\n')( |
|||
non_selfstrict, expectation) |
|||
Template(name + '-infunc2', |
|||
'function foo() {\n "use strict";\n function bar() {\n' + |
|||
source +'\n }\n}\n')(non_selfstrict, expectation) |
|||
|
|||
selfstrict = {"selfstrict": "\"use strict\";", "id": "selfstrict"} |
|||
nestedstrict = {"selfstrict": "function bar(){\"use strict\";}", |
|||
"id": "nestedstrict"} |
|||
selfstrictnestedclean = {"selfstrict": """ |
|||
"use strict"; |
|||
function bar(){} |
|||
""", "id": "selfstrictnestedclean"} |
|||
selftest = Template(name + '-$id', source) |
|||
selftest(selfstrict, expectation) |
|||
selftest(selfstrictnestedclean, expectation) |
|||
selftest(nestedstrict, None) |
|||
selftest(non_selfstrict, None) |
|||
|
|||
|
|||
# ---------------------------------------------------------------------- |
|||
# Test templates |
|||
|
|||
DuplicateParameterTest("dups", """ |
|||
function foo(a, a) { $selfstrict } |
|||
"""); |
|||
|
|||
DuplicateParameterTest("dups-apart", """ |
|||
function foo(a, b, c, d, e, f, g, h, i, j, k, l, m, n, a) { $selfstrict } |
|||
"""); |
|||
|
|||
DuplicateParameterTest("dups-escaped", """ |
|||
function foo(\u0061, b, c, d, e, f, g, h, i, j, k, l, m, n, a) { $selfstrict } |
|||
"""); |
|||
|
|||
DuplicateParameterTest("triples", """ |
|||
function foo(a, b, c, d, e, f, g, h, a, i, j, k, l, m, n, a) { $selfstrict } |
|||
"""); |
|||
|
|||
DuplicateParameterTest("escapes", """ |
|||
function foo(a, \u0061) { $selfstrict } |
|||
"""); |
|||
|
|||
DuplicateParameterTest("long-names", """ |
|||
function foo(arglebargleglopglyfarglebargleglopglyfarglebargleglopglyfa, |
|||
arglebargleglopglyfarglebargleglopglyfarglebargleglopglyfa) { |
|||
$selfstrict |
|||
} |
|||
"""); |
@ -0,0 +1,162 @@ |
|||
# 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. |
|||
|
|||
# Tests of duplicate properties in object literals. |
|||
|
|||
# ---------------------------------------------------------------------- |
|||
# Utility functions to generate a number of tests for each property |
|||
# name pair. |
|||
|
|||
def PropertyTest(name, propa, propb, allow_strict = True): |
|||
replacement = {"id1": propa, "id2": propb, "name": name} |
|||
|
|||
# Tests same test in both strict and non-strict context. |
|||
def StrictTest(name, source, replacement, expectation): |
|||
if (allow_strict): |
|||
Template("strict-" + name, |
|||
"\"use strict\";\n" + source)(replacement, expectation) |
|||
Template(name, source)(replacement, expectation) |
|||
|
|||
# This one only fails in non-strict context. |
|||
if (allow_strict): |
|||
Template("strict-$name-data-data", """ |
|||
"use strict"; |
|||
var o = {$id1: 42, $id2: 42}; |
|||
""")(replacement, "strict_duplicate_property") |
|||
|
|||
Template("$name-data-data", """ |
|||
var o = {$id1: 42, $id2: 42}; |
|||
""")(replacement, None) |
|||
|
|||
StrictTest("$name-data-get", """ |
|||
var o = {$id1: 42, get $id2(){}}; |
|||
""", replacement, "accessor_data_property") |
|||
|
|||
StrictTest("$name-data-set", """ |
|||
var o = {$id1: 42, set $id2(v){}}; |
|||
""", replacement, "accessor_data_property") |
|||
|
|||
StrictTest("$name-get-data", """ |
|||
var o = {get $id1(){}, $id2: 42}; |
|||
""", replacement, "accessor_data_property") |
|||
|
|||
StrictTest("$name-set-data", """ |
|||
var o = {set $id1(v){}, $id2: 42}; |
|||
""", replacement, "accessor_data_property") |
|||
|
|||
StrictTest("$name-get-get", """ |
|||
var o = {get $id1(){}, get $id2(){}}; |
|||
""", replacement, "accessor_get_set") |
|||
|
|||
StrictTest("$name-set-set", """ |
|||
var o = {set $id1(v){}, set $id2(v){}}; |
|||
""", replacement, "accessor_get_set") |
|||
|
|||
StrictTest("$name-nested-get", """ |
|||
var o = {get $id1(){}, o: {get $id2(){} } }; |
|||
""", replacement, None) |
|||
|
|||
StrictTest("$name-nested-set", """ |
|||
var o = {set $id1(){}, o: {set $id2(){} } }; |
|||
""", replacement, None) |
|||
|
|||
|
|||
def TestBothWays(name, propa, propb, allow_strict = True): |
|||
PropertyTest(name + "-1", propa, propb, allow_strict) |
|||
PropertyTest(name + "-2", propb, propa, allow_strict) |
|||
|
|||
def TestSame(name, prop, allow_strict = True): |
|||
PropertyTest(name, prop, prop, allow_strict) |
|||
|
|||
#----------------------------------------------------------------------- |
|||
|
|||
# Simple identifier property |
|||
TestSame("a", "a") |
|||
|
|||
# Get/set identifiers |
|||
TestSame("get-id", "get") |
|||
TestSame("set-id", "set") |
|||
|
|||
# Number properties |
|||
TestSame("0", "0") |
|||
TestSame("0.1", "0.1") |
|||
TestSame("1.0", "1.0") |
|||
TestSame("42.33", "42.33") |
|||
TestSame("2^32-2", "4294967294") |
|||
TestSame("2^32", "4294967296") |
|||
TestSame("2^53", "9007199254740992") |
|||
TestSame("Hex20", "0x20") |
|||
TestSame("exp10", "1e10") |
|||
TestSame("exp20", "1e20") |
|||
TestSame("Oct40", "040", False); |
|||
|
|||
|
|||
# String properties |
|||
TestSame("str-a", '"a"') |
|||
TestSame("str-0", '"0"') |
|||
TestSame("str-42", '"42"') |
|||
TestSame("str-empty", '""') |
|||
|
|||
# Keywords |
|||
TestSame("if", "if") |
|||
TestSame("case", "case") |
|||
|
|||
# Future reserved keywords |
|||
TestSame("public", "public") |
|||
TestSame("class", "class") |
|||
|
|||
|
|||
# Test that numbers are converted to string correctly. |
|||
|
|||
TestBothWays("hex-int", "0x20", "32") |
|||
TestBothWays("oct-int", "040", "32", False) # Octals disallowed in strict mode. |
|||
TestBothWays("dec-int", "32.00", "32") |
|||
TestBothWays("dec-underflow-int", |
|||
"32.00000000000000000000000000000000000000001", "32") |
|||
TestBothWays("exp-int", "3.2e1", "32") |
|||
TestBothWays("exp-int", "3200e-2", "32") |
|||
TestBothWays("overflow-inf", "1e2000", "Infinity") |
|||
TestBothWays("overflow-inf-exact", "1.797693134862315808e+308", "Infinity") |
|||
TestBothWays("non-overflow-inf-exact", "1.797693134862315807e+308", |
|||
"1.7976931348623157e+308") |
|||
TestBothWays("underflow-0", "1e-2000", "0") |
|||
TestBothWays("underflow-0-exact", "2.4703282292062E-324", "0") |
|||
TestBothWays("non-underflow-0-exact", "2.4703282292063E-324", "5e-324") |
|||
TestBothWays("precission-loss-high", "9007199254740992", "9007199254740993") |
|||
TestBothWays("precission-loss-low", "1.9999999999999998", "1.9999999999999997") |
|||
TestBothWays("non-canonical-literal-int", "1.0", "1") |
|||
TestBothWays("non-canonical-literal-frac", "1.50", "1.5") |
|||
TestBothWays("rounding-down", "1.12512512512512452", "1.1251251251251244") |
|||
TestBothWays("rounding-up", "1.12512512512512453", "1.1251251251251246") |
|||
|
|||
TestBothWays("hex-int-str", "0x20", '"32"') |
|||
TestBothWays("dec-int-str", "32.00", '"32"') |
|||
TestBothWays("exp-int-str", "3.2e1", '"32"') |
|||
TestBothWays("overflow-inf-str", "1e2000", '"Infinity"') |
|||
TestBothWays("underflow-0-str", "1e-2000", '"0"') |
|||
TestBothWays("non-canonical-literal-int-str", "1.0", '"1"') |
|||
TestBothWays("non-canonical-literal-frac-str", "1.50", '"1.5"') |
@ -0,0 +1,424 @@ |
|||
#!/bin/bash |
|||
# 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. |
|||
|
|||
|
|||
########## Global variable definitions |
|||
|
|||
BRANCHNAME=prepare-push |
|||
TRUNKBRANCH=trunk-push |
|||
TEMP_BRANCH=v8-push-to-trunk-script-temporary-branch |
|||
VERSION_FILE="src/version.cc" |
|||
PERSISTFILE_BASENAME=/tmp/v8-push-to-trunk-tempfile |
|||
CHANGELOG_ENTRY_FILE="$PERSISTFILE_BASENAME-changelog-entry" |
|||
PATCH_FILE="$PERSISTFILE_BASENAME-patch" |
|||
COMMITMSG_FILE="$PERSISTFILE_BASENAME-commitmsg" |
|||
TOUCHED_FILES_FILE="$PERSISTFILE_BASENAME-touched-files" |
|||
STEP=0 |
|||
|
|||
|
|||
########## Function definitions |
|||
|
|||
usage() { |
|||
cat << EOF |
|||
usage: $0 OPTIONS |
|||
|
|||
Performs the necessary steps for a V8 push to trunk. Only works for \ |
|||
git checkouts. |
|||
|
|||
OPTIONS: |
|||
-h Show this message |
|||
-s Specify the step where to start work. Default: 0. |
|||
-l Manually specify the git commit ID of the last push to trunk. |
|||
EOF |
|||
} |
|||
|
|||
die() { |
|||
[[ -n "$1" ]] && echo "Error: $1" |
|||
echo "Exiting." |
|||
exit 1 |
|||
} |
|||
|
|||
confirm() { |
|||
echo -n "$1 [Y/n] " |
|||
read ANSWER |
|||
if [[ -z "$ANSWER" || "$ANSWER" == "Y" || "$ANSWER" == "y" ]] ; then |
|||
return 0 |
|||
else |
|||
return 1 |
|||
fi |
|||
} |
|||
|
|||
delete_branch() { |
|||
local MATCH=$(git branch | grep $1) |
|||
if [ "$MATCH" == "$1" ] ; then |
|||
confirm "Branch $1 exists, do you want to delete it?" |
|||
if [ $? -eq 0 ] ; then |
|||
git branch -D $1 |
|||
echo "Branch $1 deleted." |
|||
else |
|||
die "Can't continue. Please delete branch $1 and try again." |
|||
fi |
|||
fi |
|||
} |
|||
|
|||
# Persist and restore variables to support canceling/resuming execution |
|||
# of this script. |
|||
persist() { |
|||
local VARNAME=$1 |
|||
local FILE="$PERSISTFILE_BASENAME-$VARNAME" |
|||
echo "${!VARNAME}" > $FILE |
|||
} |
|||
|
|||
restore() { |
|||
local VARNAME=$1 |
|||
local FILE="$PERSISTFILE_BASENAME-$VARNAME" |
|||
local VALUE="$(cat $FILE)" |
|||
eval "$VARNAME=\"$VALUE\"" |
|||
} |
|||
|
|||
restore_if_unset() { |
|||
local VARNAME=$1 |
|||
[[ -z "${!VARNAME}" ]] && restore "$VARNAME" |
|||
[[ -z "${!VARNAME}" ]] && die "Variable '$VARNAME' could not be restored." |
|||
} |
|||
|
|||
|
|||
########## Option parsing |
|||
|
|||
while getopts ":hs:l:" OPTION ; do |
|||
case $OPTION in |
|||
h) usage |
|||
exit 0 |
|||
;; |
|||
s) STEP=$OPTARG |
|||
;; |
|||
l) LASTPUSH=$OPTARG |
|||
;; |
|||
?) echo "Illegal option: -$OPTARG" |
|||
usage |
|||
exit 1 |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
|
|||
########## Regular workflow |
|||
|
|||
# Cancel if this is not a git checkout. |
|||
[[ -d .git ]] \ |
|||
|| die "This is not a git checkout, this script won't work for you." |
|||
|
|||
# Cancel if EDITOR is unset or not executable. |
|||
[[ -n "$EDITOR" && -x "$(which $EDITOR)" ]] \ |
|||
|| die "Please set your EDITOR environment variable, you'll need it." |
|||
|
|||
if [ $STEP -le 0 ] ; then |
|||
echo ">>> Step 0: Preparation" |
|||
# Check for a clean workdir. |
|||
[[ -z "$(git status -s -uno)" ]] \ |
|||
|| die "Workspace is not clean. Please commit or undo your changes." |
|||
|
|||
# Persist current branch. |
|||
CURRENT_BRANCH=$(git status -s -b -uno | grep "^##" | awk '{print $2}') |
|||
persist "CURRENT_BRANCH" |
|||
# Get ahold of a safe temporary branch and check it out. |
|||
if [ "$CURRENT_BRANCH" != "$TEMP_BRANCH" ] ; then |
|||
delete_branch $TEMP_BRANCH |
|||
git checkout -b $TEMP_BRANCH |
|||
fi |
|||
# Delete branches if they exist. |
|||
delete_branch $BRANCHNAME |
|||
delete_branch $TRUNKBRANCH |
|||
fi |
|||
|
|||
if [ $STEP -le 1 ] ; then |
|||
echo ">>> Step 1: Fetch unfetched revisions." |
|||
git svn fetch || die "'git svn fetch' failed." |
|||
fi |
|||
|
|||
if [ $STEP -le 2 ] ; then |
|||
echo ">>> Step 2: Create a fresh branch." |
|||
git checkout -b $BRANCHNAME svn/bleeding_edge \ |
|||
|| die "Creating branch $BRANCHNAME failed." |
|||
fi |
|||
|
|||
if [ $STEP -le 3 ] ; then |
|||
echo ">>> Step 3: Detect commit ID of last push to trunk." |
|||
[[ -n "$LASTPUSH" ]] || LASTPUSH=$(git log -1 --format=%H ChangeLog) |
|||
LOOP=1 |
|||
while [ $LOOP -eq 1 ] ; do |
|||
# Print assumed commit, circumventing git's pager. |
|||
git log -1 $LASTPUSH | cat |
|||
confirm "Is the commit printed above the last push to trunk?" |
|||
if [ $? -eq 0 ] ; then |
|||
LOOP=0 |
|||
else |
|||
LASTPUSH=$(git log -1 --format=%H $LASTPUSH^ ChangeLog) |
|||
fi |
|||
done |
|||
persist "LASTPUSH" |
|||
fi |
|||
|
|||
if [ $STEP -le 4 ] ; then |
|||
echo ">>> Step 4: Prepare raw ChangeLog entry." |
|||
# These version numbers are used again later for the trunk commit. |
|||
MAJOR=$(grep "#define MAJOR_VERSION" "$VERSION_FILE" | awk '{print $NF}') |
|||
persist "MAJOR" |
|||
MINOR=$(grep "#define MINOR_VERSION" "$VERSION_FILE" | awk '{print $NF}') |
|||
persist "MINOR" |
|||
BUILD=$(grep "#define BUILD_NUMBER" "$VERSION_FILE" | awk '{print $NF}') |
|||
persist "BUILD" |
|||
|
|||
DATE=$(date +%Y-%m-%d) |
|||
persist "DATE" |
|||
echo "$DATE: Version $MAJOR.$MINOR.$BUILD" > "$CHANGELOG_ENTRY_FILE" |
|||
echo "" >> "$CHANGELOG_ENTRY_FILE" |
|||
COMMITS=$(git log $LASTPUSH..HEAD --format=%H) |
|||
for commit in $COMMITS ; do |
|||
# Get the commit's title line. |
|||
git log -1 $commit --format="%w(80,8,8)%s" >> "$CHANGELOG_ENTRY_FILE" |
|||
# Grep for "BUG=xxxx" lines in the commit message. |
|||
git log -1 $commit --format="%b" | grep BUG= | grep -v "BUG=$" \ |
|||
| sed -e 's/^/ /' \ |
|||
>> "$CHANGELOG_ENTRY_FILE" |
|||
# Append the commit's author for reference. |
|||
git log -1 $commit --format="%w(80,8,8)(%an)" >> "$CHANGELOG_ENTRY_FILE" |
|||
echo "" >> "$CHANGELOG_ENTRY_FILE" |
|||
done |
|||
fi |
|||
|
|||
if [ $STEP -le 5 ] ; then |
|||
echo ">>> Step 5: Edit ChangeLog entry." |
|||
echo -n "Please press <Return> to have your EDITOR open the ChangeLog entry, \ |
|||
then edit its contents to your liking. When you're done, save the file and \ |
|||
exit your EDITOR. " |
|||
read ANSWER |
|||
$EDITOR "$CHANGELOG_ENTRY_FILE" |
|||
NEWCHANGELOG=$(mktemp) |
|||
# Eliminate any trailing newlines by going through a shell variable. |
|||
CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE") |
|||
[[ -n "$CHANGELOGENTRY" ]] || die "Empty ChangeLog entry." |
|||
echo "$CHANGELOGENTRY" > "$NEWCHANGELOG" |
|||
echo "" >> "$NEWCHANGELOG" # Explicitly insert two empty lines. |
|||
echo "" >> "$NEWCHANGELOG" |
|||
cat ChangeLog >> "$NEWCHANGELOG" |
|||
mv "$NEWCHANGELOG" ChangeLog |
|||
fi |
|||
|
|||
if [ $STEP -le 6 ] ; then |
|||
echo ">>> Step 6: Increment version number." |
|||
restore_if_unset "BUILD" |
|||
NEWBUILD=$(($BUILD + 1)) |
|||
confirm "Automatically increment BUILD_NUMBER? (Saying 'n' will fire up \ |
|||
your EDITOR on $VERSION_FILE so you can make arbitrary changes. When \ |
|||
you're done, save the file and exit your EDITOR.)" |
|||
if [ $? -eq 0 ] ; then |
|||
sed -e "/#define BUILD_NUMBER/s/[0-9]*$/$NEWBUILD/" \ |
|||
-i "$VERSION_FILE" |
|||
else |
|||
$EDITOR "$VERSION_FILE" |
|||
fi |
|||
NEWMAJOR=$(grep "#define MAJOR_VERSION" "$VERSION_FILE" | awk '{print $NF}') |
|||
persist "NEWMAJOR" |
|||
NEWMINOR=$(grep "#define MINOR_VERSION" "$VERSION_FILE" | awk '{print $NF}') |
|||
persist "NEWMINOR" |
|||
NEWBUILD=$(grep "#define BUILD_NUMBER" "$VERSION_FILE" | awk '{print $NF}') |
|||
persist "NEWBUILD" |
|||
fi |
|||
|
|||
if [ $STEP -le 7 ] ; then |
|||
echo ">>> Step 7: Commit to local branch." |
|||
restore_if_unset "NEWMAJOR" |
|||
restore_if_unset "NEWMINOR" |
|||
restore_if_unset "NEWBUILD" |
|||
git commit -a -m "Prepare push to trunk. \ |
|||
Now working on version $NEWMAJOR.$NEWMINOR.$NEWBUILD." \ |
|||
|| die "'git commit -a' failed." |
|||
fi |
|||
|
|||
if [ $STEP -le 8 ] ; then |
|||
echo ">>> Step 8: Upload for code review." |
|||
echo -n "Please enter the email address of a V8 reviewer for your patch: " |
|||
read REVIEWER |
|||
git cl upload -r $REVIEWER --send-mail \ |
|||
|| die "'git cl upload' failed, please try again." |
|||
fi |
|||
|
|||
if [ $STEP -le 9 ] ; then |
|||
echo ">>> Step 9: Commit to the repository." |
|||
echo "Please wait for an LGTM, then type \"LGTM<Return>\" to commit your \ |
|||
change. (If you need to iterate on the patch, do so in another shell.)" |
|||
unset ANSWER |
|||
while [ "$ANSWER" != "LGTM" ] ; do |
|||
[[ -n "$ANSWER" ]] && echo "That was not 'LGTM'." |
|||
echo -n "> " |
|||
read ANSWER |
|||
done |
|||
# Re-read the ChangeLog entry (to pick up possible changes). |
|||
cat ChangeLog | awk --posix '{ |
|||
if ($0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}:/) { |
|||
if (in_firstblock == 1) { |
|||
exit 0; |
|||
} else { |
|||
in_firstblock = 1; |
|||
} |
|||
}; |
|||
print $0; |
|||
}' > "$CHANGELOG_ENTRY_FILE" |
|||
git cl dcommit || die "'git cl dcommit' failed, please try again." |
|||
fi |
|||
|
|||
if [ $STEP -le 10 ] ; then |
|||
echo ">>> Step 10: NOP" |
|||
# Present in the manual guide, not necessary (even harmful!) for this script. |
|||
fi |
|||
|
|||
if [ $STEP -le 11 ] ; then |
|||
echo ">>> Step 11: Squash commits into one." |
|||
# Instead of relying on "git rebase -i", we'll just create a diff, because |
|||
# that's easier to automate. |
|||
git diff svn/trunk > "$PATCH_FILE" |
|||
# Convert the ChangeLog entry to commit message format: |
|||
# - remove date |
|||
# - remove indentation |
|||
# - merge paragraphs into single long lines, keeping empty lines between them. |
|||
restore_if_unset "DATE" |
|||
CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE") |
|||
echo "$CHANGELOGENTRY" \ |
|||
| sed -e "s/^$DATE: //" \ |
|||
| sed -e 's/^ *//' \ |
|||
| awk '{ |
|||
if (need_space == 1) { |
|||
printf(" "); |
|||
}; |
|||
printf("%s", $0); |
|||
if ($0 ~ /^$/) { |
|||
printf("\n\n"); |
|||
need_space = 0; |
|||
} else { |
|||
need_space = 1; |
|||
} |
|||
}' > "$COMMITMSG_FILE" || die "Commit message editing failed." |
|||
LOOP=1 |
|||
while [ $LOOP -eq 1 ] ; do |
|||
echo "This is the trunk commit message:" |
|||
echo "--------------------" |
|||
cat "$COMMITMSG_FILE" |
|||
echo -e "\n--------------------" |
|||
confirm "Does this look good to you? (Saying 'n' will fire up your \ |
|||
EDITOR so you can change the commit message. When you're done, save the \ |
|||
file and exit your EDITOR.)" |
|||
if [ $? -eq 0 ] ; then |
|||
LOOP=0 |
|||
else |
|||
$EDITOR "$COMMITMSG_FILE" |
|||
fi |
|||
done |
|||
rm -f "$CHANGELOG_ENTRY_FILE" |
|||
fi |
|||
|
|||
if [ $STEP -le 12 ] ; then |
|||
echo ">>> Step 12: Create a new branch from trunk." |
|||
git checkout -b $TRUNKBRANCH svn/trunk \ |
|||
|| die "Checking out a new branch '$TRUNKBRANCH' failed." |
|||
fi |
|||
|
|||
if [ $STEP -le 13 ] ; then |
|||
echo ">>> Step 13: Apply squashed changes." |
|||
patch -p1 < "$PATCH_FILE" | tee >(awk '{print $NF}' >> "$TOUCHED_FILES_FILE") |
|||
[[ $? -eq 0 ]] || die "Applying the patch to trunk failed." |
|||
TOUCHED_FILES=$(cat "$TOUCHED_FILES_FILE") |
|||
for FILE in $TOUCHED_FILES ; do |
|||
git add "$FILE" |
|||
done |
|||
rm -f "$PATCH_FILE" |
|||
rm -f "$TOUCHED_FILES_FILE" |
|||
fi |
|||
|
|||
if [ $STEP -le 14 ] ; then |
|||
echo ">>> Step 14: Set correct version for trunk." |
|||
restore_if_unset "MAJOR" |
|||
restore_if_unset "MINOR" |
|||
restore_if_unset "BUILD" |
|||
sed -e "/#define MAJOR_VERSION/s/[0-9]*$/$MAJOR/" \ |
|||
-e "/#define MINOR_VERSION/s/[0-9]*$/$MINOR/" \ |
|||
-e "/#define BUILD_NUMBER/s/[0-9]*$/$BUILD/" \ |
|||
-e "/#define PATCH_LEVEL/s/[0-9]*$/0/" \ |
|||
-e "/#define IS_CANDIDATE_VERSION/s/[0-9]*$/0/" \ |
|||
-i "$VERSION_FILE" || die "Patching $VERSION_FILE failed." |
|||
fi |
|||
|
|||
if [ $STEP -le 15 ] ; then |
|||
echo ">>> Step 15: Commit to local trunk branch." |
|||
git add "$VERSION_FILE" |
|||
git commit -F "$COMMITMSG_FILE" || die "'git commit' failed." |
|||
rm -f "$COMMITMSG_FILE" |
|||
fi |
|||
|
|||
if [ $STEP -le 16 ] ; then |
|||
echo ">>> Step 16: Sanity check." |
|||
confirm "Please check if your local checkout is sane: Inspect $VERSION_FILE, \ |
|||
compile, run tests. Do you want to commit this new trunk revision to the \ |
|||
repository?" |
|||
[[ $? -eq 0 ]] || die "Execution canceled." |
|||
fi |
|||
|
|||
if [ $STEP -le 17 ] ; then |
|||
echo ">>> Step 17. Commit to SVN." |
|||
git svn dcommit || die "'git svn dcommit' failed." |
|||
fi |
|||
|
|||
if [ $STEP -le 18 ] ; then |
|||
echo ">>> Step 18: Tag the new revision." |
|||
restore_if_unset "MAJOR" |
|||
restore_if_unset "MINOR" |
|||
restore_if_unset "BUILD" |
|||
git svn tag $MAJOR.$MINOR.$BUILD -m "Tagging version $MAJOR.$MINOR.$BUILD" \ |
|||
|| die "'git svn tag' failed." |
|||
fi |
|||
|
|||
if [ $STEP -le 19 ] ; then |
|||
echo ">>> Step 19: Cleanup." |
|||
restore_if_unset "CURRENT_BRANCH" |
|||
git checkout -f $CURRENT_BRANCH |
|||
[[ "$TEMP_BRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TEMP_BRANCH |
|||
[[ "$BRANCHNAME" != "$CURRENT_BRANCH" ]] && git branch -D $BRANCHNAME |
|||
[[ "$TRUNKBRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TRUNKBRANCH |
|||
fi |
|||
|
|||
if [ $STEP -le 20 ] ; then |
|||
echo ">>> Step 20: Done!" |
|||
restore_if_unset "MAJOR" |
|||
restore_if_unset "MINOR" |
|||
restore_if_unset "BUILD" |
|||
echo "Congratulations, you have successfully created the trunk revision \ |
|||
$MAJOR.$MINOR.$BUILD. Please don't forget to update the v8rel spreadsheet, \ |
|||
and to roll this new version into Chromium." |
|||
# Clean up all temporary files. |
|||
rm -f "$PERSISTFILE_BASENAME"* |
|||
fi |
Loading…
Reference in new issue