diff --git a/mozilla/js2/src/formatter.cpp b/mozilla/js2/src/formatter.cpp index 7cbd83521b9..8447216551c 100644 --- a/mozilla/js2/src/formatter.cpp +++ b/mozilla/js2/src/formatter.cpp @@ -1,470 +1,443 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include "algo.h" #include "formatter.h" -namespace JavaScript -{ - static const char controlCharNames[6] = {'b', 't', 'n', 'v', 'f', 'r'}; - +namespace JS = JavaScript; + + +static const char controlCharNames[6] = {'b', 't', 'n', 'v', 'f', 'r'}; + // Print the characters from begin to end, escaping them as necessary to make // the resulting string be readable if placed between two quotes specified by // quote (which should be either '\'' or '"'). - void - escapeString(Formatter &f, const char16 *begin, const char16 *end, - char16 quote) - { - ASSERT(begin <= end); - - const char16 *chunk = begin; - while (begin != end) { - char16 ch = *begin++; - CharInfo ci(ch); - if (char16Value(ch) < 0x20 || isLineBreak(ci) || isFormat(ci) - || ch == '\\' || ch == quote) { - if (begin-1 != chunk) - printString(f, chunk, begin-1); - chunk = begin; +void JS::escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote) +{ + ASSERT(begin <= end); + + const char16 *chunk = begin; + while (begin != end) { + char16 ch = *begin++; + CharInfo ci(ch); + if (char16Value(ch) < 0x20 || isLineBreak(ci) || isFormat(ci) || ch == '\\' || ch == quote) { + if (begin-1 != chunk) + printString(f, chunk, begin-1); + chunk = begin; + + f << '\\'; + switch (ch) { + case 0x0008: + case 0x0009: + case 0x000A: + case 0x000B: + case 0x000C: + case 0x000D: + f << controlCharNames[ch - 0x0008]; + break; + + case '\'': + case '"': + case '\\': + f << ch; + break; + + case 0x0000: + if (begin == end || char16Value(*begin) < '0' || char16Value(*begin) > '9') { + f << '0'; + break; + } + default: + if (char16Value(ch) <= 0xFF) { + f << 'x'; + printHex(f, static_cast(char16Value(ch)), 2); + } else { + f << 'u'; + printHex(f, static_cast(char16Value(ch)), 4); + } + } + } + } + if (begin != chunk) + printString(f, chunk, begin); +} + - f << '\\'; - switch (ch) { - case 0x0008: - case 0x0009: - case 0x000A: - case 0x000B: - case 0x000C: - case 0x000D: - f << controlCharNames[ch - 0x0008]; - break; - - case '\'': - case '"': - case '\\': - f << ch; - break; - - case 0x0000: - if (begin == end || char16Value(*begin) < '0' || - char16Value(*begin) > '9') { - f << '0'; - break; - } - default: - if (char16Value(ch) <= 0xFF) { - f << 'x'; - printHex(f, - static_cast(char16Value(ch)), - 2); - } else { - f << 'u'; - printHex(f, - static_cast(char16Value(ch)), - 4); - } - } - } - } - if (begin != chunk) - printString(f, chunk, begin); - } - - // Print s as a quoted string using the given quotes (which should be // either '\'' or '"'). - void - quoteString(Formatter &f, const String &s, char16 quote) - { - f << quote; - const char16 *begin = s.data(); - escapeString(f, begin, begin + s.size(), quote); - f << quote; - } +void JS::quoteString(Formatter &f, const String &s, char16 quote) +{ + f << quote; + const char16 *begin = s.data(); + escapeString(f, begin, begin + s.size(), quote); + f << quote; +} + #ifdef XP_MAC_MPW // Macintosh MPW replacements for the ANSI routines. These translate LF's to // CR's because the MPW libraries supplied by Metrowerks don't do that for some // reason. - static void - translateLFtoCR(char *begin, char *end) - { - while (begin != end) { - if (*begin == '\n') - *begin = '\r'; - ++begin; - } - } +static void translateLFtoCR(char *begin, char *end) +{ + while (begin != end) { + if (*begin == '\n') + *begin = '\r'; + ++begin; + } +} - size_t - printChars(FILE *file, const char *begin, const char *end) - { - ASSERT(end >= begin); - size_t n = static_cast(end - begin); - size_t extra = 0; - char buffer[1024]; - while (n > sizeof buffer) { - std::memcpy(buffer, begin, sizeof buffer); - translateLFtoCR(buffer, buffer + sizeof buffer); - extra += fwrite(buffer, 1, sizeof buffer, file); - n -= sizeof buffer; - begin += sizeof buffer; - } - std::memcpy(buffer, begin, n); - translateLFtoCR(buffer, buffer + n); - return extra + fwrite(buffer, 1, n, file); - } +size_t JS::printChars(FILE *file, const char *begin, const char *end) +{ + ASSERT(end >= begin); + size_t n = static_cast(end - begin); + size_t extra = 0; + char buffer[1024]; - int - std::fputc(int c, FILE *file) - { - char buffer = static_cast(c); - if (buffer == '\n') - buffer = '\r'; - return static_cast(fwrite(&buffer, 1, 1, file)); - } + while (n > sizeof buffer) { + std::memcpy(buffer, begin, sizeof buffer); + translateLFtoCR(buffer, buffer + sizeof buffer); + extra += fwrite(buffer, 1, sizeof buffer, file); + n -= sizeof buffer; + begin += sizeof buffer; + } + std::memcpy(buffer, begin, n); + translateLFtoCR(buffer, buffer + n); + return extra + fwrite(buffer, 1, n, file); +} - int - std::fputs(const char *s, FILE *file) - { - return static_cast(printChars(file, s, s + strlen(s))); - } - int - std::fprintf(FILE* file, const char *format, ...) - { - Buffer b; +int std::fputc(int c, FILE *file) +{ + char buffer = static_cast(c); + if (buffer == '\n') + buffer = '\r'; + return static_cast(fwrite(&buffer, 1, 1, file)); +} - while (true) { - va_list args; - va_start(args, format); - int n = vsnprintf(b.buffer, b.size, format, args); - va_end(args); - if (n >= 0 && n < b.size) { - translateLFtoCR(b.buffer, b.buffer + n); - return static_cast(fwrite(b.buffer, 1, - static_cast(n), file)); - } - b.expand(b.size*2); - } - } - + +int std::fputs(const char *s, FILE *file) +{ + return static_cast(printChars(file, s, s + strlen(s))); +} + + +int std::fprintf(FILE* file, const char *format, ...) +{ + Buffer b; + + while (true) { + va_list args; + va_start(args, format); + int n = vsnprintf(b.buffer, b.size, format, args); + va_end(args); + if (n >= 0 && n < b.size) { + translateLFtoCR(b.buffer, b.buffer + n); + return static_cast(fwrite(b.buffer, 1, static_cast(n), file)); + } + b.expand(b.size*2); + } +} #endif // XP_MAC_MPW + // Write ch. - void - Formatter::printChar8(char ch) - { - printStr8(&ch, &ch + 1); - } +void JS::Formatter::printChar8(char ch) +{ + printStr8(&ch, &ch + 1); +} // Write ch. - void - Formatter::printChar16(char16 ch) - { - printStr16(&ch, &ch + 1); - } +void JS::Formatter::printChar16(char16 ch) +{ + printStr16(&ch, &ch + 1); +} // Write the null-terminated string str. - void - Formatter::printZStr8(const char *str) - { - printStr8(str, str + strlen(str)); - } +void JS::Formatter::printZStr8(const char *str) +{ + printStr8(str, str + strlen(str)); +} // Write the String s. - void - Formatter::printString16(const String &s) - { - const char16 *begin = s.data(); - printStr16(begin, begin + s.size()); - } +void JS::Formatter::printString16(const String &s) +{ + const char16 *begin = s.data(); + printStr16(begin, begin + s.size()); +} // Write the printf format using the supplied args. - void - Formatter::printVFormat8(const char *format, va_list args) - { - Buffer b; +void JS::Formatter::printVFormat8(const char *format, va_list args) +{ + Buffer b; - while (true) { - int n = vsnprintf(b.buffer, b.size, format, args); - if (n >= 0 && static_cast(n) < b.size) { - printStr8(b.buffer, b.buffer + n); - return; - } - b.expand(b.size*2); - } - } - + while (true) { + int n = vsnprintf(b.buffer, b.size, format, args); + if (n >= 0 && static_cast(n) < b.size) { + printStr8(b.buffer, b.buffer + n); + return; + } + b.expand(b.size*2); + } +} - static const int printCharBufferSize = 64; + +static const int printCharBufferSize = 64; // Print ch count times. - void - printChar(Formatter &f, char ch, int count) - { - char str[printCharBufferSize]; - - while (count > 0) { - int c = count; - if (c > printCharBufferSize) - c = printCharBufferSize; - count -= c; - STD::memset(str, ch, static_cast(c)); - printString(f, str, str+c); - } - } +void JS::printChar(Formatter &f, char ch, int count) +{ + char str[printCharBufferSize]; + + while (count > 0) { + int c = count; + if (c > printCharBufferSize) + c = printCharBufferSize; + count -= c; + STD::memset(str, ch, static_cast(c)); + printString(f, str, str+c); + } +} // Print ch count times. - void - printChar(Formatter &f, char16 ch, int count) - { - char16 str[printCharBufferSize]; - - while (count > 0) { - int c = count; - if (c > printCharBufferSize) - c = printCharBufferSize; - count -= c; - char16 *strEnd = str + c; - std::fill(str, strEnd, ch); - printString(f, str, strEnd); - } - } +void JS::printChar(Formatter &f, char16 ch, int count) +{ + char16 str[printCharBufferSize]; + + while (count > 0) { + int c = count; + if (c > printCharBufferSize) + c = printCharBufferSize; + count -= c; + char16 *strEnd = str + c; + std::fill(str, strEnd, ch); + printString(f, str, strEnd); + } +} // Print i using the given formatting string, padding on the left with pad // characters to use at least nDigits characters. - void - printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format) - { - char str[20]; - int n = sprintf(str, format, i); - if (n < nDigits) - printChar(f, pad, nDigits - n); - printString(f, str, str+n); - } +void JS::printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format) +{ + char str[20]; + int n = sprintf(str, format, i); + if (n < nDigits) + printChar(f, pad, nDigits - n); + printString(f, str, str+n); +} // Print p as a pointer. - void - printPtr(Formatter &f, void *p) - { - char str[20]; - int n = sprintf(str, "%p", p); - printString(f, str, str+n); - } +void JS::printPtr(Formatter &f, void *p) +{ + char str[20]; + int n = sprintf(str, "%p", p); + printString(f, str, str+n); +} // printf formats for printing non-ASCII characters on an ASCII stream #ifdef XP_MAC - static const char unprintableFormat[] = "\xC7%.4X\xC8"; // Use angle quotes +static const char unprintableFormat[] = "\xC7%.4X\xC8"; // Use angle quotes #elif defined _WIN32 - static const char unprintableFormat[] = "\xAB%.4X\xBB"; // Use angle quotes +static const char unprintableFormat[] = "\xAB%.4X\xBB"; // Use angle quotes #else - static const char unprintableFormat[] = "<%.4X>"; +static const char unprintableFormat[] = "<%.4X>"; #endif - static const uint16 defaultFilterRanges[] = { - 0x00, 0x09, // Filter all control characters except \t and \n - 0x0B, 0x20, - 0x7F, 0x100, // Filter all non-ASCII characters - 0, 0 - }; +static const uint16 defaultFilterRanges[] = { + 0x00, 0x09, // Filter all control characters except \t and \n + 0x0B, 0x20, + 0x7F, 0x100, // Filter all non-ASCII characters + 0, 0 +}; - BitSet<256> AsciiFileFormatter::defaultFilter(defaultFilterRanges); +JS::BitSet<256> JS::AsciiFileFormatter::defaultFilter(defaultFilterRanges); // Construct an AsciiFileFormatter using the given file and filter f. // If f is nil, use the default filter. - AsciiFileFormatter::AsciiFileFormatter(FILE *file, BitSet<256> *f): - file(file) -#ifndef _WIN32 // Microsoft Visual C++ 6.0 bug - , filter(f ? *f : defaultFilter) +JS::AsciiFileFormatter::AsciiFileFormatter(FILE *file, BitSet<256> *f): file(file) +#ifndef _WIN32 // Microsoft Visual C++ 6.0 bug + , filter(f ? *f : defaultFilter) #endif - { -#ifdef _WIN32 // Microsoft Visual C++ 6.0 bug - if (f) - filter = *f; - else - filter = defaultFilter; +{ +#ifdef _WIN32 // Microsoft Visual C++ 6.0 bug + if (f) + filter = *f; + else + filter = defaultFilter; #endif - filterEmpty = filter.none(); - } + filterEmpty = filter.none(); +} // Write ch, escaping non-ASCII characters. - void - AsciiFileFormatter::printChar8(char ch) - { - if (filterChar(ch)) - fprintf(file, unprintableFormat, static_cast(ch)); - else - fputc(ch, file); - } +void JS::AsciiFileFormatter::printChar8(char ch) +{ + if (filterChar(ch)) + fprintf(file, unprintableFormat, static_cast(ch)); + else + fputc(ch, file); +} // Write ch, escaping non-ASCII characters. - void - AsciiFileFormatter::printChar16(char16 ch) - { - if (filterChar(ch)) - fprintf(file, unprintableFormat, char16Value(ch)); - else - fputc(static_cast(ch), file); - } +void JS::AsciiFileFormatter::printChar16(char16 ch) +{ + if (filterChar(ch)) + fprintf(file, unprintableFormat, char16Value(ch)); + else + fputc(static_cast(ch), file); +} // Write the null-terminated string str, escaping non-ASCII characters. - void - AsciiFileFormatter::printZStr8(const char *str) - { - if (filterEmpty) - fputs(str, file); - else - printStr8(str, str + strlen(str)); - } +void JS::AsciiFileFormatter::printZStr8(const char *str) +{ + if (filterEmpty) + fputs(str, file); + else + printStr8(str, str + strlen(str)); +} // Write the string between strBegin and strEnd, escaping non-ASCII characters. - void - AsciiFileFormatter::printStr8(const char *strBegin, const char *strEnd) - { - if (filterEmpty) - printChars(file, strBegin, strEnd); - else { - ASSERT(strEnd >= strBegin); - const char *p = strBegin; - while (strBegin != strEnd) { - char ch = *strBegin; - if (filterChar(ch)) { - if (p != strBegin) { - printChars(file, p, strBegin); - p = strBegin; - } - fprintf(file, unprintableFormat, static_cast(ch)); - } - ++strBegin; - } - if (p != strBegin) - printChars(file, p, strBegin); - } - } +void JS::AsciiFileFormatter::printStr8(const char *strBegin, const char *strEnd) +{ + if (filterEmpty) + printChars(file, strBegin, strEnd); + else { + ASSERT(strEnd >= strBegin); + const char *p = strBegin; + while (strBegin != strEnd) { + char ch = *strBegin; + if (filterChar(ch)) { + if (p != strBegin) { + printChars(file, p, strBegin); + p = strBegin; + } + fprintf(file, unprintableFormat, static_cast(ch)); + } + ++strBegin; + } + if (p != strBegin) + printChars(file, p, strBegin); + } +} + // Write the string between strBegin and strEnd, escaping non-ASCII characters. - void - AsciiFileFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) - { - char buffer[512]; +void JS::AsciiFileFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) +{ + char buffer[512]; - ASSERT(strEnd >= strBegin); - char *q = buffer; - while (strBegin != strEnd) { - char16 ch = *strBegin++; - if (filterChar(ch)) { - if (q != buffer) { - printChars(file, buffer, q); - q = buffer; - } - fprintf(file, unprintableFormat, char16Value(ch)); - } else { - *q++ = static_cast(ch); - if (q == buffer + sizeof buffer) { - printChars(file, buffer, buffer + sizeof buffer); - q = buffer; - } - } - } - if (q != buffer) - printChars(file, buffer, q); - } + ASSERT(strEnd >= strBegin); + char *q = buffer; + while (strBegin != strEnd) { + char16 ch = *strBegin++; + if (filterChar(ch)) { + if (q != buffer) { + printChars(file, buffer, q); + q = buffer; + } + fprintf(file, unprintableFormat, char16Value(ch)); + } else { + *q++ = static_cast(ch); + if (q == buffer + sizeof buffer) { + printChars(file, buffer, buffer + sizeof buffer); + q = buffer; + } + } + } + if (q != buffer) + printChars(file, buffer, q); +} - AsciiFileFormatter stdOut(stdout); - AsciiFileFormatter stdErr(stderr); + +JS::AsciiFileFormatter JS::stdOut(stdout); +JS::AsciiFileFormatter JS::stdErr(stderr); // Write ch. - void - StringFormatter::printChar8(char ch) - { - s += ch; - } +void JS::StringFormatter::printChar8(char ch) +{ + s += ch; +} // Write ch. - void - StringFormatter::printChar16(char16 ch) - { - s += ch; - } +void JS::StringFormatter::printChar16(char16 ch) +{ + s += ch; +} // Write the null-terminated string str. - void - StringFormatter::printZStr8(const char *str) - { - s += str; - } +void JS::StringFormatter::printZStr8(const char *str) +{ + s += str; +} // Write the string between strBegin and strEnd. - void - StringFormatter::printStr8(const char *strBegin, const char *strEnd) - { - appendChars(s, strBegin, strEnd); - } +void JS::StringFormatter::printStr8(const char *strBegin, const char *strEnd) +{ + appendChars(s, strBegin, strEnd); +} // Write the string between strBegin and strEnd. - void - StringFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) - { - s.append(strBegin, strEnd); - } +void JS::StringFormatter::printStr16(const char16 *strBegin, const char16 *strEnd) +{ + s.append(strBegin, strEnd); +} // Write the String str. - void - StringFormatter::printString16(const String &str) - { - s += str; - } +void JS::StringFormatter::printString16(const String &str) +{ + s += str; +} + // @@ -475,39 +448,39 @@ namespace JavaScript // Languages and Systems 2:4, October 1980, pages 477-482 for the algorithm. // The default line width for pretty printing - uint32 PrettyPrinter::defaultLineWidth = 20; +uint32 JS::PrettyPrinter::defaultLineWidth = 20; -// Create a PrettyPrinter that outputs to Formatter f. The PrettyPrinter +// Create a PrettyPrinter that outputs to Formatter f. The PrettyPrinter // breaks lines at optional breaks so as to try not to exceed lines of width -// lineWidth, although it may not always be able to do so. Formatter f should +// lineWidth, although it may not always be able to do so. Formatter f should // be at the beginning of a line. Call end before destroying the Formatter; // otherwise the last line may not be output to f. - PrettyPrinter::PrettyPrinter(Formatter &f, uint32 lineWidth): - lineWidth(min(lineWidth, static_cast(unlimitedLineWidth))), - outputFormatter(f), - outputPos(0), - lineNum(0), - lastBreak(0), - margin(0), - nNestedBlocks(0), - leftSerialPos(0), - rightSerialPos(0), - itemPool(20) - { +JS::PrettyPrinter::PrettyPrinter(Formatter &f, uint32 lineWidth): + lineWidth(min(lineWidth, static_cast(unlimitedLineWidth))), + outputFormatter(f), + outputPos(0), + lineNum(0), + lastBreak(0), + margin(0), + nNestedBlocks(0), + leftSerialPos(0), + rightSerialPos(0), + itemPool(20) +{ #ifdef DEBUG - topRegion = 0; + topRegion = 0; #endif - } +} // Destroy the PrettyPrinter. Because it's a very bad idea for a destructor to // throw exceptions, this destructor does not flush any buffered output. Call // end just before destroying the PrettyPrinter to do that. - PrettyPrinter::~PrettyPrinter() - { - ASSERT(!topRegion && !nNestedBlocks); - } +JS::PrettyPrinter::~PrettyPrinter() +{ + ASSERT(!topRegion && !nNestedBlocks); +} // Output either a line break (if sameLine is false) or length spaces (if @@ -516,23 +489,22 @@ namespace JavaScript // If this method throws an exception, it is guaranteed to already have updated // all of the PrettyPrinter state; all that might be missing would be some // output to outputFormatter. - void - PrettyPrinter::outputBreak(bool sameLine, uint32 length) - { - leftSerialPos += length; +void JS::PrettyPrinter::outputBreak(bool sameLine, uint32 length) +{ + leftSerialPos += length; - if (sameLine) { - outputPos += length; - // Exceptions may be thrown below. - printChar(outputFormatter, ' ', static_cast(length)); - } else { - lastBreak = ++lineNum; - outputPos = margin; - // Exceptions may be thrown below. - outputFormatter << '\n'; - printChar(outputFormatter, ' ', static_cast(margin)); - } - } + if (sameLine) { + outputPos += length; + // Exceptions may be thrown below. + printChar(outputFormatter, ' ', static_cast(length)); + } else { + lastBreak = ++lineNum; + outputPos = margin; + // Exceptions may be thrown below. + outputFormatter << '\n'; + printChar(outputFormatter, ' ', static_cast(margin)); + } +} // Check to see whether (rightSerialPos+rightOffset)-leftSerialPos has gotten so large that we may pop items @@ -542,91 +514,86 @@ namespace JavaScript // // If this method throws an exception, it leaves the PrettyPrinter in a consistent state, having // atomically popped off one or more items from the left end of activeItems. - bool - PrettyPrinter::reduceLeftActiveItems(uint32 rightOffset) - { - uint32 newRightSerialPos = rightSerialPos + rightOffset; - while (activeItems) { - Item *leftItem = &activeItems.front(); - if (itemStack && leftItem == itemStack.front()) { - if (outputPos + newRightSerialPos - leftSerialPos > lineWidth) { - itemStack.pop_front(); - leftItem->lengthKnown = true; - leftItem->totalLength = infiniteLength; - } else if (leftItem->lengthKnown) - itemStack.pop_front(); - } +bool JS::PrettyPrinter::reduceLeftActiveItems(uint32 rightOffset) +{ + uint32 newRightSerialPos = rightSerialPos + rightOffset; + while (activeItems) { + Item *leftItem = &activeItems.front(); + if (itemStack && leftItem == itemStack.front()) { + if (outputPos + newRightSerialPos - leftSerialPos > lineWidth) { + itemStack.pop_front(); + leftItem->lengthKnown = true; + leftItem->totalLength = infiniteLength; + } else if (leftItem->lengthKnown) + itemStack.pop_front(); + } - if (!leftItem->lengthKnown) - return true; + if (!leftItem->lengthKnown) + return true; - activeItems.pop_front(); - try { - uint32 length = leftItem->length; - switch (leftItem->kind) { - case Item::text: - { - outputPos += length; - leftSerialPos += length; - // Exceptions may be thrown below. - char16 *textBegin; - char16 *textEnd; - do { - length -= itemText.pop_front(length, textBegin, - textEnd); - printString(outputFormatter, textBegin, textEnd); - } while (length); - } - break; - - case Item::blockBegin: - case Item::indentBlockBegin: - { - BlockInfo *b = savedBlocks.advance_back(); - b->margin = margin; - b->lastBreak = lastBreak; - b->fits = outputPos + leftItem->totalLength <= lineWidth; - if (leftItem->hasKind(Item::blockBegin)) - margin = outputPos; - else - margin += length; - } - break; - - case Item::blockEnd: - { - BlockInfo &b = savedBlocks.pop_back(); - margin = b.margin; - lastBreak = b.lastBreak; - } - break; - - case Item::indent: - margin += length; - ASSERT(static_cast(margin) >= 0); - break; - - case Item::linearBreak: - // Exceptions may be thrown below, but only after - // updating the PrettyPrinter. - outputBreak(savedBlocks.back().fits, length); - break; - - case Item::fillBreak: - // Exceptions may be thrown below, but only after - // updating the PrettyPrinter. - outputBreak(lastBreak == lineNum && outputPos + - leftItem->totalLength <= lineWidth, length); - break; - } - } catch (...) { - itemPool.destroy(leftItem); - throw; - } - itemPool.destroy(leftItem); - } - return false; - } + activeItems.pop_front(); + try { + uint32 length = leftItem->length; + switch (leftItem->kind) { + case Item::text: + { + outputPos += length; + leftSerialPos += length; + // Exceptions may be thrown below. + char16 *textBegin; + char16 *textEnd; + do { + length -= itemText.pop_front(length, textBegin, textEnd); + printString(outputFormatter, textBegin, textEnd); + } while (length); + } + break; + + case Item::blockBegin: + case Item::indentBlockBegin: + { + BlockInfo *b = savedBlocks.advance_back(); + b->margin = margin; + b->lastBreak = lastBreak; + b->fits = outputPos + leftItem->totalLength <= lineWidth; + if (leftItem->hasKind(Item::blockBegin)) + margin = outputPos; + else + margin += length; + } + break; + + case Item::blockEnd: + { + BlockInfo &b = savedBlocks.pop_back(); + margin = b.margin; + lastBreak = b.lastBreak; + } + break; + + case Item::indent: + margin += length; + ASSERT(static_cast(margin) >= 0); + break; + + case Item::linearBreak: + // Exceptions may be thrown below, but only after updating the PrettyPrinter. + outputBreak(savedBlocks.back().fits, length); + break; + + case Item::fillBreak: + // Exceptions may be thrown below, but only after updating the PrettyPrinter. + outputBreak(lastBreak == lineNum && outputPos + leftItem->totalLength <= lineWidth, length); + break; + } + } catch (...) { + itemPool.destroy(leftItem); + throw; + } + itemPool.destroy(leftItem); + } + return false; +} // A break or end of input is about to be processed. Check whether there are @@ -635,82 +602,75 @@ namespace JavaScript // The current rightSerialPos must be the beginning of the break or end of input. // // This method can't throw exceptions. - void - PrettyPrinter::reduceRightActiveItems() - { - uint32 nUnmatchedBlockEnds = 0; - while (itemStack) { - Item *rightItem = itemStack.pop_back(); - switch (rightItem->kind) { - case Item::blockBegin: - case Item::indentBlockBegin: - if (!nUnmatchedBlockEnds) { - itemStack.fast_push_back(rightItem); - return; - } - rightItem->computeTotalLength(rightSerialPos); - --nUnmatchedBlockEnds; - break; +void JS::PrettyPrinter::reduceRightActiveItems() +{ + uint32 nUnmatchedBlockEnds = 0; + while (itemStack) { + Item *rightItem = itemStack.pop_back(); + switch (rightItem->kind) { + case Item::blockBegin: + case Item::indentBlockBegin: + if (!nUnmatchedBlockEnds) { + itemStack.fast_push_back(rightItem); + return; + } + rightItem->computeTotalLength(rightSerialPos); + --nUnmatchedBlockEnds; + break; - case Item::blockEnd: - ++nUnmatchedBlockEnds; - break; + case Item::blockEnd: + ++nUnmatchedBlockEnds; + break; - case Item::linearBreak: - case Item::fillBreak: - rightItem->computeTotalLength(rightSerialPos); - if (!nUnmatchedBlockEnds) - // There can be at most one consecutive break posted on - // the itemStack. - return; - break; + case Item::linearBreak: + case Item::fillBreak: + rightItem->computeTotalLength(rightSerialPos); + if (!nUnmatchedBlockEnds) + // There can be at most one consecutive break posted on the itemStack. + return; + break; - default: - ASSERT(false); // Other kinds can't be pushed onto the - // itemStack. - } - } - } + default: + ASSERT(false); // Other kinds can't be pushed onto the itemStack. + } + } +} // Indent the beginning of every new line after this one by offset until the // corresponding endIndent call. Return an Item to pass to endIndent that will // end this indentation. This method may throw an exception, in which case the // PrettyPrinter is left unchanged. - PrettyPrinter::Item & - PrettyPrinter::beginIndent(int32 offset) - { - Item *unindent = new(itemPool) Item(Item::indent, - static_cast(-offset)); - if (activeItems) { - try { - activeItems.push_back(*new(itemPool) Item(Item::indent, - static_cast(offset))); - } catch (...) { - itemPool.destroy(unindent); - throw; - } - } else { - margin += offset; - ASSERT(static_cast(margin) >= 0); - } - return *unindent; - } +JS::PrettyPrinter::Item &JS::PrettyPrinter::beginIndent(int32 offset) +{ + Item *unindent = new(itemPool) Item(Item::indent, static_cast(-offset)); + if (activeItems) { + try { + activeItems.push_back(*new(itemPool) Item(Item::indent, static_cast(offset))); + } catch (...) { + itemPool.destroy(unindent); + throw; + } + } else { + margin += offset; + ASSERT(static_cast(margin) >= 0); + } + return *unindent; +} -// End an indent began by beginIndent. i should be the result of a beginIndent. +// End an indent began by beginIndent. i should be the result of a beginIndent. // This method can't throw exceptions (it's called by the Indent destructor). - void - PrettyPrinter::endIndent(Item &i) - { - if (activeItems) - activeItems.push_back(i); - else { - margin += i.length; - ASSERT(static_cast(margin) >= 0); - itemPool.destroy(&i); - } - } +void JS::PrettyPrinter::endIndent(Item &i) +{ + if (activeItems) + activeItems.push_back(i); + else { + margin += i.length; + ASSERT(static_cast(margin) >= 0); + itemPool.destroy(&i); + } +} // Begin a logical block. If kind is Item::indentBlockBegin, offset is the @@ -718,43 +678,40 @@ namespace JavaScript // Return an Item to pass to endBlock that will end this block. // This method may throw an exception, in which case the PrettyPrinter is left // unchanged. - PrettyPrinter::Item & - PrettyPrinter::beginBlock(Item::Kind kind, int32 offset) - { - uint32 newNNestedBlocks = nNestedBlocks + 1; - savedBlocks.reserve(newNNestedBlocks); - itemStack.reserve_back(1 + newNNestedBlocks); - Item *endItem = new(itemPool) Item(Item::blockEnd); - Item *beginItem; - try { - beginItem = new(itemPool) Item(kind, static_cast(offset), - rightSerialPos); - } catch (...) { - itemPool.destroy(endItem); - throw; - } - // No state modifications before this point. - // No exceptions after this point. - activeItems.push_back(*beginItem); - itemStack.fast_push_back(beginItem); - nNestedBlocks = newNNestedBlocks; - return *endItem; - } +JS::PrettyPrinter::Item &JS::PrettyPrinter::beginBlock(Item::Kind kind, int32 offset) +{ + uint32 newNNestedBlocks = nNestedBlocks + 1; + savedBlocks.reserve(newNNestedBlocks); + itemStack.reserve_back(1 + newNNestedBlocks); + Item *endItem = new(itemPool) Item(Item::blockEnd); + Item *beginItem; + try { + beginItem = new(itemPool) Item(kind, static_cast(offset), rightSerialPos); + } catch (...) { + itemPool.destroy(endItem); + throw; + } + // No state modifications before this point. + // No exceptions after this point. + activeItems.push_back(*beginItem); + itemStack.fast_push_back(beginItem); + nNestedBlocks = newNNestedBlocks; + return *endItem; +} // End a logical block began by beginBlock. i should be the result of a // beginBlock. // This method can't throw exceptions (it's called by the Block destructor). - void - PrettyPrinter::endBlock(Item &i) - { - activeItems.push_back(i); - itemStack.fast_push_back(&i); - --nNestedBlocks; - } +void JS::PrettyPrinter::endBlock(Item &i) +{ + activeItems.push_back(i); + itemStack.fast_push_back(&i); + --nNestedBlocks; +} -// Write a conditional line break. This kind of a line break can only be +// Write a conditional line break. This kind of a line break can only be // emitted inside a block. // A linear line break starts a new line if the containing block cannot be put // all one one line; otherwise the line break is replaced by nSpaces spaces. @@ -771,21 +728,20 @@ namespace JavaScript // // If this method throws an exception, it leaves the PrettyPrinter in a // consistent state. - void - PrettyPrinter::conditionalBreak(uint32 nSpaces, Item::Kind kind) - { - ASSERT(nSpaces <= unlimitedLineWidth && nNestedBlocks); - reduceRightActiveItems(); - itemStack.reserve_back(1 + nNestedBlocks); - // Begin of exception-atomic stack update. Only new(itemPool) can throw - // an exception here, in which case nothing is updated. - Item *i = new(itemPool) Item(kind, nSpaces, rightSerialPos); - activeItems.push_back(*i); - itemStack.fast_push_back(i); - rightSerialPos += nSpaces; - // End of exception-atomic stack update. - reduceLeftActiveItems(0); - } +void JS::PrettyPrinter::conditionalBreak(uint32 nSpaces, Item::Kind kind) +{ + ASSERT(nSpaces <= unlimitedLineWidth && nNestedBlocks); + reduceRightActiveItems(); + itemStack.reserve_back(1 + nNestedBlocks); + // Begin of exception-atomic stack update. Only new(itemPool) can throw + // an exception here, in which case nothing is updated. + Item *i = new(itemPool) Item(kind, nSpaces, rightSerialPos); + activeItems.push_back(*i); + itemStack.fast_push_back(i); + rightSerialPos += nSpaces; + // End of exception-atomic stack update. + reduceLeftActiveItems(0); +} // Write the string between strBegin and strEnd. Any embedded newlines ('\n' @@ -793,42 +749,37 @@ namespace JavaScript // // If this method throws an exception, it may have partially formatted the // string but leaves the PrettyPrinter in a consistent state. - void - PrettyPrinter::printStr8(const char *strBegin, const char *strEnd) - { - while (strBegin != strEnd) { - const char *sectionEnd = findValue(strBegin, strEnd, '\n'); - uint32 sectionLength = static_cast(sectionEnd - strBegin); - if (sectionLength) { - if (reduceLeftActiveItems(sectionLength)) { - itemText.reserve_back(sectionLength); - Item &backItem = activeItems.back(); - // Begin of exception-atomic update. Only new(itemPool) - // can throw an exception here, in which case nothing is - // updated. - if (backItem.hasKind(Item::text)) - backItem.length += sectionLength; - else - activeItems.push_back(*new(itemPool) Item(Item::text, - sectionLength)); - rightSerialPos += sectionLength; - itemText.fast_append(reinterpret_cast(strBegin), - reinterpret_cast(sectionEnd)); - // End of exception-atomic update. - } else { - ASSERT(!itemStack && !activeItems && !itemText && - leftSerialPos == rightSerialPos); - outputPos += sectionLength; - printString(outputFormatter, strBegin, sectionEnd); - } - strBegin = sectionEnd; - if (strBegin == strEnd) - break; - } - requiredBreak(); - ++strBegin; - } - } +void JS::PrettyPrinter::printStr8(const char *strBegin, const char *strEnd) +{ + while (strBegin != strEnd) { + const char *sectionEnd = findValue(strBegin, strEnd, '\n'); + uint32 sectionLength = static_cast(sectionEnd - strBegin); + if (sectionLength) { + if (reduceLeftActiveItems(sectionLength)) { + itemText.reserve_back(sectionLength); + Item &backItem = activeItems.back(); + // Begin of exception-atomic update. Only new(itemPool) can throw an exception here, + // in which case nothing is updated. + if (backItem.hasKind(Item::text)) + backItem.length += sectionLength; + else + activeItems.push_back(*new(itemPool) Item(Item::text, sectionLength)); + rightSerialPos += sectionLength; + itemText.fast_append(reinterpret_cast(strBegin), reinterpret_cast(sectionEnd)); + // End of exception-atomic update. + } else { + ASSERT(!itemStack && !activeItems && !itemText && leftSerialPos == rightSerialPos); + outputPos += sectionLength; + printString(outputFormatter, strBegin, sectionEnd); + } + strBegin = sectionEnd; + if (strBegin == strEnd) + break; + } + requiredBreak(); + ++strBegin; + } +} // Write the string between strBegin and strEnd. Any embedded newlines ('\n' @@ -836,56 +787,51 @@ namespace JavaScript // // If this method throws an exception, it may have partially formatted the // string but leaves the PrettyPrinter in a consistent state. - void - PrettyPrinter::printStr16(const char16 *strBegin, const char16 *strEnd) - { - while (strBegin != strEnd) { - const char16 *sectionEnd = findValue(strBegin, strEnd, uni::lf); - uint32 sectionLength = static_cast(sectionEnd - strBegin); - if (sectionLength) { - if (reduceLeftActiveItems(sectionLength)) { - itemText.reserve_back(sectionLength); - Item &backItem = activeItems.back(); - // Begin of exception-atomic update. Only new(itemPool) - // can throw an exception here, in which case nothing is - // updated. - if (backItem.hasKind(Item::text)) - backItem.length += sectionLength; - else - activeItems.push_back(*new(itemPool) Item(Item::text, - sectionLength)); - rightSerialPos += sectionLength; - itemText.fast_append(strBegin, sectionEnd); - // End of exception-atomic update. - } else { - ASSERT(!itemStack && !activeItems && !itemText && - leftSerialPos == rightSerialPos); - outputPos += sectionLength; - printString(outputFormatter, strBegin, sectionEnd); - } - strBegin = sectionEnd; - if (strBegin == strEnd) - break; - } - requiredBreak(); - ++strBegin; - } - } +void JS::PrettyPrinter::printStr16(const char16 *strBegin, const char16 *strEnd) +{ + while (strBegin != strEnd) { + const char16 *sectionEnd = findValue(strBegin, strEnd, uni::lf); + uint32 sectionLength = static_cast(sectionEnd - strBegin); + if (sectionLength) { + if (reduceLeftActiveItems(sectionLength)) { + itemText.reserve_back(sectionLength); + Item &backItem = activeItems.back(); + // Begin of exception-atomic update. Only new(itemPool) can throw an exception here, + // in which case nothing is updated. + if (backItem.hasKind(Item::text)) + backItem.length += sectionLength; + else + activeItems.push_back(*new(itemPool) Item(Item::text, sectionLength)); + rightSerialPos += sectionLength; + itemText.fast_append(strBegin, sectionEnd); + // End of exception-atomic update. + } else { + ASSERT(!itemStack && !activeItems && !itemText && leftSerialPos == rightSerialPos); + outputPos += sectionLength; + printString(outputFormatter, strBegin, sectionEnd); + } + strBegin = sectionEnd; + if (strBegin == strEnd) + break; + } + requiredBreak(); + ++strBegin; + } +} // Write a required line break. // // If this method throws an exception, it may have emitted partial output but // leaves the PrettyPrinter in a consistent state. - void - PrettyPrinter::requiredBreak() - { - reduceRightActiveItems(); - reduceLeftActiveItems(infiniteLength); - ASSERT(!itemStack && !activeItems && !itemText && - leftSerialPos == rightSerialPos); - outputBreak(false, 0); - } +void JS::PrettyPrinter::requiredBreak() +{ + reduceRightActiveItems(); + reduceLeftActiveItems(infiniteLength); + ASSERT(!itemStack && !activeItems && !itemText && + leftSerialPos == rightSerialPos); + outputBreak(false, 0); +} // If required is true, write a required line break; otherwise write a linear @@ -893,14 +839,13 @@ namespace JavaScript // // If this method throws an exception, it may have emitted partial output but // leaves the PrettyPrinter in a consistent state. - void - PrettyPrinter::linearBreak(uint32 nSpaces, bool required) - { - if (required) - requiredBreak(); - else - linearBreak(nSpaces); - } +void JS::PrettyPrinter::linearBreak(uint32 nSpaces, bool required) +{ + if (required) + requiredBreak(); + else + linearBreak(nSpaces); +} // Flush any saved output in the PrettyPrinter to the output. Call this just @@ -909,15 +854,12 @@ namespace JavaScript // // If this method throws an exception, it may have emitted partial output but // leaves the PrettyPrinter in a consistent state. - void - PrettyPrinter::end() - { - ASSERT(!topRegion); - reduceRightActiveItems(); - reduceLeftActiveItems(infiniteLength); - ASSERT(!savedBlocks && !itemStack && !activeItems && !itemText && - rightSerialPos == leftSerialPos && !margin); - } - - +void JS::PrettyPrinter::end() +{ + ASSERT(!topRegion); + reduceRightActiveItems(); + reduceLeftActiveItems(infiniteLength); + ASSERT(!savedBlocks && !itemStack && !activeItems && !itemText && + rightSerialPos == leftSerialPos && !margin); } + diff --git a/mozilla/js2/src/formatter.h b/mozilla/js2/src/formatter.h index cb7fbdc6a1e..6f667b16449 100644 --- a/mozilla/js2/src/formatter.h +++ b/mozilla/js2/src/formatter.h @@ -13,11 +13,11 @@ * The Original Code is the JavaScript 2 Prototype. * * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are + * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License (the "GPL"), in which case the @@ -43,7 +43,7 @@ #include "utilities.h" #include "strings.h" -namespace JavaScript +namespace JavaScript { // // Output @@ -51,332 +51,271 @@ namespace JavaScript // Print the characters between begin and end to the given file. These // characters may include nulls. - size_t printChars(FILE *file, const char *begin, const char *end); + size_t printChars(FILE *file, const char *begin, const char *end); #ifndef XP_MAC_MPW - inline size_t printChars(FILE *file, const char *begin, const char *end) { - ASSERT(end >= begin); - return STD::fwrite(begin, 1, static_cast(end - begin), file); - } + inline size_t printChars(FILE *file, const char *begin, const char *end) { + ASSERT(end >= begin); + return STD::fwrite(begin, 1, static_cast(end - begin), file); + } #endif + // A Formatter is an abstract base class representing a simplified output stream. // One can print text to a Formatter by using << and the various global // print... methods below. Formatters accept both char and char16 text and // convert as appropriate to their actual stream. - class Formatter { - protected: - virtual void printChar8(char ch); - virtual void printChar16(char16 ch); - virtual void printZStr8(const char *str); - virtual void printStr8(const char *strBegin, const char *strEnd) = 0; - virtual void printStr16(const char16 *strBegin, - const char16 *strEnd) = 0; - virtual void printString16(const String &s); - virtual void printVFormat8(const char *format, va_list args); - public: - - Formatter &operator<<(char ch) {printChar8(ch); return *this;} - Formatter &operator<<(char16 ch) {printChar16(ch); return *this;} - Formatter &operator<<(const char *str) {printZStr8(str); return *this;} - Formatter &operator<<(const String &s) {printString16(s); return *this;} - Formatter &operator<<(uint32 i) { - printFormat(*this, "%u", i); - return *this; - } + class Formatter { + protected: + virtual void printChar8(char ch); + virtual void printChar16(char16 ch); + virtual void printZStr8(const char *str); + virtual void printStr8(const char *strBegin, const char *strEnd) = 0; + virtual void printStr16(const char16 *strBegin, const char16 *strEnd) = 0; + virtual void printString16(const String &s); + virtual void printVFormat8(const char *format, va_list args); + public: - friend void printString(Formatter &f, const char *strBegin, - const char *strEnd) { - f.printStr8(strBegin, strEnd); - } + Formatter &operator<<(char ch) {printChar8(ch); return *this;} + Formatter &operator<<(char16 ch) {printChar16(ch); return *this;} + Formatter &operator<<(const char *str) {printZStr8(str); return *this;} + Formatter &operator<<(const String &s) {printString16(s); return *this;} + Formatter &operator<<(uint32 i) { + printFormat(*this, "%u", i); + return *this; + } - friend void printString(Formatter &f, const char16 *strBegin, - const char16 *strEnd) { - f.printStr16(strBegin, strEnd); - } - - friend void printFormat(Formatter &f, const char *format, ...) { - va_list args; - va_start(args, format); - f.printVFormat8(format, args); - va_end(args); - } - }; - - void printNum(Formatter &f, uint32 i, int nDigits, char pad, - const char *format); - void printChar(Formatter &f, char ch, int count); - void printChar(Formatter &f, char16 ch, int count); + friend void printString(Formatter &f, const char *strBegin, const char *strEnd) { + f.printStr8(strBegin, strEnd); + } - inline void printDec(Formatter &f, int32 i, int nDigits = 0, - char pad = ' ') { - printNum(f, (uint32)i, nDigits, pad, "%i"); - } - - inline void printDec(Formatter &f, uint32 i, int nDigits = 0, - char pad = ' ') { - printNum(f, i, nDigits, pad, "%u"); - } - - inline void printHex(Formatter &f, int32 i, int nDigits = 0, - char pad = '0') { - printNum(f, (uint32)i, nDigits, pad, "%X"); - } - - inline void printHex(Formatter &f, uint32 i, int nDigits = 0, - char pad = '0') { - printNum(f, i, nDigits, pad, "%X"); - } - - void printPtr(Formatter &f, void *p); + friend void printString(Formatter &f, const char16 *strBegin, const char16 *strEnd) { + f.printStr16(strBegin, strEnd); + } + + friend void printFormat(Formatter &f, const char *format, ...) { + va_list args; + va_start(args, format); + f.printVFormat8(format, args); + va_end(args); + } + }; + + void printNum(Formatter &f, uint32 i, int nDigits, char pad, const char *format); + void printChar(Formatter &f, char ch, int count); + void printChar(Formatter &f, char16 ch, int count); + inline void printDec(Formatter &f, int32 i, int nDigits = 0, char pad = ' ') {printNum(f, (uint32)i, nDigits, pad, "%i");} + inline void printDec(Formatter &f, uint32 i, int nDigits = 0, char pad = ' ') {printNum(f, i, nDigits, pad, "%u");} + inline void printHex(Formatter &f, int32 i, int nDigits = 0, char pad = '0') {printNum(f, (uint32)i, nDigits, pad, "%X");} + inline void printHex(Formatter &f, uint32 i, int nDigits = 0, char pad = '0') {printNum(f, i, nDigits, pad, "%X");} + void printPtr(Formatter &f, void *p); - // An AsciiFileFormatter is a Formatter that prints to a standard ASCII - // file or stream. Characters with Unicode values of 256 or higher are - // converted to escape sequences. Selected lower characters can also be - // converted to escape sequences; these are specified by set bits in the - // BitSet passed to the constructor. - class AsciiFileFormatter: public Formatter { - FILE *file; - BitSet<256> filter; // Set of first 256 characters that are to be - // converted to escape sequences - bool filterEmpty; // True if filter passes all 256 characters - public: - static BitSet<256> defaultFilter; // Default value of filter when not - // given in the constructor - - explicit AsciiFileFormatter(FILE *file, BitSet<256> *filter = 0); + // An AsciiFileFormatter is a Formatter that prints to a standard ASCII + // file or stream. Characters with Unicode values of 256 or higher are + // converted to escape sequences. Selected lower characters can also be + // converted to escape sequences; these are specified by set bits in the + // BitSet passed to the constructor. + class AsciiFileFormatter: public Formatter { + FILE *file; + BitSet<256> filter; // Set of first 256 characters that are to be converted to escape sequences + bool filterEmpty; // True if filter passes all 256 characters + public: + static BitSet<256> defaultFilter; // Default value of filter when not given in the constructor - private: - bool filterChar(char ch) {return filter[static_cast(ch)];} - bool filterChar(char16 ch) { - return char16Value(ch) >= 0x100 || filter[char16Value(ch)]; - } - - protected: - void printChar8(char ch); - void printChar16(char16 ch); - void printZStr8(const char *str); - void printStr8(const char *strBegin, const char *strEnd); - void printStr16(const char16 *strBegin, const char16 *strEnd); - }; + explicit AsciiFileFormatter(FILE *file, BitSet<256> *filter = 0); - extern AsciiFileFormatter stdOut; - extern AsciiFileFormatter stdErr; + private: + bool filterChar(char ch) {return filter[static_cast(ch)];} + bool filterChar(char16 ch) { + return char16Value(ch) >= 0x100 || filter[char16Value(ch)]; + } + + protected: + void printChar8(char ch); + void printChar16(char16 ch); + void printZStr8(const char *str); + void printStr8(const char *strBegin, const char *strEnd); + void printStr16(const char16 *strBegin, const char16 *strEnd); + }; + + extern AsciiFileFormatter stdOut; + extern AsciiFileFormatter stdErr; - // A StringFormatter is a Formatter that prints to a String. - class StringFormatter: public Formatter { - String s; + // A StringFormatter is a Formatter that prints to a String. + class StringFormatter: public Formatter { + String s; - public: - const String& getString() { return s; } - void clear() {JavaScript::clear(s);} - protected: - void printChar8(char ch); - void printChar16(char16 ch); - void printZStr8(const char *str); - void printStr8(const char *strBegin, const char *strEnd); - void printStr16(const char16 *strBegin, const char16 *strEnd); - void printString16(const String &str); - }; + public: + const String& getString() { return s; } + void clear() {JavaScript::clear(s);} + protected: + void printChar8(char ch); + void printChar16(char16 ch); + void printZStr8(const char *str); + void printStr8(const char *strBegin, const char *strEnd); + void printStr16(const char16 *strBegin, const char16 *strEnd); + void printString16(const String &str); + }; // // Formatted Output // - class PrettyPrinter: public Formatter { - public: - STATIC_CONST(uint32, unlimitedLineWidth = 0x7FFFFFFF); - class Region; - class Indent; - class Block; + class PrettyPrinter: public Formatter { + public: + STATIC_CONST(uint32, unlimitedLineWidth = 0x7FFFFFFF); + class Region; + class Indent; + class Block; - private: - STATIC_CONST(uint32, infiniteLength = 0x80000000); - const uint32 lineWidth; // Current maximum desired line width + private: + STATIC_CONST(uint32, infiniteLength = 0x80000000); + const uint32 lineWidth; // Current maximum desired line width - struct BlockInfo { - uint32 margin; // Saved margin before this block's beginning - uint32 lastBreak; // Saved lastBreak before this block's beginning - bool fits; // True if this entire block fits on one line - }; - // Variables for the back end that prints to the destination - Formatter &outputFormatter; // Destination formatter on which the - // result should be printed - uint32 outputPos; // Number of characters printed on current - // output line - uint32 lineNum; // Serial number of current line - uint32 lastBreak; // Number of line just after the last - // break that occurred in this block - uint32 margin; // Current left margin in spaces - ArrayBuffer savedBlocks; // Stack of saved information - // about partially printed blocks + struct BlockInfo { + uint32 margin; // Saved margin before this block's beginning + uint32 lastBreak; // Saved lastBreak before this block's beginning + bool fits; // True if this entire block fits on one line + }; - // Variables for the front end that calculates block sizes - struct Item: ListQueueEntry { - enum Kind {text, blockBegin, indentBlockBegin, blockEnd, indent, - linearBreak, fillBreak}; + // Variables for the back end that prints to the destination + Formatter &outputFormatter; // Destination formatter on which the result should be printed + uint32 outputPos; // Number of characters printed on current output line + uint32 lineNum; // Serial number of current line + uint32 lastBreak; // Number of line just after the last break that occurred in this block + uint32 margin; // Current left margin in spaces + ArrayBuffer savedBlocks; // Stack of saved information about partially printed blocks - const Kind kind; // The kind of this text sequence - bool lengthKnown; // True if totalLength is known; always true for - // text, blockEnd, and indent Items - uint32 length; // Length of this text sequence, number of spaces - // for this break, or delta for indent or - // indentBlockBegin - uint32 totalLength; // Total length of this block (for blockBegin) - // or length of this break plus following clump - // (for breaks) - // If lengthKnown is false, this is the - // serialPos of this Item instead of a length - bool hasKind(Kind k) const {return kind == k;} - - explicit Item(Kind kind) : - kind(kind), lengthKnown(true) {} - Item(Kind kind, uint32 length) : - kind(kind), lengthKnown(true), length(length) {} - Item(Kind kind, uint32 length, uint32 beginSerialPos): - kind(kind), lengthKnown(false), length(length), - totalLength(beginSerialPos) {} - - void computeTotalLength(uint32 endSerialPos) { - ASSERT(!lengthKnown); - lengthKnown = true; - totalLength = endSerialPos - totalLength; - } - - }; + // Variables for the front end that calculates block sizes + struct Item: ListQueueEntry { + enum Kind {text, blockBegin, indentBlockBegin, blockEnd, indent, linearBreak, fillBreak}; + + const Kind kind; // The kind of this text sequence + bool lengthKnown; // True if totalLength is known; always true for text, blockEnd, and indent Items + uint32 length; // Length of this text sequence, number of spaces for this break, or delta for indent or indentBlockBegin + uint32 totalLength; // Total length of this block (for blockBegin) or length of this break plus following clump (for breaks); + // If lengthKnown is false, this is the serialPos of this Item instead of a length + bool hasKind(Kind k) const {return kind == k;} + + explicit Item(Kind kind): kind(kind), lengthKnown(true) {} + Item(Kind kind, uint32 length): kind(kind), lengthKnown(true), length(length) {} + Item(Kind kind, uint32 length, uint32 beginSerialPos): + kind(kind), lengthKnown(false), length(length), totalLength(beginSerialPos) {} + + void computeTotalLength(uint32 endSerialPos) { + ASSERT(!lengthKnown); + lengthKnown = true; + totalLength = endSerialPos - totalLength; + } + + }; #ifdef DEBUG - Region *topRegion; // Most deeply nested Region + Region *topRegion; // Most deeply nested Region #endif - uint32 nNestedBlocks; // Number of nested Blocks - - uint32 leftSerialPos; // The difference rightSerialPos- - uint32 rightSerialPos; // leftSerialPos is always the number of - // characters that would be output by - // printing activeItems if they all fit - // on one line; only the difference - // matters -- the absolute values are - // irrelevant and may wrap around 2^32. - - ArrayQueue itemStack; // Stack of enclosing nested Items - // whose lengths have not yet been - // determined itemStack always has - // room for at least nNestedBlocks - // extra entries so that end Items - // may be added without throwing an - // exception. - - Pool itemPool; // Pool from which to allocate - // activeItems - - ListQueue activeItems; // Queue of items left to be printed - - ArrayQueue itemText; // Text of text items in activeItems, - // in the same order as in activeItems + uint32 nNestedBlocks; // Number of nested Blocks - public: - static uint32 defaultLineWidth; // Default for lineWidth if not given - // to the constructor + uint32 leftSerialPos; // The difference rightSerialPos- + uint32 rightSerialPos; // leftSerialPos is always the number of characters that would be output by + // printing activeItems if they all fit on one line; only the difference + // matters -- the absolute values are irrelevant and may wrap around 2^32. - explicit PrettyPrinter(Formatter &f, - uint32 lineWidth = defaultLineWidth); - private: - PrettyPrinter(const PrettyPrinter&); // No copy constructor - void operator=(const PrettyPrinter&); // No assignment operator - public: - ~PrettyPrinter(); - - private: - void outputBreak(bool sameLine, uint32 nSpaces); - bool reduceLeftActiveItems(uint32 rightOffset); - void reduceRightActiveItems(); + ArrayQueue itemStack; // Stack of enclosing nested Items whose lengths have not yet been determined; + // itemStack always has room for at least nNestedBlocks extra entries so that end Items + // may be added without throwing an exception. + Pool itemPool; // Pool from which to allocate activeItems + ListQueue activeItems; // Queue of items left to be printed + ArrayQueue itemText; // Text of text items in activeItems, in the same order as in activeItems - Item &beginIndent(int32 offset); - void endIndent(Item &i); + public: + static uint32 defaultLineWidth; // Default for lineWidth if not given to the constructor - Item &beginBlock(Item::Kind kind, int32 offset); - void endBlock(Item &i); + explicit PrettyPrinter(Formatter &f, uint32 lineWidth = defaultLineWidth); + private: + PrettyPrinter(const PrettyPrinter&); // No copy constructor + void operator=(const PrettyPrinter&); // No assignment operator + public: + ~PrettyPrinter(); - void conditionalBreak(uint32 nSpaces, Item::Kind kind); + private: + void outputBreak(bool sameLine, uint32 nSpaces); + bool reduceLeftActiveItems(uint32 rightOffset); + void reduceRightActiveItems(); - protected: - void printStr8(const char *strBegin, const char *strEnd); - void printStr16(const char16 *strBegin, const char16 *strEnd); - public: + Item &beginIndent(int32 offset); + void endIndent(Item &i); - void requiredBreak(); - void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces, - Item::linearBreak);} - void linearBreak(uint32 nSpaces, bool required); - void fillBreak(uint32 nSpaces) { - conditionalBreak(nSpaces, Item::fillBreak); - } - - void end(); + Item &beginBlock(Item::Kind kind, int32 offset); + void endBlock(Item &i); - friend class Region; - friend class Indent; - friend class Block; + void conditionalBreak(uint32 nSpaces, Item::Kind kind); - class Region { + protected: + void printStr8(const char *strBegin, const char *strEnd); + void printStr16(const char16 *strBegin, const char16 *strEnd); + public: + + void requiredBreak(); + void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::linearBreak);} + void linearBreak(uint32 nSpaces, bool required); + void fillBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::fillBreak);} + + void end(); + + friend class Region; + friend class Indent; + friend class Block; + + class Region { #ifdef DEBUG - Region *next; // Link to next most deeply nested Region + Region *next; // Link to next most deeply nested Region #endif - protected: - PrettyPrinter &pp; + protected: + PrettyPrinter &pp; - Region(PrettyPrinter &pp) : pp(pp) { - DEBUG_ONLY(next = pp.topRegion; pp.topRegion = this;); - } - private: - Region(const Region&); // No copy constructor - void operator=(const Region&); // No assignment operator - protected: + Region(PrettyPrinter &pp): pp(pp) {DEBUG_ONLY(next = pp.topRegion; pp.topRegion = this;);} + private: + Region(const Region&); // No copy constructor + void operator=(const Region&); // No assignment operator + protected: #ifdef DEBUG - ~Region() {pp.topRegion = next;} + ~Region() {pp.topRegion = next;} #endif - }; - - // Use an Indent object to temporarily indent a PrettyPrinter by the - // offset given to the Indent's constructor. The PrettyPrinter's margin - // is set back to its original value when the Indent object is destroyed. - // Using an Indent object is exception-safe; no matter how control - // leaves an Indent scope, the indent is undone. - // Scopes of Indent and Block objects must be properly nested. - class Indent: public Region { - Item &endItem; // The Item returned by beginIndent - public: - Indent(PrettyPrinter &pp, int32 offset) : - Region(pp), endItem(pp.beginIndent(offset)) {} - ~Indent() {pp.endIndent(endItem);} - }; - - // Use a Block object to temporarily enter a PrettyPrinter block. If an - // offset is provided, line breaks inside the block are indented by that - // offset relative to the existing indent; otherwise, line breaks inside - // the block are indented to the current output position. The block - // lasts until the Block object is destroyed. - // Scopes of Indent and Block objects must be properly nested. - class Block: public Region { - Item &endItem; // The Item returned by beginBlock - public: - explicit Block(PrettyPrinter &pp) : - Region(pp), endItem(pp.beginBlock(Item::blockBegin, 0)) {} - Block(PrettyPrinter &pp, int32 offset) : - Region(pp), endItem(pp.beginBlock(Item::indentBlockBegin, - offset)) {} - ~Block() {pp.endBlock(endItem);} - }; - }; + }; - - void escapeString(Formatter &f, const char16 *begin, const char16 *end, - char16 quote); - void quoteString(Formatter &f, const String &s, char16 quote); - + // Use an Indent object to temporarily indent a PrettyPrinter by the + // offset given to the Indent's constructor. The PrettyPrinter's margin + // is set back to its original value when the Indent object is destroyed. + // Using an Indent object is exception-safe; no matter how control + // leaves an Indent scope, the indent is undone. + // Scopes of Indent and Block objects must be properly nested. + class Indent: public Region { + Item &endItem; // The Item returned by beginIndent + public: + Indent(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginIndent(offset)) {} + ~Indent() {pp.endIndent(endItem);} + }; + + // Use a Block object to temporarily enter a PrettyPrinter block. If an + // offset is provided, line breaks inside the block are indented by that + // offset relative to the existing indent; otherwise, line breaks inside + // the block are indented to the current output position. The block + // lasts until the Block object is destroyed. + // Scopes of Indent and Block objects must be properly nested. + class Block: public Region { + Item &endItem; // The Item returned by beginBlock + public: + explicit Block(PrettyPrinter &pp): Region(pp), endItem(pp.beginBlock(Item::blockBegin, 0)) {} + Block(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginBlock(Item::indentBlockBegin, offset)) {} + ~Block() {pp.endBlock(endItem);} + }; + }; + + + void escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote); + void quoteString(Formatter &f, const String &s, char16 quote); } - #endif /* formatter_h___ */ diff --git a/mozilla/js2/src/icode_emitter.cpp b/mozilla/js2/src/icode_emitter.cpp index 36704749609..2cc7d33f397 100644 --- a/mozilla/js2/src/icode_emitter.cpp +++ b/mozilla/js2/src/icode_emitter.cpp @@ -74,22 +74,28 @@ bool LabelEntry::containsLabel(const StringAtom *label) return false; } -static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKind) +// ***** FIX ME! ***** +// The attributes should be evaluated, not pattern-matched against fixed names. +static bool hasAttribute(const ExprList *attributes, Token::Kind tokenKind) { - while (identifiers) { - if (identifiers->name.tokenKind == tokenKind) + while (attributes) { + ExprNode *expr = attributes->expr; + if (expr->hasKind(ExprNode::identifier) && static_cast(expr)->name.tokenKind == tokenKind) return true; - identifiers = identifiers->next; + attributes = attributes->next; } return false; } -static bool hasAttribute(const IdentifierList* identifiers, StringAtom &name) +// ***** FIX ME! ***** +// The attributes should be evaluated, not pattern-matched against fixed names. +static bool hasAttribute(const ExprList *attributes, const StringAtom &name) { - while (identifiers) { - if (identifiers->name == name) + while (attributes) { + ExprNode *expr = attributes->expr; + if (expr->hasKind(ExprNode::identifier) && static_cast(expr)->name == name) return true; - identifiers = identifiers->next; + attributes = attributes->next; } return false; } @@ -931,7 +937,7 @@ GenericNotBranch: } break; - case ExprNode::at: + case ExprNode::As: { BinaryExprNode *b = static_cast(p); // for now, just handle simple identifiers on the rhs. @@ -989,11 +995,13 @@ ICodeModule *ICodeGenerator::genFunction(FunctionDefinition &function, bool isSt if (v->name && (v->name->getKind() == ExprNode::identifier)) { JSType *pType = mContext->extractType(v->type); TypedRegister r = icg.allocateParameter((static_cast(v->name))->name, (v->initializer != NULL), pType); +#if 0 // ***** IdentifierList *a = v->aliases; while (a) { icg.parameterList->add(a->name, r, (v->initializer != NULL)); a = a->next; } +#endif // every unnamed parameter is also named with it's positional name if (unnamed) { positionalCount++; @@ -1055,21 +1063,10 @@ ICodeModule *ICodeGenerator::genFunction(FunctionDefinition &function, bool isSt if (superclass) { bool foundSuperCall = false; BlockStmtNode *b = function.body; - if (b && b->statements && (b->statements->getKind() == StmtNode::expression)) { + if (b && b->statements && (b->statements->hasKind(StmtNode::expression))) { ExprStmtNode *e = static_cast(b->statements); - if (e->expr->getKind() == ExprNode::call) { - InvokeExprNode *i = static_cast(e->expr); - if (i->op->getKind() == ExprNode::dot) { - BinaryExprNode *b = static_cast(i->op); - if ((b->op1->getKind() == ExprNode::This) && (b->op2->getKind() == ExprNode::qualify)) { - BinaryExprNode *q = static_cast(b->op2); - if (q->op1->getKind() == ExprNode::Super) { - // XXX verify that q->op2 is either the superclass name or a constructor for it - foundSuperCall = true; - } - } - } - } + if (e->expr->hasKind(ExprNode::superStmt)) + foundSuperCall = true; // ***** FIX ME ***** There are other forms of super-call. } if (!foundSuperCall) { // invoke the default superclass constructor icg.call(icg.bindThis(thisValue, icg.getStatic(superclass, superclass->getName())), args); @@ -1099,7 +1096,6 @@ JSTypes::Operator simpleLookup[ExprNode::kindsEnd] = { JSTypes::None, // True, JSTypes::None, // False, JSTypes::None, // This, - JSTypes::None, // Super, JSTypes::None, // parentheses, JSTypes::None, // numUnit, JSTypes::None, // exprUnit, @@ -1113,10 +1109,12 @@ JSTypes::Operator simpleLookup[ExprNode::kindsEnd] = { JSTypes::None, // dot, JSTypes::None, // dotClass, JSTypes::None, // dotParen, - JSTypes::None, // at, + JSTypes::None, // superExpr, + JSTypes::None, // superStmt, + JSTypes::None, // Const, JSTypes::None, // Delete, + JSTypes::None, // Void, JSTypes::None, // Typeof, - JSTypes::None, // Eval, JSTypes::None, // preIncrement, JSTypes::None, // preDecrement, JSTypes::None, // postIncrement, @@ -1147,6 +1145,7 @@ JSTypes::Operator simpleLookup[ExprNode::kindsEnd] = { JSTypes::None, // greaterThanOrEqual, JSTypes::SpittingImage, // identical, JSTypes::None, // notIdentical, + JSTypes::None, // As, JSTypes::In, // In, JSTypes::None, // Instanceof, JSTypes::None, // assignment, diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index 507f4c42f43..6f8e9df7c90 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -87,7 +87,7 @@ ICodeModule* Context::compileFunction(const String &source) Arena a; String filename = widenCString("Some source source"); Parser p(getWorld(), a, source, filename); - ExprNode* e = p.parseExpression(false); + ExprNode* e = p.parseListExpression(false); ASSERT(e->getKind() == ExprNode::functionLiteral); FunctionExprNode* f = static_cast(e); ICodeGenerator icg(this, NULL, NULL, ICodeGenerator::kIsTopLevel, extractType(f->function.resultType)); @@ -107,9 +107,9 @@ ICodeModule* Context::compileFunction(const String &source) JSValue Context::readEvalFile(FILE* in, const String& fileName) { String buffer; - int ch; - while ((ch = getc(in)) != EOF) - buffer += static_cast(ch); + int ch; + while ((ch = getc(in)) != EOF) + buffer += static_cast(ch); JSValues emptyArgs; JSValue result; @@ -119,18 +119,18 @@ JSValue Context::readEvalFile(FILE* in, const String& fileName) Parser p(getWorld(), a, buffer, fileName); StmtNode *parsedStatements = p.parseProgram(); /*******/ - ASSERT(p.lexer.peek(true).hasKind(Token::end)); + ASSERT(p.lexer.peek(true).hasKind(Token::end)); { PrettyPrinter f(stdOut, 30); { - PrettyPrinter::Block b(f, 2); + PrettyPrinter::Block b(f, 2); f << "Program ="; f.linearBreak(1); StmtNode::printStatements(f, parsedStatements); } f.end(); } - stdOut << '\n'; + stdOut << '\n'; /*******/ // Generate code for parsedStatements, which is a linked @@ -207,37 +207,37 @@ struct Linkage : public Context::Frame, public gc_base { } }; -static JSValue shiftLeft_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue shiftLeft_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toInt32()); JSValue num2(r2.toUInt32()); return JSValue(num1.i32 << (num2.u32 & 0x1F)); } -static JSValue shiftRight_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue shiftRight_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toInt32()); JSValue num2(r2.toUInt32()); return JSValue(num1.i32 >> (num2.u32 & 0x1F)); } -static JSValue UshiftRight_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue UshiftRight_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toUInt32()); JSValue num2(r2.toUInt32()); return JSValue(num1.u32 >> (num2.u32 & 0x1F)); } -static JSValue and_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue and_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toInt32()); JSValue num2(r2.toInt32()); return JSValue(num1.i32 & num2.i32); } -static JSValue or_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue or_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toInt32()); JSValue num2(r2.toInt32()); return JSValue(num1.i32 | num2.i32); } -static JSValue xor_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue xor_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toInt32()); JSValue num2(r2.toInt32()); @@ -272,50 +272,50 @@ static JSValue add_Default(Context *cx, const JSValue& r1, const JSValue& r2) } } -static JSValue subtract_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue subtract_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toNumber()); JSValue num2(r2.toNumber()); return JSValue(num1.f64 - num2.f64); } -static JSValue multiply_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue multiply_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toNumber()); JSValue num2(r2.toNumber()); return JSValue(num1.f64 * num2.f64); } -static JSValue divide_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue divide_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toNumber()); JSValue num2(r2.toNumber()); return JSValue(num1.f64 / num2.f64); } -static JSValue remainder_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue remainder_Default(Context *, const JSValue& r1, const JSValue& r2) { JSValue num1(r1.toNumber()); JSValue num2(r2.toNumber()); return JSValue(fmod(num1.f64, num2.f64)); } -static JSValue predecrement_Default(Context *cx, const JSValue& r) +static JSValue predecrement_Default(Context *, const JSValue& r) { JSValue num(r.toNumber()); return JSValue(num.f64 - 1.0); } -static JSValue preincrement_Default(Context *cx, const JSValue& r) +static JSValue preincrement_Default(Context *, const JSValue& r) { JSValue num(r.toNumber()); return JSValue(num.f64 + 1.0); } -static JSValue plus_Default(Context *cx, const JSValue& r) +static JSValue plus_Default(Context *, const JSValue& r) { return JSValue(r.toNumber()); } -static JSValue minus_Default(Context *cx, const JSValue& r) +static JSValue minus_Default(Context *, const JSValue& r) { JSValue num(r.toNumber()); return JSValue(-num.f64); } -static JSValue complement_Default(Context *cx, const JSValue& r) +static JSValue complement_Default(Context *, const JSValue& r) { JSValue num(r.toInt32()); return JSValue(~num.i32); @@ -392,7 +392,7 @@ static JSValue equal_Default(Context *cx, const JSValue& r1, const JSValue& r2) } return kFalseValue; } -static JSValue identical_Default(Context *cx, const JSValue& r1, const JSValue& r2) +static JSValue identical_Default(Context *, const JSValue& r1, const JSValue& r2) { if (r1.getType() != r2.getType()) return kFalseValue; @@ -971,7 +971,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (getter->isNative()) { JSValues argv(2); argv[0] = kNullValue; - argv[1] = getter; + argv[1] = getter; JSValue result = static_cast(getter)->mCode(this, argv); if (dst(ln).first != NotARegister) (*registers)[dst(ln).first] = result; diff --git a/mozilla/js2/src/lexer.cpp b/mozilla/js2/src/lexer.cpp index 03a44ea4edd..0e2f19cd961 100644 --- a/mozilla/js2/src/lexer.cpp +++ b/mozilla/js2/src/lexer.cpp @@ -1,56 +1,55 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include "numerics.h" #include "lexer.h" -namespace JavaScript -{ +namespace JS = JavaScript; + // Create a new Lexer for lexing the provided source code. The Lexer will // intern identifiers, keywords, and regular expressions in the designated // world. - Lexer::Lexer(World &world, const String &source, - const String &sourceLocation, uint32 initialLineNum): - world(world), reader(source, sourceLocation, initialLineNum) - { - nextToken = tokens; - nTokensFwd = 0; +JS::Lexer::Lexer(World &world, const String &source, const String &sourceLocation, uint32 initialLineNum): + world(world), reader(source, sourceLocation, initialLineNum) +{ + nextToken = tokens; + nTokensFwd = 0; #ifdef DEBUG - nTokensBack = 0; + nTokensBack = 0; #endif - lexingUnit = false; - } + lexingUnit = false; +} // Get and return the next token. The token remains valid until the next @@ -62,34 +61,32 @@ namespace JavaScript // If preferRegExp is true, a / will be preferentially interpreted as // starting a regular expression; otherwise, a / will be preferentially // interpreted as division or /=. - const Token - &Lexer::get(bool preferRegExp) - { - const Token &t = peek(preferRegExp); - if (++nextToken == tokens + tokenBufferSize) - nextToken = tokens; - --nTokensFwd; - DEBUG_ONLY(++nTokensBack); - return t; - } +const JS::Token &JS::Lexer::get(bool preferRegExp) +{ + const Token &t = peek(preferRegExp); + if (++nextToken == tokens + tokenBufferSize) + nextToken = tokens; + --nTokensFwd; + DEBUG_ONLY(++nTokensBack); + return t; +} // Peek at the next token using the given preferRegExp setting. If that // token's kind matches the given kind, consume that token and return it. // Otherwise, do not consume that token and return nil. - const Token * - Lexer::eat(bool preferRegExp, Token::Kind kind) - { - const Token &t = peek(preferRegExp); - if (t.kind != kind) - return 0; - if (++nextToken == tokens + tokenBufferSize) - nextToken = tokens; - --nTokensFwd; - DEBUG_ONLY(++nTokensBack); - return &t; - } - +const JS::Token *JS::Lexer::eat(bool preferRegExp, Token::Kind kind) +{ + const Token &t = peek(preferRegExp); + if (t.kind != kind) + return 0; + if (++nextToken == tokens + tokenBufferSize) + nextToken = tokens; + --nTokensFwd; + DEBUG_ONLY(++nTokensBack); + return &t; +} + // Return the next token without consuming it. // @@ -98,30 +95,29 @@ namespace JavaScript // interpreted as division or /=. A subsequent call to peek or get will // return the same token; that call must be presented with the same value // for preferRegExp. - const Token & - Lexer::peek(bool preferRegExp) - { - // Use an already looked-up token if there is one. - if (nTokensFwd) { - ASSERT(savedPreferRegExp[nextToken - tokens] == preferRegExp); - } else { - lexToken(preferRegExp); - nTokensFwd = 1; +const JS::Token &JS::Lexer::peek(bool preferRegExp) +{ + // Use an already looked-up token if there is one. + if (nTokensFwd) { + ASSERT(savedPreferRegExp[nextToken - tokens] == preferRegExp); + } else { + lexToken(preferRegExp); + nTokensFwd = 1; #ifdef DEBUG - savedPreferRegExp[nextToken - tokens] = preferRegExp; - if (nTokensBack == tokenLookahead) { - nTokensBack = tokenLookahead-1; - if (tokenGuard) - (nextToken >= tokens+tokenLookahead ? - nextToken-tokenLookahead : - nextToken+tokenBufferSize-tokenLookahead)->valid = false; - } -#endif + savedPreferRegExp[nextToken - tokens] = preferRegExp; + if (nTokensBack == tokenLookahead) { + nTokensBack = tokenLookahead-1; + if (tokenGuard) + (nextToken >= tokens+tokenLookahead ? + nextToken-tokenLookahead : + nextToken+tokenBufferSize-tokenLookahead)->valid = false; } - return *nextToken; +#endif } - - + return *nextToken; +} + + #ifdef DEBUG // Change the setting of preferRegExp for an already peeked token. // The token must not be one for which that setting mattered. @@ -129,597 +125,581 @@ namespace JavaScript // THIS IS A DANGEROUS FUNCTION! // Use it only if you can be prove that the already peeked token does not // start with a slash. - void - Lexer::redesignate(bool preferRegExp) - { - ASSERT(nTokensFwd); +void JS::Lexer::redesignate(bool preferRegExp) +{ + if (nTokensFwd) { ASSERT(savedPreferRegExp[nextToken - tokens] != preferRegExp); ASSERT(!(nextToken->hasKind(Token::regExp) || nextToken->hasKind(Token::divide) || nextToken->hasKind(Token::divideEquals))); savedPreferRegExp[nextToken - tokens] = preferRegExp; } +} #endif + // Unread the last token. This call may be called to unread at most // tokenBufferSize tokens at a time (where a peek also counts as temporarily // reading and unreading one token). When a token that has been unread is // peeked or read again, the same value must be passed in preferRegExp as for // the first time that token was read or peeked. - void - Lexer::unget() - { - ASSERT(nTokensBack--); - nTokensFwd++; - if (nextToken == tokens) - nextToken = tokens + tokenBufferSize; - --nextToken; - } +void JS::Lexer::unget() +{ + ASSERT(nTokensBack--); + nTokensFwd++; + if (nextToken == tokens) + nextToken = tokens + tokenBufferSize; + --nextToken; +} + // Report a syntax error at the backUp-th last character read by the Reader. // In other words, if backUp is 0, the error is at the next character to be // read by the Reader; if backUp is 1, the error is at the last character // read by the Reader, and so forth. - void - Lexer::syntaxError(const char *message, uint backUp) - { - reader.unget(backUp); - reader.error(Exception::syntaxError, widenCString(message), - reader.getPos()); - } +void JS::Lexer::syntaxError(const char *message, uint backUp) +{ + reader.unget(backUp); + reader.error(Exception::syntaxError, widenCString(message), reader.getPos()); +} + // Get the next character from the reader, skipping any Unicode format-control // (Cf) characters. - inline char16 - Lexer::getChar() - { - char16 ch = reader.get(); - if (char16Value(ch) >= firstFormatChar) - ch = internalGetChar(ch); - return ch; - } +inline char16 JS::Lexer::getChar() +{ + char16 ch = reader.get(); + if (char16Value(ch) >= firstFormatChar) + ch = internalGetChar(ch); + return ch; +} + // Helper for getChar() - char16 - Lexer::internalGetChar(char16 ch) - { - while (isFormat(ch)) - ch = reader.get(); - return ch; - } - +char16 JS::Lexer::internalGetChar(char16 ch) +{ + while (isFormat(ch)) + ch = reader.get(); + return ch; +} + // Peek the next character from the reader, skipping any Unicode // format-control (Cf) characters, which are read and discarded. - inline char16 - Lexer::peekChar() - { - char16 ch = reader.peek(); - if (char16Value(ch) >= firstFormatChar) - ch = internalPeekChar(ch); - return ch; - } +inline char16 JS::Lexer::peekChar() +{ + char16 ch = reader.peek(); + if (char16Value(ch) >= firstFormatChar) + ch = internalPeekChar(ch); + return ch; +} + // Helper for peekChar() - char16 - Lexer::internalPeekChar(char16 ch) - { - while (isFormat(ch)) { - reader.get(); - ch = reader.peek(); - } - return ch; +char16 JS::Lexer::internalPeekChar(char16 ch) +{ + while (isFormat(ch)) { + reader.get(); + ch = reader.peek(); } - + return ch; +} + + // Peek the next character from the reader, skipping any Unicode // format-control (Cf) characters, which are read and discarded. If the // peeked character matches ch, read that character and return true; // otherwise return false. ch must not be null. - bool - Lexer::testChar(char16 ch) - { - ASSERT(ch); // If ch were null, it could match the eof null. - char16 ch2 = peekChar(); - if (ch == ch2) { - reader.get(); - return true; - } - return false; +bool JS::Lexer::testChar(char16 ch) +{ + ASSERT(ch); // If ch were null, it could match the eof null. + char16 ch2 = peekChar(); + if (ch == ch2) { + reader.get(); + return true; } - + return false; +} + + // A backslash has been read. Read the rest of the escape code. // Return the interpreted escaped character. Throw an exception if the // escape is not valid. If unicodeOnly is true, allow only \uxxxx escapes. - char16 - Lexer::lexEscape(bool unicodeOnly) - { - char16 ch = getChar(); - int nDigits; - - if (!unicodeOnly || ch == 'u') - switch (ch) { - case '0': - // Make sure that the next character isn't a digit. - ch = peekChar(); - if (!isASCIIDecimalDigit(ch)) - return 0x00; - // Point to the next character in the error message - getChar(); - break; +char16 JS::Lexer::lexEscape(bool unicodeOnly) +{ + char16 ch = getChar(); + int nDigits; - case 'b': - return 0x08; - case 'f': - return 0x0C; - case 'n': - return 0x0A; - case 'r': - return 0x0D; - case 't': - return 0x09; - case 'v': - return 0x0B; - - case 'x': - nDigits = 2; - goto lexHex; - case 'u': - nDigits = 4; - lexHex: - { - uint32 n = 0; - while (nDigits--) { - ch = getChar(); - uint digit; - if (!isASCIIHexDigit(ch, digit)) - goto error; - n = (n << 4) | digit; - } - return static_cast(n); - } - default: - if (!reader.getEof(ch)) { - CharInfo chi(ch); - if (!isAlphanumeric(chi) && !isLineBreak(chi)) - return ch; - } + if (!unicodeOnly || ch == 'u') + switch (ch) { + case '0': + // Make sure that the next character isn't a digit. + ch = peekChar(); + if (!isASCIIDecimalDigit(ch)) + return 0x00; + // Point to the next character in the error message + getChar(); + break; + + case 'b': + return 0x08; + case 'f': + return 0x0C; + case 'n': + return 0x0A; + case 'r': + return 0x0D; + case 't': + return 0x09; + case 'v': + return 0x0B; + + case 'x': + nDigits = 2; + goto lexHex; + case 'u': + nDigits = 4; + lexHex: + { + uint32 n = 0; + while (nDigits--) { + ch = getChar(); + uint digit; + if (!isASCIIHexDigit(ch, digit)) + goto error; + n = (n << 4) | digit; + } + return static_cast(n); } - error: - syntaxError("Bad escape code"); - return 0; - } - - + default: + if (!reader.getEof(ch)) { + CharInfo chi(ch); + if (!isAlphanumeric(chi) && !isLineBreak(chi)) + return ch; + } + } + error: + syntaxError("Bad escape code"); + return 0; +} + + // Read an identifier into s. The initial value of s is ignored and cleared. // Return true if an escape code has been encountered. // If allowLeadingDigit is true, allow the first character of s to be a digit, // just like any continuing identifier character. - bool - Lexer::lexIdentifier(String &s, bool allowLeadingDigit) - { - reader.beginRecording(s); - bool hasEscape = false; - - while (true) { - char16 ch = getChar(); - char16 ch2 = ch; - if (ch == '\\') { - ch2 = lexEscape(true); - hasEscape = true; - } - CharInfo chi2(ch2); - - if (!(allowLeadingDigit ? isIdContinuing(chi2) : - isIdLeading(chi2))) { - if (ch == '\\') - syntaxError("Identifier escape expands into " - "non-identifier character"); - else - reader.unget(); - break; - } - reader.recordChar(ch2); - allowLeadingDigit = true; +bool JS::Lexer::lexIdentifier(String &s, bool allowLeadingDigit) +{ + reader.beginRecording(s); + bool hasEscape = false; + + while (true) { + char16 ch = getChar(); + char16 ch2 = ch; + if (ch == '\\') { + ch2 = lexEscape(true); + hasEscape = true; } - reader.endRecording(); - return hasEscape; + CharInfo chi2(ch2); + + if (!(allowLeadingDigit ? isIdContinuing(chi2) : + isIdLeading(chi2))) { + if (ch == '\\') + syntaxError("Identifier escape expands into non-identifier character"); + else + reader.unget(); + break; + } + reader.recordChar(ch2); + allowLeadingDigit = true; } - - + reader.endRecording(); + return hasEscape; +} + + // Read a numeric literal into nextToken->chars and nextToken->value. // Return true if the numeric literal is followed by a unit, but don't read // the unit yet. - bool - Lexer::lexNumeral() - { - int hasDecimalPoint = 0; - String &s = nextToken->chars; - uint digit; - - reader.beginRecording(s); - char16 ch = getChar(); - if (ch == '0') { - reader.recordChar('0'); - ch = getChar(); - if ((ch&~0x20) == 'X') { - uint32 pos = reader.getPos(); - char16 ch2 = getChar(); - if (isASCIIHexDigit(ch2, digit)) { - reader.recordChar(ch); - do { - reader.recordChar(ch2); - ch2 = getChar(); - } while (isASCIIHexDigit(ch2, digit)); - ch = ch2; - } else - reader.setPos(pos); - goto done; - } else if (isASCIIDecimalDigit(ch)) { - syntaxError("Numeric constant syntax error"); - } - } - while (isASCIIDecimalDigit(ch) || ch == '.' && !hasDecimalPoint++) { - reader.recordChar(ch); - ch = getChar(); - } - if ((ch&~0x20) == 'E') { +bool JS::Lexer::lexNumeral() +{ + int hasDecimalPoint = 0; + String &s = nextToken->chars; + uint digit; + + reader.beginRecording(s); + char16 ch = getChar(); + if (ch == '0') { + reader.recordChar('0'); + ch = getChar(); + if ((ch&~0x20) == 'X') { uint32 pos = reader.getPos(); char16 ch2 = getChar(); - char16 sign = 0; - if (ch2 == '+' || ch2 == '-') { - sign = ch2; - ch2 = getChar(); - } - if (isASCIIDecimalDigit(ch2)) { + if (isASCIIHexDigit(ch2, digit)) { reader.recordChar(ch); - if (sign) - reader.recordChar(sign); do { reader.recordChar(ch2); ch2 = getChar(); - } while (isASCIIDecimalDigit(ch2)); + } while (isASCIIHexDigit(ch2, digit)); ch = ch2; } else reader.setPos(pos); + goto done; + } else if (isASCIIDecimalDigit(ch)) { + syntaxError("Numeric constant syntax error"); } - - done: - // At this point the reader is just past the character ch, which - // is the first non-formatting character that is not part of the - // number. - reader.endRecording(); - const char16 *sBegin = s.data(); - const char16 *sEnd = sBegin + s.size(); - const char16 *numEnd; - nextToken->value = stringToDouble(sBegin, sEnd, numEnd); - ASSERT(numEnd == sEnd); - reader.unget(); - ASSERT(ch == reader.peek()); - return isIdContinuing(ch) || ch == '\\'; + } + while (isASCIIDecimalDigit(ch) || ch == '.' && !hasDecimalPoint++) { + reader.recordChar(ch); + ch = getChar(); + } + if ((ch&~0x20) == 'E') { + uint32 pos = reader.getPos(); + char16 ch2 = getChar(); + char16 sign = 0; + if (ch2 == '+' || ch2 == '-') { + sign = ch2; + ch2 = getChar(); + } + if (isASCIIDecimalDigit(ch2)) { + reader.recordChar(ch); + if (sign) + reader.recordChar(sign); + do { + reader.recordChar(ch2); + ch2 = getChar(); + } while (isASCIIDecimalDigit(ch2)); + ch = ch2; + } else + reader.setPos(pos); } - + done: + // At this point the reader is just past the character ch, which + // is the first non-formatting character that is not part of the + // number. + reader.endRecording(); + const char16 *sBegin = s.data(); + const char16 *sEnd = sBegin + s.size(); + const char16 *numEnd; + nextToken->value = stringToDouble(sBegin, sEnd, numEnd); + ASSERT(numEnd == sEnd); + reader.unget(); + ASSERT(ch == reader.peek()); + return isIdContinuing(ch) || ch == '\\'; +} + + // Read a string literal into s. The initial value of s is ignored and // cleared. The opening quote has already been read into separator. - void - Lexer::lexString(String &s, char16 separator) - { - char16 ch; - - reader.beginRecording(s); - while ((ch = reader.get()) != separator) { - CharInfo chi(ch); - if (!isFormat(chi)) { - if (ch == '\\') - ch = lexEscape(false); - else if (reader.getEof(ch) || isLineBreak(chi)) - syntaxError("Unterminated string literal"); - reader.recordChar(ch); - } +void JS::Lexer::lexString(String &s, char16 separator) +{ + char16 ch; + + reader.beginRecording(s); + while ((ch = reader.get()) != separator) { + CharInfo chi(ch); + if (!isFormat(chi)) { + if (ch == '\\') + ch = lexEscape(false); + else if (reader.getEof(ch) || isLineBreak(chi)) + syntaxError("Unterminated string literal"); + reader.recordChar(ch); } - reader.endRecording(); } - - + reader.endRecording(); +} + + // Read a regular expression literal. Store the regular expression in // nextToken->id and the flags in nextToken->chars. // The opening slash has already been read. - void Lexer::lexRegExp() - { - String s; - char16 prevCh = 0; - - reader.beginRecording(s); - while (true) { - char16 ch = getChar(); - CharInfo chi(ch); - if (reader.getEof(ch) || isLineBreak(chi)) - syntaxError("Unterminated regular expression literal"); - if (prevCh == '\\') { - reader.recordChar(ch); - // Ignore slashes and backslashes immediately after a backslash - prevCh = 0; - } else if (ch != '/') { - reader.recordChar(ch); - prevCh = ch; - } else - break; - } - reader.endRecording(); - nextToken->id = &world.identifiers[s]; - - lexIdentifier(nextToken->chars, true); +void JS::Lexer::lexRegExp() +{ + String s; + char16 prevCh = 0; + + reader.beginRecording(s); + while (true) { + char16 ch = getChar(); + CharInfo chi(ch); + if (reader.getEof(ch) || isLineBreak(chi)) + syntaxError("Unterminated regular expression literal"); + if (prevCh == '\\') { + reader.recordChar(ch); + // Ignore slashes and backslashes immediately after a backslash + prevCh = 0; + } else if (ch != '/') { + reader.recordChar(ch); + prevCh = ch; + } else + break; } - + reader.endRecording(); + nextToken->id = &world.identifiers[s]; + + lexIdentifier(nextToken->chars, true); +} + + // Read a token from the Reader and store it at *nextToken. // If the Reader reached the end of file, store a Token whose Kind is end. - void Lexer::lexToken(bool preferRegExp) - { - Token &t = *nextToken; - t.lineBreak = false; - t.id = 0; - // Don't really need to waste time clearing this string here - //clear(t.chars); - Token::Kind kind; - - if (lexingUnit) { - lexIdentifier(t.chars, false); - ASSERT(t.chars.size()); - kind = Token::unit; // unit - lexingUnit = false; +void JS::Lexer::lexToken(bool preferRegExp) +{ + Token &t = *nextToken; + t.lineBreak = false; + t.id = 0; + // Don't really need to waste time clearing this string here + //clear(t.chars); + Token::Kind kind; + + if (lexingUnit) { + lexIdentifier(t.chars, false); + ASSERT(t.chars.size()); + kind = Token::unit; // unit + lexingUnit = false; + } else { + next: + char16 ch = reader.get(); + if (reader.getEof(ch)) { + endOfInput: + t.pos = reader.getPos() - 1; + kind = Token::end; } else { - next: - char16 ch = reader.get(); - if (reader.getEof(ch)) { - endOfInput: + char16 ch2; + CharInfo chi(ch); + + switch (cGroup(chi)) { + case CharInfo::FormatGroup: + case CharInfo::WhiteGroup: + goto next; + + case CharInfo::IdGroup: t.pos = reader.getPos() - 1; - kind = Token::end; - } else { - char16 ch2; - CharInfo chi(ch); - - switch (cGroup(chi)) { - case CharInfo::FormatGroup: - case CharInfo::WhiteGroup: - goto next; - - case CharInfo::IdGroup: - t.pos = reader.getPos() - 1; - readIdentifier: - { - reader.unget(); - String s; - bool hasEscape = lexIdentifier(s, false); - t.id = &world.identifiers[s]; - kind = hasEscape ? Token::identifier : - t.id->tokenKind; - } - break; - - case CharInfo::NonIdGroup: - case CharInfo::IdContinueGroup: - t.pos = reader.getPos() - 1; - switch (ch) { - case '(': - kind = Token::openParenthesis; // ( - break; - case ')': - kind = Token::closeParenthesis; // ) - break; - case '[': - kind = Token::openBracket; // [ - break; - case ']': - kind = Token::closeBracket; // ] - break; - case '{': - kind = Token::openBrace; // { - break; - case '}': - kind = Token::closeBrace; // } - break; - case ',': - kind = Token::comma; // , - break; - case ';': - kind = Token::semicolon; // ; - break; - case '.': - kind = Token::dot; // . - ch2 = getChar(); - if (isASCIIDecimalDigit(ch2)) { - reader.setPos(t.pos); - goto number; // decimal point - } else if (ch2 == '.') { - kind = Token::doubleDot; // .. - if (testChar('.')) - kind = Token::tripleDot;// ... - } else - reader.unget(); - break; - case ':': - kind = Token::colon; // : - if (testChar(':')) - kind = Token::doubleColon; // :: - break; - case '#': - kind = Token::pound; // # - break; - case '@': - kind = Token::at; // @ - break; - case '?': - kind = Token::question; // ? - break; - - case '~': - kind = Token::complement; // ~ - break; - case '!': - kind = Token::logicalNot; // ! - if (testChar('=')) { - kind = Token::notEqual; // != - if (testChar('=')) - kind = Token::notIdentical; // !== - } - break; - - case '*': - kind = Token::times; // * *= - tryAssignment: - if (testChar('=')) - kind = Token::Kind(kind + - Token::timesEquals - - Token::times); - break; - - case '/': - kind = Token::divide; // / - ch = getChar(); - if (ch == '/') { // // comment - do { - ch = reader.get(); - if (reader.getEof(ch)) - goto endOfInput; - } while (!isLineBreak(ch)); - goto endOfLine; - } else if (ch == '*') { // /*comment*/ - ch = 0; - do { - ch2 = ch; - ch = getChar(); - if (isLineBreak(ch)) { - reader.beginLine(); - t.lineBreak = true; - } else if (reader.getEof(ch)) - syntaxError("Unterminated /* " - "comment"); - } while (ch != '/' || ch2 != '*'); - goto next; - } else { - reader.unget(); - if (preferRegExp) { // Regular expression - kind = Token::regExp; - lexRegExp(); - } else - goto tryAssignment; // /= - } - break; - - case '%': - kind = Token::modulo; // % - goto tryAssignment; // %= - - case '+': - kind = Token::plus; // + - if (testChar('+')) - kind = Token::increment; // ++ - else - goto tryAssignment; // += - break; - - case '-': - kind = Token::minus; // - - ch = getChar(); - if (ch == '-') - kind = Token::decrement; // -- - else if (ch == '>') - kind = Token::arrow; // -> - else { - reader.unget(); - goto tryAssignment; // -= - } - break; - - case '&': - kind = Token::bitwiseAnd; // & && &= &&= - logical: - if (testChar(ch)) - kind = Token::Kind(kind - - Token::bitwiseAnd + - Token::logicalAnd); - goto tryAssignment; - case '^': - kind = Token::bitwiseXor; // ^ ^^ ^= ^^= - goto logical; - case '|': - kind = Token::bitwiseOr; // | || |= ||= - goto logical; - - case '=': - kind = Token::assignment; // = - if (testChar('=')) { - kind = Token::equal; // == - if (testChar('=')) - kind = Token::identical; // === - } - break; - - case '<': - kind = Token::lessThan; // < - if (testChar('<')) { - kind = Token::leftShift; // << - goto tryAssignment; // <<= - } - comparison: - if (testChar('=')) // <= >= - kind = Token::Kind(kind + - Token::lessThanOrEqual - - Token::lessThan); - break; - case '>': - kind = Token::greaterThan; // > - if (testChar('>')) { - kind = Token::rightShift; // >> - if (testChar('>')) - kind = Token::logicalRightShift; // >>> - goto tryAssignment; // >>= >>>= - } - goto comparison; - - case '\\': - goto readIdentifier; // An identifier that - // starts with an escape - - case '\'': - case '"': - kind = Token::string; // 'string' "string" - lexString(t.chars, ch); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - reader.unget(); // Number - number: - kind = Token::number; - lexingUnit = lexNumeral(); - break; - - default: - syntaxError("Bad character"); - } - break; - - case CharInfo::LineBreakGroup: - endOfLine: - reader.beginLine(); - t.lineBreak = true; - goto next; + readIdentifier: + { + reader.unget(); + String s; + bool hasEscape = lexIdentifier(s, false); + t.id = &world.identifiers[s]; + kind = hasEscape ? Token::identifier : t.id->tokenKind; } + break; + + case CharInfo::NonIdGroup: + case CharInfo::IdContinueGroup: + t.pos = reader.getPos() - 1; + switch (ch) { + case '(': + kind = Token::openParenthesis; // ( + break; + case ')': + kind = Token::closeParenthesis; // ) + break; + case '[': + kind = Token::openBracket; // [ + break; + case ']': + kind = Token::closeBracket; // ] + break; + case '{': + kind = Token::openBrace; // { + break; + case '}': + kind = Token::closeBrace; // } + break; + case ',': + kind = Token::comma; // , + break; + case ';': + kind = Token::semicolon; // ; + break; + case '.': + kind = Token::dot; // . + ch2 = getChar(); + if (isASCIIDecimalDigit(ch2)) { + reader.setPos(t.pos); + goto number; // decimal point + } else if (ch2 == '.') { + kind = Token::doubleDot; // .. + if (testChar('.')) + kind = Token::tripleDot;// ... + } else + reader.unget(); + break; + case ':': + kind = Token::colon; // : + if (testChar(':')) + kind = Token::doubleColon; // :: + break; + case '#': + kind = Token::pound; // # + break; + case '@': + kind = Token::at; // @ + break; + case '?': + kind = Token::question; // ? + break; + + case '~': + kind = Token::complement; // ~ + break; + case '!': + kind = Token::logicalNot; // ! + if (testChar('=')) { + kind = Token::notEqual; // != + if (testChar('=')) + kind = Token::notIdentical; // !== + } + break; + + case '*': + kind = Token::times; // * *= + tryAssignment: + if (testChar('=')) + kind = Token::Kind(kind + Token::timesEquals - Token::times); + break; + + case '/': + kind = Token::divide; // / + ch = getChar(); + if (ch == '/') { // // comment + do { + ch = reader.get(); + if (reader.getEof(ch)) + goto endOfInput; + } while (!isLineBreak(ch)); + goto endOfLine; + } else if (ch == '*') { // /*comment*/ + ch = 0; + do { + ch2 = ch; + ch = getChar(); + if (isLineBreak(ch)) { + reader.beginLine(); + t.lineBreak = true; + } else if (reader.getEof(ch)) + syntaxError("Unterminated /* comment"); + } while (ch != '/' || ch2 != '*'); + goto next; + } else { + reader.unget(); + if (preferRegExp) { // Regular expression + kind = Token::regExp; + lexRegExp(); + } else + goto tryAssignment; // /= + } + break; + + case '%': + kind = Token::modulo; // % + goto tryAssignment; // %= + + case '+': + kind = Token::plus; // + + if (testChar('+')) + kind = Token::increment; // ++ + else + goto tryAssignment; // += + break; + + case '-': + kind = Token::minus; // - + ch = getChar(); + if (ch == '-') + kind = Token::decrement; // -- + else if (ch == '>') + kind = Token::arrow; // -> + else { + reader.unget(); + goto tryAssignment; // -= + } + break; + + case '&': + kind = Token::bitwiseAnd; // & && &= &&= + logical: + if (testChar(ch)) + kind = Token::Kind(kind - Token::bitwiseAnd + Token::logicalAnd); + goto tryAssignment; + case '^': + kind = Token::bitwiseXor; // ^ ^^ ^= ^^= + goto logical; + case '|': + kind = Token::bitwiseOr; // | || |= ||= + goto logical; + + case '=': + kind = Token::assignment; // = + if (testChar('=')) { + kind = Token::equal; // == + if (testChar('=')) + kind = Token::identical; // === + } + break; + + case '<': + kind = Token::lessThan; // < + if (testChar('<')) { + kind = Token::leftShift; // << + goto tryAssignment; // <<= + } + comparison: + if (testChar('=')) // <= >= + kind = Token::Kind(kind + Token::lessThanOrEqual - Token::lessThan); + break; + case '>': + kind = Token::greaterThan; // > + if (testChar('>')) { + kind = Token::rightShift; // >> + if (testChar('>')) + kind = Token::logicalRightShift; // >>> + goto tryAssignment; // >>= >>>= + } + goto comparison; + + case '\\': + goto readIdentifier; // An identifier that starts with an escape + + case '\'': + case '"': + kind = Token::string; // 'string' "string" + lexString(t.chars, ch); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + reader.unget(); // Number + number: + kind = Token::number; + lexingUnit = lexNumeral(); + break; + + default: + syntaxError("Bad character"); + } + break; + + case CharInfo::LineBreakGroup: + endOfLine: + reader.beginLine(); + t.lineBreak = true; + goto next; } } - t.kind = kind; -#ifdef DEBUG - t.valid = true; -#endif } - + t.kind = kind; +#ifdef DEBUG + t.valid = true; +#endif } diff --git a/mozilla/js2/src/lexer.h b/mozilla/js2/src/lexer.h index 83931748fca..171da41eb94 100644 --- a/mozilla/js2/src/lexer.h +++ b/mozilla/js2/src/lexer.h @@ -17,7 +17,7 @@ * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License (the "GPL"), in which case the @@ -40,56 +40,39 @@ #include "token.h" #include "world.h" -namespace JavaScript +namespace JavaScript { - class Lexer { - enum {tokenLookahead = 2}; // Number of tokens that can be - // simultaneously live + enum {tokenLookahead = 2}; // Number of tokens that can be simultaneously live #ifdef DEBUG - enum {tokenGuard = 10}; // Number of invalid tokens added to - // circular token buffer to catch - // references to old tokens + enum {tokenGuard = 10}; // Number of invalid tokens added to circular token buffer to catch references to old tokens #else - enum {tokenGuard = 0}; // Number of invalid tokens added to - // circular token buffer to catch - // references to old tokens + enum {tokenGuard = 0}; // Number of invalid tokens added to circular token buffer to catch references to old tokens #endif // Token lookahead buffer size enum {tokenBufferSize = tokenLookahead + tokenGuard}; - Token tokens[tokenBufferSize]; // Circular buffer of recently read or - // lookahead tokens - Token *nextToken; // Address of next Token in the - // circular buffer to be returned by - // get() - int nTokensFwd; // Net number of Tokens on which - // unget() has been called; these - // Tokens are ahead of nextToken + Token tokens[tokenBufferSize]; // Circular buffer of recently read or lookahead tokens + Token *nextToken; // Address of next Token in the circular buffer to be returned by get() + int nTokensFwd; // Net number of Tokens on which unget() has been called; these Tokens are ahead of nextToken #ifdef DEBUG - int nTokensBack; // Number of Tokens on which unget() - // can be called; these Tokens are - // beind nextToken - bool savedPreferRegExp[tokenBufferSize]; // Circular buffer of saved - // values of preferRegExp to - // get() calls + int nTokensBack; // Number of Tokens on which unget() can be called; these Tokens are beind nextToken + bool savedPreferRegExp[tokenBufferSize]; // Circular buffer of saved values of preferRegExp to get() calls #endif - bool lexingUnit; // True if lexing a unit identifier - // immediately following a number + bool lexingUnit; // True if lexing a unit identifier immediately following a number public: World &world; Reader reader; - Lexer(World &world, const String &source, const String &sourceLocation, - uint32 initialLineNum = 1); - + Lexer(World &world, const String &source, const String &sourceLocation, uint32 initialLineNum = 1); + const Token &get(bool preferRegExp); const Token *eat(bool preferRegExp, Token::Kind kind); const Token &peek(bool preferRegExp); void redesignate(bool preferRegExp); void unget(); uint32 getPos() const; - + private: void syntaxError(const char *message, uint backUp = 1); char16 getChar(); @@ -97,7 +80,7 @@ namespace JavaScript char16 peekChar(); char16 internalPeekChar(char16 ch); bool testChar(char16 ch); - + char16 lexEscape(bool unicodeOnly); bool lexIdentifier(String &s, bool allowLeadingDigit); bool lexNumeral(); @@ -106,20 +89,16 @@ namespace JavaScript void lexToken(bool preferRegExp); }; + #ifndef DEBUG - inline void Lexer::redesignate(bool) {} // See description for the DEBUG - // version inside parser.cpp + inline void Lexer::redesignate(bool) {} // See description for the DEBUG version inside lexer.cpp #endif - // Return the position of the first character of the next token, - // which must have been peeked. - inline uint32 - Lexer::getPos() const + // Return the position of the first character of the next token, which must have been peeked. + inline uint32 Lexer::getPos() const { ASSERT(nTokensFwd); return nextToken->getPos(); } - } - #endif /* lexer_h___ */ diff --git a/mozilla/js2/src/nodefactory.h b/mozilla/js2/src/nodefactory.h index cfb19cdb9a5..93efd0a48d7 100644 --- a/mozilla/js2/src/nodefactory.h +++ b/mozilla/js2/src/nodefactory.h @@ -60,10 +60,6 @@ namespace JavaScript { Identifier(const Token &t) { return new(getArena()) IdentifierExprNode(t); } - static IdentifierList * - ListedIdentifier(String &name) { - return new(getArena()) IdentifierList(*new StringAtom(name)); - } #if 0 static QualifiedIdentifierNode QualifiedIdentifier(Node qualifier, IdentifierNode identifier ) { diff --git a/mozilla/js2/src/parser.cpp b/mozilla/js2/src/parser.cpp index f78a57e9422..1685fd1e6d7 100644 --- a/mozilla/js2/src/parser.cpp +++ b/mozilla/js2/src/parser.cpp @@ -1,118 +1,128 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include "numerics.h" #include "parser.h" #include "nodefactory.h" +namespace JS = JavaScript; + + // // Parser // -namespace JavaScript -{ - NodeFactory *NodeFactory::state; +JS::NodeFactory *JS::NodeFactory::state; + // Create a new Parser for parsing the provided source code, interning // identifiers, keywords, and regular expressions in the designated world, // and allocating the parse tree in the designated arena. - Parser::Parser(World &world, Arena &arena, const String &source, - const String &sourceLocation, uint32 initialLineNum): - lexer(world, source, sourceLocation, initialLineNum), - arena(arena), lineBreaksSignificant(true) - { - NodeFactory::Init(arena); - } +JS::Parser::Parser(World &world, Arena &arena, const String &source, const String &sourceLocation, uint32 initialLineNum): + lexer(world, source, sourceLocation, initialLineNum), arena(arena), lineBreaksSignificant(true) +{ + NodeFactory::Init(arena); +} // Report a syntax error at the backUp-th last token read by the Lexer. // In other words, if backUp is 0, the error is at the next token to be read // by the Lexer (which must have been peeked already); if backUp is 1, the // error is at the last token read by the Lexer, and so forth. - void - Parser::syntaxError(const char *message, uint backUp) - { - syntaxError(widenCString(message), backUp); - } +void JS::Parser::syntaxError(const char *message, uint backUp) +{ + syntaxError(widenCString(message), backUp); +} + // Same as above, but the error message is already a String. - void - Parser::syntaxError(const String &message, uint backUp) - { - while (backUp--) - lexer.unget(); - getReader().error(Exception::syntaxError, message, lexer.getPos()); - } +void JS::Parser::syntaxError(const String &message, uint backUp) +{ + while (backUp--) + lexer.unget(); + getReader().error(Exception::syntaxError, message, lexer.getPos()); +} // Get the next token using the given preferRegExp setting. If that token's // kind matches the given kind, consume that token and return it. Otherwise // throw a syntax error. - const Token & - Parser::require(bool preferRegExp, Token::Kind kind) - { - const Token &t = lexer.get(preferRegExp); - if (!t.hasKind(kind)) { - String message; - bool special = Token::isSpecialKind(kind); - - if (special) - message += '\''; - message += Token::kindName(kind); - if (special) - message += '\''; - message += " expected"; - syntaxError(message); - } - return t; - } +const JS::Token &JS::Parser::require(bool preferRegExp, Token::Kind kind) +{ + const Token &t = lexer.get(preferRegExp); + if (!t.hasKind(kind)) { + String message; + bool special = Token::isSpecialKind(kind); + + if (special) + message += '\''; + message += Token::kindName(kind); + if (special) + message += '\''; + message += " expected"; + syntaxError(message); + } + return t; +} + // Copy the Token's chars into the current arena and return the resulting copy. - inline String & - Parser::copyTokenChars(const Token &t) - { - return newArenaString(arena, t.getChars()); - } +inline JS::String &JS::Parser::copyTokenChars(const Token &t) +{ + return newArenaString(arena, t.getChars()); +} + // If t is an Identifier, return a new IdentifierExprNode corresponding to t. // Otherwise, return null. - ExprNode * - Parser::makeIdentifierExpression(const Token &t) const - { - if (t.hasIdentifierKind()) - return new(arena) IdentifierExprNode(t); - return 0; - } +JS::ExprNode *JS::Parser::makeIdentifierExpression(const Token &t) const +{ + if (t.hasIdentifierKind()) + return new(arena) IdentifierExprNode(t); + return 0; +} + + +// Parse and return an Identifier. +JS::ExprNode *JS::Parser::parseIdentifier() +{ + const Token &t = lexer.get(true); + ExprNode *e = makeIdentifierExpression(t); + if (!e) + syntaxError("Identifier expected"); + return e; +} + // An identifier or parenthesized expression has just been parsed into e. // If it is followed by one or more ::'s followed by identifiers, construct @@ -120,870 +130,947 @@ namespace JavaScript // to true. If no :: is found, return e and set foundQualifiers to false. // After parseIdentifierQualifiers finishes, the next token might have been // peeked with the given preferRegExp setting. - ExprNode * - Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, - bool preferRegExp) - { - const Token *tDoubleColon = lexer.eat(preferRegExp, - Token::doubleColon); - if (!tDoubleColon) { - foundQualifiers = false; - return e; - } +JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp) +{ + const Token *tDoubleColon = lexer.eat(preferRegExp, Token::doubleColon); + if (!tDoubleColon) { + foundQualifiers = false; + return e; + } + + foundQualifiers = true; + uint32 pos = tDoubleColon->getPos(); + return new(arena) BinaryExprNode(pos, ExprNode::qualify, e, parseIdentifier()); +} - foundQualifiers = true; - checkStackSize(); - uint32 pos = tDoubleColon->getPos(); - return new(arena) BinaryExprNode(pos, ExprNode::qualify, e, - parseQualifiedIdentifier(lexer.get(true), - preferRegExp)); - } // An opening parenthesis has just been parsed into tParen. Finish parsing a -// ParenthesizedExpression. -// If it is followed by one or more ::'s followed by identifiers, construct -// the appropriate qualify parse node and return it and set foundQualifiers to -// true. If no :: is found, return the ParenthesizedExpression and set -// foundQualifiers to false. After parseParenthesesAndIdentifierQualifiers -// finishes, the next token might have been peeked with the given preferRegExp -// setting. - ExprNode * - Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, - bool &foundQualifiers, - bool preferRegExp) - { - uint32 pos = tParen.getPos(); - ExprNode *e = new(arena) UnaryExprNode(pos, ExprNode::parentheses, - parseExpression(false)); - require(false, Token::closeParenthesis); - return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); - } +// ParenthesizedListExpression (or ParenthesizedExpression if noComma is true). +// If it is in fact a ParenthesizedExpression and is followed by a :: and an identifier, +// construct the appropriate qualify parse node, return it, set foundQualifiers to true. +// Otherwise return the ParenthesizedListExpression and set foundQualifiers to false. +// After parseParenthesesAndIdentifierQualifiers finishes, the next token might have been +// peeked with the given preferRegExp setting. +JS::ExprNode *JS::Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool noComma, bool &foundQualifiers, + bool preferRegExp) +{ + uint32 pos = tParen.getPos(); + ExprNode *inner = parseGeneralExpression(false, false, false, noComma); + ExprNode *e = new(arena) UnaryExprNode(pos, ExprNode::parentheses, inner); + require(false, Token::closeParenthesis); + if (inner->hasKind(ExprNode::comma)) { + foundQualifiers = false; + return e; + } + return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); +} -// Parse and return a qualifiedIdentifier. The first token has already been -// parsed and is in t. If the second token was peeked, it should be have been -// done with the given preferRegExp setting. After parseQualifiedIdentifier -// finishes, the next token might have been peeked with the given + +// Parse and return a qualifiedIdentifier. The first token has already been parsed and is in t. +// If the second token was peeked, it should be have been done with the given preferRegExp setting. +// After parseQualifiedIdentifier finishes, the next token might have been peeked with the given // preferRegExp setting. - ExprNode * - Parser::parseQualifiedIdentifier(const Token &t, bool preferRegExp) - { - bool foundQualifiers; - ExprNode *e = makeIdentifierExpression(t); - if (e) - return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); - if (t.hasKind(Token::openParenthesis)) { - e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, - preferRegExp); - goto checkQualifiers; - } - if (t.hasKind(Token::Super)) { - e = parseIdentifierQualifiers(new(arena) ExprNode(t.getPos(), - ExprNode::Super), - foundQualifiers, preferRegExp); - goto checkQualifiers; - } - if (t.hasKind(Token::Public) || t.hasKind(Token::Package) || - t.hasKind(Token::Private)) { - e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), - foundQualifiers, preferRegExp); - checkQualifiers: - if (!foundQualifiers) - syntaxError("'::' expected", 0); - return e; - } - syntaxError("Identifier or '(' expected"); - return 0; // Unreachable code here just to shut up compiler warnings - } +JS::ExprNode *JS::Parser::parseQualifiedIdentifier(const Token &t, bool preferRegExp) +{ + bool foundQualifiers; + ExprNode *e = makeIdentifierExpression(t); + if (e) + return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp); + if (t.hasKind(Token::openParenthesis)) { + e = parseParenthesesAndIdentifierQualifiers(t, true, foundQualifiers, preferRegExp); + goto checkQualifiers; + } + if (t.hasKind(Token::Public) || t.hasKind(Token::Private)) { + e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers, preferRegExp); + checkQualifiers: + if (!foundQualifiers) + syntaxError("'::' expected", 0); + return e; + } + syntaxError("Qualified identifier expected"); + return 0; // Unreachable code here just to shut up compiler warnings +} + // Parse and return an arrayLiteral. The opening bracket has already been // read into initialToken. - PairListExprNode * - Parser::parseArrayLiteral(const Token &initialToken) - { - uint32 initialPos = initialToken.getPos(); - NodeQueue elements; - - while (true) { - ExprNode *element = 0; - const Token &t = lexer.peek(true); - if (t.hasKind(Token::comma) || t.hasKind(Token::closeBracket)) - lexer.redesignate(false); // Safe: neither ',' - // nor '}' starts with a slash. - else - element = parseAssignmentExpression(false); - elements += new(arena) ExprPairList(0, element); +JS::PairListExprNode *JS::Parser::parseArrayLiteral(const Token &initialToken) +{ + uint32 initialPos = initialToken.getPos(); + NodeQueue elements; - const Token &tSeparator = lexer.get(false); - if (tSeparator.hasKind(Token::closeBracket)) - break; - if (!tSeparator.hasKind(Token::comma)) - syntaxError("',' expected"); - } - return new(arena) PairListExprNode(initialPos, ExprNode::arrayLiteral, - elements.first); - } + while (true) { + ExprNode *element = 0; + const Token &t = lexer.peek(true); + if (t.hasKind(Token::comma) || t.hasKind(Token::closeBracket)) + lexer.redesignate(false); // Safe: neither ',' nor '}' starts with a slash. + else + element = parseAssignmentExpression(false); + elements += new(arena) ExprPairList(0, element); + + const Token &tSeparator = lexer.get(false); + if (tSeparator.hasKind(Token::closeBracket)) + break; + if (!tSeparator.hasKind(Token::comma)) + syntaxError("',' expected"); + } + return new(arena) PairListExprNode(initialPos, ExprNode::arrayLiteral, elements.first); +} // Parse and return an objectLiteral. The opening brace has already been // read into initialToken. - PairListExprNode * - Parser::parseObjectLiteral(const Token &initialToken) - { - uint32 initialPos = initialToken.getPos(); - NodeQueue elements; - - if (!lexer.eat(true, Token::closeBrace)) - while (true) { - const Token &t = lexer.get(true); - ExprNode *field; - if (t.hasIdentifierKind() || - t.hasKind(Token::openParenthesis) || - t.hasKind(Token::Super) || t.hasKind(Token::Public) || - t.hasKind(Token::Package) || t.hasKind(Token::Private)) - field = parseQualifiedIdentifier(t, false); - else if (t.hasKind(Token::string)) { - field = NodeFactory::LiteralString(t.getPos(), - ExprNode::string, - copyTokenChars(t)); - } - else if (t.hasKind(Token::number)) - field = new(arena) NumberExprNode(t); - else { - syntaxError("Field name expected"); - // Unreachable code here just to shut up compiler warnings - field = 0; - } - require(false, Token::colon); - elements += NodeFactory::LiteralField(field, - parseAssignmentExpression(false)); +JS::PairListExprNode *JS::Parser::parseObjectLiteral(const Token &initialToken) +{ + uint32 initialPos = initialToken.getPos(); + NodeQueue elements; - const Token &tSeparator = lexer.get(false); - if (tSeparator.hasKind(Token::closeBrace)) - break; - if (!tSeparator.hasKind(Token::comma)) - syntaxError("',' expected"); - } - return new(arena) PairListExprNode(initialPos, - ExprNode::objectLiteral, - elements.first); + if (!lexer.eat(true, Token::closeBrace)) + while (true) { + const Token &t = lexer.get(true); + ExprNode *field = makeIdentifierExpression(t); + if (!field) { + if (t.hasKind(Token::string)) + field = NodeFactory::LiteralString(t.getPos(), ExprNode::string, copyTokenChars(t)); + else if (t.hasKind(Token::number)) + field = new(arena) NumberExprNode(t); + else if (t.hasKind(Token::openParenthesis)) { + field = parseAssignmentExpression(false); + require(false, Token::closeParenthesis); + } else + syntaxError("Field name expected"); + } + require(false, Token::colon); + elements += new(arena) ExprPairList(field, parseAssignmentExpression(false)); + + const Token &tSeparator = lexer.get(false); + if (tSeparator.hasKind(Token::closeBrace)) + break; + if (!tSeparator.hasKind(Token::comma)) + syntaxError("',' expected"); + } + return new(arena) PairListExprNode(initialPos, ExprNode::objectLiteral, elements.first); } -// Parse and return a PrimaryExpression. -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. After parsePrimaryExpression finishes, the next -// token might have been peeked with preferRegExp set to false. - ExprNode * - Parser::parsePrimaryExpression() - { - ExprNode *e; - ExprNode::Kind eKind; - - const Token &t = lexer.get(true); - switch (t.getKind()) { - case Token::Null: - eKind = ExprNode::Null; - goto makeExprNode; - - case Token::True: - eKind = ExprNode::True; - goto makeExprNode; - - case Token::False: - eKind = ExprNode::False; - goto makeExprNode; - - case Token::This: - eKind = ExprNode::This; - goto makeExprNode; - - case Token::Super: - eKind = ExprNode::Super; - if (lexer.peek(false).hasKind(Token::doubleColon)) - goto makeQualifiedIdentifierNode; - makeExprNode: - e = new(arena) ExprNode(t.getPos(), eKind); - break; - - case Token::Public: - if (lexer.peek(false).hasKind(Token::doubleColon)) - goto makeQualifiedIdentifierNode; - e = new(arena) IdentifierExprNode(t); - break; - - case Token::number: - { - const Token &tUnit = lexer.peek(false); - if (!lineBreakBefore(tUnit) && - (tUnit.hasKind(Token::unit) || - tUnit.hasKind(Token::string))) { - lexer.get(false); - e = new(arena) NumUnitExprNode(t.getPos(), - ExprNode::numUnit, - copyTokenChars(t), - t.getValue(), - copyTokenChars(tUnit)); - } else - e = new(arena) NumberExprNode(t); - } - break; - - case Token::string: - e = NodeFactory::LiteralString(t.getPos(), ExprNode::string, - copyTokenChars(t)); - break; - - case Token::regExp: - e = new(arena) RegExpExprNode(t.getPos(), ExprNode::regExp, - t.getIdentifier(), - copyTokenChars(t)); - break; - - case Token::Package: - case Token::Private: - case CASE_TOKEN_NONRESERVED: - makeQualifiedIdentifierNode: - e = parseQualifiedIdentifier(t, false); - break; - - case Token::openParenthesis: - { - bool foundQualifiers; - e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, - false); - if (!foundQualifiers) { - const Token &tUnit = lexer.peek(false); - if (!lineBreakBefore(tUnit) && - tUnit.hasKind(Token::string)) { - lexer.get(false); - e = new(arena) ExprUnitExprNode(t.getPos(), - ExprNode::exprUnit, e, - copyTokenChars(tUnit)); - } - } - } - break; - - case Token::openBracket: - e = parseArrayLiteral(t); - break; - - case Token::openBrace: - e = parseObjectLiteral(t); - break; - - case Token::Function: - { - FunctionExprNode *f = new(arena) FunctionExprNode(t.getPos()); - const Token &t2 = lexer.get(true); - f->function.prefix = FunctionName::normal; - if (!(f->function.name = makeIdentifierExpression(t2))) - lexer.unget(); - parseFunctionSignature(f->function); - f->function.body = parseBody(0); - e = f; - } - break; - - default: - syntaxError("Expression expected"); - // Unreachable code here just to shut up compiler warnings - e = 0; - } - - return e; - } - - -// Parse a . or @ followed by a QualifiedIdentifier or ParenthesizedExpression -// and return the resulting BinaryExprNode. Use kind if a QualifiedIdentifier -// was found or parenKind if a ParenthesizedExpression was found. -// tOperator is the . or @ token. target is the first operand. - BinaryExprNode * - Parser::parseMember(ExprNode *target, const Token &tOperator, - ExprNode::Kind kind, ExprNode::Kind parenKind) - { - uint32 pos = tOperator.getPos(); - ExprNode *member; - const Token &t2 = lexer.get(true); - if (t2.hasKind(Token::openParenthesis)) { - bool foundQualifiers; - member = parseParenthesesAndIdentifierQualifiers(t2, - foundQualifiers, - false); - if (!foundQualifiers) - kind = parenKind; - } else - member = parseQualifiedIdentifier(t2, false); - return new(arena) BinaryExprNode(pos, kind, target, member); - } - -// Parse an ArgumentsList followed by a closing parenthesis or bracket and -// return the resulting InvokeExprNode. The target function, indexed object, -// or created class is supplied. The opening parenthesis or bracket has -// already been read. -// pos is the position to use for the InvokeExprNode. - InvokeExprNode * - Parser::parseInvoke(ExprNode *target, uint32 pos, - Token::Kind closingTokenKind, - ExprNode::Kind invokeKind) - { - NodeQueue arguments; - -#ifdef NEW_PARSER - parseArgumentList(arguments); - match(closingTokenKind); -#else - bool hasNamedArgument = false; +// e is a UnitExpression or a ParenthesizedListExpression. If it is followed by one or more +// string literals on the same line, construct and return the appropriate outer UnitExpression; +// otherwise return e. After parseUnitSuffixes finishes, the next token might have been peeked +// with preferRegExp set to false. +JS::ExprNode *JS::Parser::parseUnitSuffixes(ExprNode *e) +{ + while (true) { + const Token &t = lexer.peek(false); + if (lineBreakBefore(t) || !t.hasKind(Token::string)) + return e; + lexer.get(false); + e = new(arena) ExprUnitExprNode(t.getPos(), ExprNode::exprUnit, e, copyTokenChars(t)); + } +} - if (!lexer.eat(true, closingTokenKind)) - while (true) { - ExprNode *field = 0; - ExprNode *value = parseAssignmentExpression(false); - if (lexer.eat(false, Token::colon)) { - field = value; - if (!ExprNode::isFieldKind(field->getKind())) - syntaxError("Argument name must be an identifier, " - "string, or number"); - hasNamedArgument = true; - value = parseAssignmentExpression(false); - } else if (hasNamedArgument) - syntaxError("Unnamed argument cannot follow named " - "argument", 0); - arguments += new(arena) ExprPairList(field, value); - - const Token &tSeparator = lexer.get(false); - if (tSeparator.hasKind(closingTokenKind)) - break; - if (!tSeparator.hasKind(Token::comma)) - syntaxError("',' expected"); - } -#endif - return new(arena) InvokeExprNode(pos, invokeKind, target, - arguments.first); - } -// Parse and return a PostfixExpression. +// A super token has just been read. If superState is ssExpr, parse a SuperExpression; +// if superState is ssStmt, parse either a SuperExpression or a SuperStatement, giving +// preference to SuperExpression. superState cannot be ssNone. pos is the position of +// the super token. +// After parseSuper finishes, the next token might have been peeked with preferRegExp +// set to false. +JS::ExprNode *JS::Parser::parseSuper(uint32 pos, SuperState superState) +{ + ASSERT(superState != ssNone); + ExprNode *e = 0; + + if (lexer.eat(false, Token::openParenthesis)) { + if (superState == ssExpr) { + e = parseAssignmentExpression(false); + require(false, Token::closeParenthesis); + } else { + InvokeExprNode *se = parseInvoke(0, pos, Token::closeParenthesis, ExprNode::superStmt); + // Simplify a one-anonymous-argument superStmt into a superExpr. + ExprPairList *pairs = se->pairs; + if (!pairs || pairs->next || pairs->field) + return se; + e = pairs->value; + } + } + return new(arena) SuperExprNode(pos, e); +} + + +// Parse and return a PrimaryExpression. If superState is ssExpr, also allow a SuperExpression; +// if superState is ssStmt, also allow a SuperExpression or a SuperStatement. +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parsePrimaryExpression finishes, the next token might have been peeked with preferRegExp +// set to false. +JS::ExprNode *JS::Parser::parsePrimaryExpression(SuperState superState) +{ + ExprNode *e; + ExprNode::Kind eKind; + + const Token &t = lexer.get(true); + switch (t.getKind()) { + case Token::Null: + eKind = ExprNode::Null; + goto makeExprNode; + + case Token::True: + eKind = ExprNode::True; + goto makeExprNode; + + case Token::False: + eKind = ExprNode::False; + goto makeExprNode; + + case Token::This: + eKind = ExprNode::This; + makeExprNode: + e = new(arena) ExprNode(t.getPos(), eKind); + break; + + case Token::Public: + if (lexer.peek(false).hasKind(Token::doubleColon)) + goto makeQualifiedIdentifierNode; + e = new(arena) IdentifierExprNode(t); + break; + + case Token::number: + { + const Token &tUnit = lexer.peek(false); + if (!lineBreakBefore(tUnit) && + (tUnit.hasKind(Token::unit) || tUnit.hasKind(Token::string))) { + lexer.get(false); + e = parseUnitSuffixes(new(arena) NumUnitExprNode(t.getPos(), ExprNode::numUnit, copyTokenChars(t), + t.getValue(), copyTokenChars(tUnit))); + } else + e = new(arena) NumberExprNode(t); + } + break; + + case Token::string: + e = NodeFactory::LiteralString(t.getPos(), ExprNode::string, copyTokenChars(t)); + break; + + case Token::regExp: + e = new(arena) RegExpExprNode(t.getPos(), ExprNode::regExp, t.getIdentifier(), copyTokenChars(t)); + break; + + case Token::Private: + case CASE_TOKEN_NONRESERVED: + makeQualifiedIdentifierNode: + e = parseQualifiedIdentifier(t, false); + break; + + case Token::openParenthesis: + { + bool foundQualifiers; + e = parseParenthesesAndIdentifierQualifiers(t, false, foundQualifiers, false); + if (!foundQualifiers) + e = parseUnitSuffixes(e); + } + break; + + case Token::openBracket: + e = parseArrayLiteral(t); + break; + + case Token::openBrace: + e = parseObjectLiteral(t); + break; + + case Token::Function: + { + FunctionExprNode *f = new(arena) FunctionExprNode(t.getPos()); + const Token &t2 = lexer.get(true); + f->function.prefix = FunctionName::normal; + if (!(f->function.name = makeIdentifierExpression(t2))) + lexer.unget(); + parseFunctionSignature(f->function); + f->function.body = parseBody(0); + e = f; + } + break; + + case Token::Super: + if (superState != ssNone) { + e = parseSuper(t.getPos(), superState); + break; + } + // Fall through to a syntax error if super is not allowed. + default: + syntaxError("Expression expected"); + // Unreachable code here just to shut up compiler warnings + e = 0; + } + + return e; +} + + +// Parse a QualifiedIdentifier, ParenthesizedExpression, or 'class' following a dot +// and return the resulting ExprNode. +// tOperator is the . token. target is the first operand. If target is a superExpr then +// only a QualifiedIdentifier is allowed after the dot. +// After parseMember finishes, the next token might have been peeked with the given +// preferRegExp setting. +JS::ExprNode *JS::Parser::parseMember(ExprNode *target, const Token &tOperator, bool preferRegExp) +{ + uint32 pos = tOperator.getPos(); + const Token &t2 = lexer.get(true); + + if (t2.hasKind(Token::Class) && !target->hasKind(ExprNode::superExpr)) + return new(arena) UnaryExprNode(pos, ExprNode::dotClass, target); + + ExprNode *member; + ExprNode::Kind kind = ExprNode::dot; + if (t2.hasKind(Token::openParenthesis) && !target->hasKind(ExprNode::superExpr)) { + bool foundQualifiers; + member = parseParenthesesAndIdentifierQualifiers(t2, true, foundQualifiers, false); + if (!foundQualifiers) + kind = ExprNode::dotParen; + } else + member = parseQualifiedIdentifier(t2, preferRegExp); + return new(arena) BinaryExprNode(pos, kind, target, member); +} + + +// Parse an ArgumentsList followed by a closing parenthesis or bracket and return the resulting InvokeExprNode. +// The target function, indexed object, or created class is supplied. The opening parenthesis +// or bracket has already been read. pos is the position to use for the generated node. +JS::InvokeExprNode *JS::Parser::parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind) +{ + NodeQueue arguments; + bool hasNamedArgument = false; + + if (!lexer.eat(true, closingTokenKind)) + while (true) { + ExprNode *field = 0; + ExprNode *value = parseAssignmentExpression(false); + if (lexer.eat(false, Token::colon)) { + field = value; + if (!(field->hasKind(ExprNode::identifier) || + field->hasKind(ExprNode::number) || + field->hasKind(ExprNode::string) || + field->hasKind(ExprNode::parentheses) && !static_cast(field)->op->hasKind(ExprNode::comma))) + syntaxError("Argument name must be an identifier, string, number, or parenthesized expression"); + hasNamedArgument = true; + value = parseAssignmentExpression(false); + } else if (hasNamedArgument) + syntaxError("Unnamed argument cannot follow named argument", 0); + arguments += new(arena) ExprPairList(field, value); + + const Token &tSeparator = lexer.get(false); + if (tSeparator.hasKind(closingTokenKind)) + break; + if (!tSeparator.hasKind(Token::comma)) + syntaxError("',' expected"); + } + return new(arena) InvokeExprNode(pos, invokeKind, target, arguments.first); +} + + +// Given an alreaddy parsed PrimaryExpression, parse and return a PostfixExpression. +// If attribute is true, only allow AttributeExpression operators. +// If newExpression is true, the PrimaryExpression is immediately preceded by 'new', +// so don't allow call, postincrement, or postdecrement operators on it. +// If the first token was peeked, it should be have been done with preferRegExp set to +// the value of the attribute parameter. After parsePostfixOperator finishes, the next token +// might have been peeked with preferRegExp set to the value of the attribute parameter. +JS::ExprNode *JS::Parser::parsePostfixOperator(ExprNode *e, bool newExpression, bool attribute) +{ + while (true) { + ExprNode::Kind eKind; + const Token &t = lexer.get(attribute); + switch (t.getKind()) { + case Token::openParenthesis: + if (newExpression) + goto other; + e = parseInvoke(e, t.getPos(), Token::closeParenthesis, ExprNode::call); + break; + + case Token::openBracket: + e = parseInvoke(e, t.getPos(), Token::closeBracket, ExprNode::index); + break; + + case Token::dot: + e = parseMember(e, t, attribute); + break; + + case Token::increment: + eKind = ExprNode::postIncrement; + incDec: + if (newExpression || attribute || lineBreakBefore(t)) + goto other; + e = new(arena) UnaryExprNode(t.getPos(), eKind, e); + break; + + case Token::decrement: + eKind = ExprNode::postDecrement; + goto incDec; + + default: + other: + lexer.unget(); + return e; + } + } +} + + +// Parse and return a PostfixExpression. If superState is ssExpr, also allow a SuperExpression; +// if superState is ssStmt, also allow a SuperExpression or a SuperStatement. // If newExpression is true, this expression is immediately preceded by 'new', // so don't allow call, postincrement, or postdecrement operators on it. -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. After parsePostfixExpression finishes, the next -// token might have been peeked with preferRegExp set to false. - ExprNode * - Parser::parsePostfixExpression(bool newExpression) - { - ExprNode *e; - - const Token *tNew = lexer.eat(true, Token::New); - if (tNew) { - checkStackSize(); - uint32 posNew = tNew->getPos(); - e = parsePostfixExpression(true); - if (lexer.eat(false, Token::openParenthesis)) - e = parseInvoke(e, posNew, Token::closeParenthesis, - ExprNode::New); - else - e = new(arena) InvokeExprNode(posNew, ExprNode::New, e, 0); - } else - e = parsePrimaryExpression(); - - while (true) { - ExprNode::Kind eKind; - const Token &t = lexer.get(false); - switch (t.getKind()) { - case Token::openParenthesis: - if (newExpression) - goto other; - e = parseInvoke(e, t.getPos(), Token::closeParenthesis, - ExprNode::call); - break; - - case Token::openBracket: - e = parseInvoke(e, t.getPos(), Token::closeBracket, - ExprNode::index); - break; - - case Token::dot: - if (lexer.eat(true, Token::Class)) { - e = new(arena) UnaryExprNode(t.getPos(), - ExprNode::dotClass, e); - } else - e = parseMember(e, t, ExprNode::dot, - ExprNode::dotParen); - break; - - case Token::at: - e = parseMember(e, t, ExprNode::at, ExprNode::at); - break; - - case Token::increment: - eKind = ExprNode::postIncrement; - incDec: - if (newExpression || lineBreakBefore(t)) - goto other; - e = new(arena) UnaryExprNode(t.getPos(), eKind, e); - break; - - case Token::decrement: - eKind = ExprNode::postDecrement; - goto incDec; - - default: - other: - lexer.unget(); - return e; - } - } - } - -// Ensure that e is a postfix expression. If not, throw a syntax error on +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// +// After parsePostfixExpression finishes, the next token might have been peeked with preferRegExp +// set to false. +JS::ExprNode *JS::Parser::parsePostfixExpression(SuperState superState, bool newExpression) +{ + ExprNode *e; + + const Token *tNew = lexer.eat(true, Token::New); + if (tNew) { + checkStackSize(); + uint32 posNew = tNew->getPos(); + e = parsePostfixExpression(ssExpr, true); + if (lexer.eat(false, Token::openParenthesis)) + e = parseInvoke(e, posNew, Token::closeParenthesis, ExprNode::New); + else + e = new(arena) InvokeExprNode(posNew, ExprNode::New, e, 0); + } else { + e = parsePrimaryExpression(superState); + if (e->hasKind(ExprNode::superStmt)) { + ASSERT(superState == ssStmt); + return e; + } + } + + return parsePostfixOperator(e, newExpression, false); +} + + +// Ensure that e is a PostfixExpression. If not, throw a syntax error on // the current token. - void - Parser::ensurePostfix(const ExprNode *e) - { - ASSERT(e); - if (!e->isPostfix()) - syntaxError("Only a postfix expression can be used as the result " - "of an assignment; enclose this expression in " - "parentheses", 0); - } +void JS::Parser::ensurePostfix(const ExprNode *e) +{ + ASSERT(e); + if (!e->isPostfix()) + syntaxError("Only a postfix expression can be used as the target " + "of an assignment; enclose this expression in parentheses", 0); +} -// Parse and return a UnaryExpression. -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. -// After parseUnaryExpression finishes, the next token might have been peeked -// with preferRegExp set to false. - ExprNode * - Parser::parseUnaryExpression() - { - ExprNode::Kind eKind; - ExprNode *e; - const Token &t = lexer.peek(true); - uint32 pos = t.getPos(); - switch (t.getKind()) { - case Token::Delete: - eKind = ExprNode::Delete; - goto getPostfixExpression; - - case Token::increment: - eKind = ExprNode::preIncrement; - goto getPostfixExpression; - - case Token::decrement: - eKind = ExprNode::preDecrement; - getPostfixExpression: - lexer.get(true); - e = parsePostfixExpression(); - break; - - case Token::Typeof: - eKind = ExprNode::Typeof; - goto getUnaryExpression; - - case Token::Eval: - eKind = ExprNode::Eval; - goto getUnaryExpression; +// Parse and return an Attribute. The first token has already been read into t. +// +// After parseAttribute finishes, the next token might have been peeked with preferRegExp +// set to true. +JS::ExprNode *JS::Parser::parseAttribute(const Token &t) +{ + ExprNode::Kind eKind; - case Token::plus: - eKind = ExprNode::plus; - goto getUnaryExpression; - - case Token::minus: - eKind = ExprNode::minus; - goto getUnaryExpression; - - case Token::complement: - eKind = ExprNode::complement; - goto getUnaryExpression; - - case Token::logicalNot: - eKind = ExprNode::logicalNot; - getUnaryExpression: - lexer.get(true); - checkStackSize(); - e = parseUnaryExpression(); - break; - - default: - return parsePostfixExpression(); - } - return new(arena) UnaryExprNode(pos, eKind, e); - } - - - const Parser::BinaryOperatorInfo - Parser::tokenBinaryOperatorInfos[Token::kindsEnd] = { - - // Special + switch (t.getKind()) { + case Token::True: + eKind = ExprNode::True; + goto makeExprNode; - {ExprNode::none, pExpression, pNone}, // end - {ExprNode::none, pExpression, pNone}, // Token::number - {ExprNode::none, pExpression, pNone}, // Token::string - {ExprNode::none, pExpression, pNone}, // Token::unit - {ExprNode::none, pExpression, pNone}, // Token::regExp - - // Punctuators - - {ExprNode::none, pExpression, pNone}, // Token::openParenthesis - {ExprNode::none, pExpression, pNone}, // Token::closeParenthesis - {ExprNode::none, pExpression, pNone}, // Token::openBracket - {ExprNode::none, pExpression, pNone}, // Token::closeBracket - {ExprNode::none, pExpression, pNone}, // Token::openBrace - {ExprNode::none, pExpression, pNone}, // Token::closeBrace - {ExprNode::comma, pExpression, pExpression}, // Token::comma - {ExprNode::none, pExpression, pNone}, // Token::semicolon - {ExprNode::none, pExpression, pNone}, // Token::dot - {ExprNode::none, pExpression, pNone}, // Token::doubleDot - {ExprNode::none, pExpression, pNone}, // Token::tripleDot - {ExprNode::none, pExpression, pNone}, // Token::arrow - {ExprNode::none, pExpression, pNone}, // Token::colon - {ExprNode::none, pExpression, pNone}, // Token::doubleColon - {ExprNode::none, pExpression, pNone}, // Token::pound - {ExprNode::none, pExpression, pNone}, // Token::at - {ExprNode::none, pExpression, pNone}, // Token::increment - {ExprNode::none, pExpression, pNone}, // Token::decrement - {ExprNode::none, pExpression, pNone}, // Token::complement - {ExprNode::none, pExpression, pNone}, // Token::logicalNot - {ExprNode::multiply, pMultiplicative, pMultiplicative}, // Token::times - {ExprNode::divide, pMultiplicative, pMultiplicative}, // Token::divide - {ExprNode::modulo, pMultiplicative, pMultiplicative}, // Token::modulo - {ExprNode::add, pAdditive, pAdditive}, // Token::plus - {ExprNode::subtract, pAdditive, pAdditive}, // Token::minus - {ExprNode::leftShift, pShift, pShift}, // Token::leftShift - {ExprNode::rightShift, pShift, pShift}, // Token::rightShift - {ExprNode::logicalRightShift, pShift, pShift}, // Token::logicalRightShift - {ExprNode::logicalAnd, pBitwiseOr, pLogicalAnd}, // Token::logicalAnd (right-associative for efficiency) - {ExprNode::logicalXor, pLogicalAnd, pLogicalXor}, // Token::logicalXor (right-associative for efficiency) - {ExprNode::logicalOr, pLogicalXor, pLogicalOr}, // Token::logicalOr (right-associative for efficiency) - {ExprNode::bitwiseAnd, pBitwiseAnd, pBitwiseAnd}, // Token::bitwiseAnd - {ExprNode::bitwiseXor, pBitwiseXor, pBitwiseXor}, // Token::bitwiseXor - {ExprNode::bitwiseOr, pBitwiseOr, pBitwiseOr}, // Token::bitwiseOr - {ExprNode::assignment, pPostfix, pAssignment}, // Token::assignment - {ExprNode::multiplyEquals, pPostfix, pAssignment}, // Token::timesEquals - {ExprNode::divideEquals, pPostfix, pAssignment}, // Token::divideEquals - {ExprNode::moduloEquals, pPostfix, pAssignment}, // Token::moduloEquals - {ExprNode::addEquals, pPostfix, pAssignment}, // Token::plusEquals - {ExprNode::subtractEquals, pPostfix, pAssignment}, // Token::minusEquals - {ExprNode::leftShiftEquals, pPostfix, pAssignment}, // Token::leftShiftEquals - {ExprNode::rightShiftEquals, pPostfix, pAssignment}, // Token::rightShiftEquals - {ExprNode::logicalRightShiftEquals, pPostfix, pAssignment}, // Token::logicalRightShiftEquals - {ExprNode::logicalAndEquals, pPostfix, pAssignment}, // Token::logicalAndEquals - {ExprNode::logicalXorEquals, pPostfix, pAssignment}, // Token::logicalXorEquals - {ExprNode::logicalOrEquals, pPostfix, pAssignment}, // Token::logicalOrEquals - {ExprNode::bitwiseAndEquals, pPostfix, pAssignment}, // Token::bitwiseAndEquals - {ExprNode::bitwiseXorEquals, pPostfix, pAssignment}, // Token::bitwiseXorEquals - {ExprNode::bitwiseOrEquals, pPostfix, pAssignment}, // Token::bitwiseOrEquals - {ExprNode::equal, pEquality, pEquality}, // Token::equal - {ExprNode::notEqual, pEquality, pEquality}, // Token::notEqual - {ExprNode::lessThan, pRelational, pRelational}, // Token::lessThan - {ExprNode::lessThanOrEqual, pRelational, pRelational}, // Token::lessThanOrEqual - {ExprNode::greaterThan, pRelational, pRelational}, // Token::greaterThan - {ExprNode::greaterThanOrEqual, pRelational, pRelational}, // Token::greaterThanOrEqual - {ExprNode::identical, pEquality, pEquality}, // Token::identical - {ExprNode::notIdentical, pEquality, pEquality}, // Token::notIdentical - {ExprNode::conditional, pLogicalOr, pConditional}, // Token::question - - // Reserved words - {ExprNode::none, pExpression, pNone}, // Token::Abstract - {ExprNode::none, pExpression, pNone}, // Token::Break - {ExprNode::none, pExpression, pNone}, // Token::Case - {ExprNode::none, pExpression, pNone}, // Token::Catch - {ExprNode::none, pExpression, pNone}, // Token::Class - {ExprNode::none, pExpression, pNone}, // Token::Const - {ExprNode::none, pExpression, pNone}, // Token::Continue - {ExprNode::none, pExpression, pNone}, // Token::Debugger - {ExprNode::none, pExpression, pNone}, // Token::Default - {ExprNode::none, pExpression, pNone}, // Token::Delete - {ExprNode::none, pExpression, pNone}, // Token::Do - {ExprNode::none, pExpression, pNone}, // Token::Else - {ExprNode::none, pExpression, pNone}, // Token::Enum - {ExprNode::none, pExpression, pNone}, // Token::Export - {ExprNode::none, pExpression, pNone}, // Token::Extends - {ExprNode::none, pExpression, pNone}, // Token::False - {ExprNode::none, pExpression, pNone}, // Token::Final - {ExprNode::none, pExpression, pNone}, // Token::Finally - {ExprNode::none, pExpression, pNone}, // Token::For - {ExprNode::none, pExpression, pNone}, // Token::Function - {ExprNode::none, pExpression, pNone}, // Token::Goto - {ExprNode::none, pExpression, pNone}, // Token::If - {ExprNode::none, pExpression, pNone}, // Token::Implements - {ExprNode::none, pExpression, pNone}, // Token::Import - {ExprNode::In, pRelational, pRelational}, // Token::In - {ExprNode::Instanceof, pRelational, pRelational}, // Token::Instanceof - {ExprNode::none, pExpression, pNone}, // Token::Interface - {ExprNode::none, pExpression, pNone}, // Token::Namespace - {ExprNode::none, pExpression, pNone}, // Token::Native - {ExprNode::none, pExpression, pNone}, // Token::New - {ExprNode::none, pExpression, pNone}, // Token::Null - {ExprNode::none, pExpression, pNone}, // Token::Package - {ExprNode::none, pExpression, pNone}, // Token::Private - {ExprNode::none, pExpression, pNone}, // Token::Protected - {ExprNode::none, pExpression, pNone}, // Token::Public - {ExprNode::none, pExpression, pNone}, // Token::Return - {ExprNode::none, pExpression, pNone}, // Token::Static - {ExprNode::none, pExpression, pNone}, // Token::Super - {ExprNode::none, pExpression, pNone}, // Token::Switch - {ExprNode::none, pExpression, pNone}, // Token::Synchronized - {ExprNode::none, pExpression, pNone}, // Token::This - {ExprNode::none, pExpression, pNone}, // Token::Throw - {ExprNode::none, pExpression, pNone}, // Token::Throws - {ExprNode::none, pExpression, pNone}, // Token::Transient - {ExprNode::none, pExpression, pNone}, // Token::True - {ExprNode::none, pExpression, pNone}, // Token::Try - {ExprNode::none, pExpression, pNone}, // Token::Typeof - {ExprNode::none, pExpression, pNone}, // Token::Use - {ExprNode::none, pExpression, pNone}, // Token::Var - {ExprNode::none, pExpression, pNone}, // Token::Void - {ExprNode::none, pExpression, pNone}, // Token::Volatile - {ExprNode::none, pExpression, pNone}, // Token::While - {ExprNode::none, pExpression, pNone}, // Token::With - - // Non-reserved words - {ExprNode::none, pExpression, pNone}, // Token::Eval - {ExprNode::none, pExpression, pNone}, // Token::Exclude - {ExprNode::none, pExpression, pNone}, // Token::Get - {ExprNode::none, pExpression, pNone}, // Token::Include - {ExprNode::none, pExpression, pNone}, // Token::Set + case Token::False: + eKind = ExprNode::False; + makeExprNode: + return new(arena) ExprNode(t.getPos(), eKind); - {ExprNode::none, pExpression, pNone}, // Token::identifier + case Token::Public: + case Token::Private: + if (lexer.peek(true).hasKind(Token::doubleColon)) + break; + case Token::Abstract: + case Token::Final: + case Token::Static: + case Token::Volatile: + return new(arena) IdentifierExprNode(t); - }; + case CASE_TOKEN_NONRESERVED: + break; - struct Parser::StackedSubexpression { - ExprNode::Kind kind; // The kind of BinaryExprNode the subexpression - // should generate - uchar precedence; // Precedence of an operator with respect to - // operators on its right - uint32 pos; // The operator token's position - ExprNode *op1; // First operand of the operator - ExprNode *op2; // Second operand of the operator (used for ?: - // only) + default: + syntaxError("Attribute expected"); + } + + return parsePostfixOperator(parseQualifiedIdentifier(t, true), false, true); +} + + +// e is a parsed ListExpression or SuperStatement. Return true if e is also an Attribute. +bool JS::Parser::expressionIsAttribute(const ExprNode *e) +{ + while (true) + switch (e->getKind()) { + case ExprNode::identifier: + case ExprNode::True: + case ExprNode::False: + return true; + + case ExprNode::qualify: + return static_cast(e)->op1->hasKind(ExprNode::identifier); + + case ExprNode::call: + case ExprNode::index: + e = static_cast(e)->op; + break; + + case ExprNode::dot: + case ExprNode::dotParen: + e = static_cast(e)->op1; + break; + + case ExprNode::dotClass: + e = static_cast(e)->op; + break; + + default: + return false; + } +} + + +// Parse and return a UnaryExpression. If superState is ssExpr, also allow a SuperExpression; +// if superState is ssStmt, also allow a SuperExpression or a SuperStatement. +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// +// After parseUnaryExpression finishes, the next token might have been peeked with preferRegExp +// set to false. +JS::ExprNode *JS::Parser::parseUnaryExpression(SuperState superState) +{ + ExprNode::Kind eKind; + ExprNode *e; + + const Token &t = lexer.peek(true); + uint32 pos = t.getPos(); + switch (t.getKind()) { + case Token::Const: + eKind = ExprNode::Const; + goto getPostfixExpression; + + case Token::Delete: + eKind = ExprNode::Delete; + goto getPostfixExpression; + + case Token::increment: + eKind = ExprNode::preIncrement; + goto getPostfixExpression; + + case Token::decrement: + eKind = ExprNode::preDecrement; + getPostfixExpression: + lexer.get(true); + e = parsePostfixExpression(ssExpr, false); + break; + + case Token::Void: + eKind = ExprNode::Void; + goto getUnaryExpressionNotSuper; + + case Token::Typeof: + eKind = ExprNode::Typeof; + goto getUnaryExpressionNotSuper; + + case Token::plus: + eKind = ExprNode::plus; + goto getUnaryExpressionOrSuper; + + case Token::minus: + eKind = ExprNode::minus; + goto getUnaryExpressionOrSuper; + + case Token::complement: + eKind = ExprNode::complement; + getUnaryExpressionOrSuper: + superState = ssExpr; + goto getUnaryExpression; + + case Token::logicalNot: + eKind = ExprNode::logicalNot; + getUnaryExpressionNotSuper: + superState = ssNone; + getUnaryExpression: + lexer.get(true); + checkStackSize(); + e = parseUnaryExpression(superState); + break; + + default: + return parsePostfixExpression(superState, false); + } + return new(arena) UnaryExprNode(pos, eKind, e); +} + + +const JS::Parser::BinaryOperatorInfo JS::Parser::tokenBinaryOperatorInfos[Token::kindsEnd] = { + // Special + {ExprNode::none, pExpression, pNone, false}, // Token::end + {ExprNode::none, pExpression, pNone, false}, // Token::number + {ExprNode::none, pExpression, pNone, false}, // Token::string + {ExprNode::none, pExpression, pNone, false}, // Token::unit + {ExprNode::none, pExpression, pNone, false}, // Token::regExp + + // Punctuators + {ExprNode::none, pExpression, pNone, false}, // Token::openParenthesis + {ExprNode::none, pExpression, pNone, false}, // Token::closeParenthesis + {ExprNode::none, pExpression, pNone, false}, // Token::openBracket + {ExprNode::none, pExpression, pNone, false}, // Token::closeBracket + {ExprNode::none, pExpression, pNone, false}, // Token::openBrace + {ExprNode::none, pExpression, pNone, false}, // Token::closeBrace + {ExprNode::comma, pExpression, pExpression, false}, // Token::comma + {ExprNode::none, pExpression, pNone, false}, // Token::semicolon + {ExprNode::none, pExpression, pNone, false}, // Token::dot + {ExprNode::none, pExpression, pNone, false}, // Token::doubleDot + {ExprNode::none, pExpression, pNone, false}, // Token::tripleDot + {ExprNode::none, pExpression, pNone, false}, // Token::arrow + {ExprNode::none, pExpression, pNone, false}, // Token::colon + {ExprNode::none, pExpression, pNone, false}, // Token::doubleColon + {ExprNode::none, pExpression, pNone, false}, // Token::pound + {ExprNode::none, pExpression, pNone, false}, // Token::at + {ExprNode::none, pExpression, pNone, false}, // Token::increment + {ExprNode::none, pExpression, pNone, false}, // Token::decrement + {ExprNode::none, pExpression, pNone, false}, // Token::complement + {ExprNode::none, pExpression, pNone, false}, // Token::logicalNot + {ExprNode::multiply, pMultiplicative, pMultiplicative, true}, // Token::times + {ExprNode::divide, pMultiplicative, pMultiplicative, true}, // Token::divide + {ExprNode::modulo, pMultiplicative, pMultiplicative, true}, // Token::modulo + {ExprNode::add, pAdditive, pAdditive, true}, // Token::plus + {ExprNode::subtract, pAdditive, pAdditive, true}, // Token::minus + {ExprNode::leftShift, pShift, pShift, true}, // Token::leftShift + {ExprNode::rightShift, pShift, pShift, true}, // Token::rightShift + {ExprNode::logicalRightShift, pShift, pShift, true}, // Token::logicalRightShift + {ExprNode::logicalAnd, pBitwiseOr, pLogicalAnd, false}, // Token::logicalAnd (right-associative for efficiency) + {ExprNode::logicalXor, pLogicalAnd, pLogicalXor, false}, // Token::logicalXor (right-associative for efficiency) + {ExprNode::logicalOr, pLogicalXor, pLogicalOr, false}, // Token::logicalOr (right-associative for efficiency) + {ExprNode::bitwiseAnd, pBitwiseAnd, pBitwiseAnd, true}, // Token::bitwiseAnd + {ExprNode::bitwiseXor, pBitwiseXor, pBitwiseXor, true}, // Token::bitwiseXor + {ExprNode::bitwiseOr, pBitwiseOr, pBitwiseOr, true}, // Token::bitwiseOr + {ExprNode::assignment, pPostfix, pAssignment, false}, // Token::assignment + {ExprNode::multiplyEquals, pPostfix, pAssignment, true}, // Token::timesEquals + {ExprNode::divideEquals, pPostfix, pAssignment, true}, // Token::divideEquals + {ExprNode::moduloEquals, pPostfix, pAssignment, true}, // Token::moduloEquals + {ExprNode::addEquals, pPostfix, pAssignment, true}, // Token::plusEquals + {ExprNode::subtractEquals, pPostfix, pAssignment, true}, // Token::minusEquals + {ExprNode::leftShiftEquals, pPostfix, pAssignment, true}, // Token::leftShiftEquals + {ExprNode::rightShiftEquals, pPostfix, pAssignment, true}, // Token::rightShiftEquals + {ExprNode::logicalRightShiftEquals, pPostfix, pAssignment, true}, // Token::logicalRightShiftEquals + {ExprNode::logicalAndEquals, pPostfix, pAssignment, false}, // Token::logicalAndEquals + {ExprNode::logicalXorEquals, pPostfix, pAssignment, false}, // Token::logicalXorEquals + {ExprNode::logicalOrEquals, pPostfix, pAssignment, false}, // Token::logicalOrEquals + {ExprNode::bitwiseAndEquals, pPostfix, pAssignment, true}, // Token::bitwiseAndEquals + {ExprNode::bitwiseXorEquals, pPostfix, pAssignment, true}, // Token::bitwiseXorEquals + {ExprNode::bitwiseOrEquals, pPostfix, pAssignment, true}, // Token::bitwiseOrEquals + {ExprNode::equal, pEquality, pEquality, true}, // Token::equal + {ExprNode::notEqual, pEquality, pEquality, true}, // Token::notEqual + {ExprNode::lessThan, pRelational, pRelational, true}, // Token::lessThan + {ExprNode::lessThanOrEqual, pRelational, pRelational, true}, // Token::lessThanOrEqual + {ExprNode::greaterThan, pRelational, pRelational, true}, // Token::greaterThan + {ExprNode::greaterThanOrEqual, pRelational, pRelational, true}, // Token::greaterThanOrEqual + {ExprNode::identical, pEquality, pEquality, true}, // Token::identical + {ExprNode::notIdentical, pEquality, pEquality, true}, // Token::notIdentical + {ExprNode::conditional, pLogicalOr, pConditional, false}, // Token::question + + // Reserved words + {ExprNode::none, pExpression, pNone, false}, // Token::Abstract + {ExprNode::In, pRelational, pRelational, false}, // Token::As + {ExprNode::none, pExpression, pNone, false}, // Token::Break + {ExprNode::none, pExpression, pNone, false}, // Token::Case + {ExprNode::none, pExpression, pNone, false}, // Token::Catch + {ExprNode::none, pExpression, pNone, false}, // Token::Class + {ExprNode::none, pExpression, pNone, false}, // Token::Const + {ExprNode::none, pExpression, pNone, false}, // Token::Continue + {ExprNode::none, pExpression, pNone, false}, // Token::Debugger + {ExprNode::none, pExpression, pNone, false}, // Token::Default + {ExprNode::none, pExpression, pNone, false}, // Token::Delete + {ExprNode::none, pExpression, pNone, false}, // Token::Do + {ExprNode::none, pExpression, pNone, false}, // Token::Else + {ExprNode::none, pExpression, pNone, false}, // Token::Enum + {ExprNode::none, pExpression, pNone, false}, // Token::Export + {ExprNode::none, pExpression, pNone, false}, // Token::Extends + {ExprNode::none, pExpression, pNone, false}, // Token::False + {ExprNode::none, pExpression, pNone, false}, // Token::Final + {ExprNode::none, pExpression, pNone, false}, // Token::Finally + {ExprNode::none, pExpression, pNone, false}, // Token::For + {ExprNode::none, pExpression, pNone, false}, // Token::Function + {ExprNode::none, pExpression, pNone, false}, // Token::Goto + {ExprNode::none, pExpression, pNone, false}, // Token::If + {ExprNode::none, pExpression, pNone, false}, // Token::Implements + {ExprNode::none, pExpression, pNone, false}, // Token::Import + {ExprNode::In, pRelational, pRelational, false}, // Token::In + {ExprNode::Instanceof, pRelational, pRelational, false}, // Token::Instanceof + {ExprNode::none, pExpression, pNone, false}, // Token::Interface + {ExprNode::none, pExpression, pNone, false}, // Token::Namespace + {ExprNode::none, pExpression, pNone, false}, // Token::Native + {ExprNode::none, pExpression, pNone, false}, // Token::New + {ExprNode::none, pExpression, pNone, false}, // Token::Null + {ExprNode::none, pExpression, pNone, false}, // Token::Package + {ExprNode::none, pExpression, pNone, false}, // Token::Private + {ExprNode::none, pExpression, pNone, false}, // Token::Protected + {ExprNode::none, pExpression, pNone, false}, // Token::Public + {ExprNode::none, pExpression, pNone, false}, // Token::Return + {ExprNode::none, pExpression, pNone, false}, // Token::Static + {ExprNode::none, pExpression, pNone, false}, // Token::Super + {ExprNode::none, pExpression, pNone, false}, // Token::Switch + {ExprNode::none, pExpression, pNone, false}, // Token::Synchronized + {ExprNode::none, pExpression, pNone, false}, // Token::This + {ExprNode::none, pExpression, pNone, false}, // Token::Throw + {ExprNode::none, pExpression, pNone, false}, // Token::Throws + {ExprNode::none, pExpression, pNone, false}, // Token::Transient + {ExprNode::none, pExpression, pNone, false}, // Token::True + {ExprNode::none, pExpression, pNone, false}, // Token::Try + {ExprNode::none, pExpression, pNone, false}, // Token::Typeof + {ExprNode::none, pExpression, pNone, false}, // Token::Use + {ExprNode::none, pExpression, pNone, false}, // Token::Var + {ExprNode::none, pExpression, pNone, false}, // Token::Void + {ExprNode::none, pExpression, pNone, false}, // Token::Volatile + {ExprNode::none, pExpression, pNone, false}, // Token::While + {ExprNode::none, pExpression, pNone, false}, // Token::With + + // Non-reserved words + {ExprNode::none, pExpression, pNone, false}, // Token::Eval + {ExprNode::none, pExpression, pNone, false}, // Token::Exclude + {ExprNode::none, pExpression, pNone, false}, // Token::Get + {ExprNode::none, pExpression, pNone, false}, // Token::Include + {ExprNode::none, pExpression, pNone, false}, // Token::Set + + {ExprNode::none, pExpression, pNone, false} // Token::identifier }; -// Parse and return an Expression. If noIn is false, allow the in operator. -// If noAssignment is false, allow the = and op= operators. If noComma is -// false, allow the comma operator. If the first token was peeked, it should -// be have been done with preferRegExp set to true. -// After parseExpression finishes, the next token might have been peeked with -// preferRegExp set to false. - ExprNode * - Parser::parseExpression(bool noIn, bool noAssignment, bool noComma) - { - ArrayBuffer subexpressionStack; +struct JS::Parser::StackedSubexpression { + ExprNode::Kind kind; // The kind of BinaryExprNode the subexpression should generate + uchar precedence; // Precedence of an operator with respect to operators on its right + bool superRight; // True if the right operand can be super + uint32 pos; // The operator token's position + ExprNode *op1; // First operand of the operator + ExprNode *op2; // Second operand of the operator (used for ?: only) +}; - checkStackSize(); - // Push a limiter onto subexpressionStack. - subexpressionStack.reserve_advance_back()->precedence = pNone; - while (true) { - foundColon: - ExprNode *e = parseUnaryExpression(); - - const Token &t = lexer.peek(false); - const BinaryOperatorInfo &binOpInfo = - tokenBinaryOperatorInfos[t.getKind()]; - Precedence precedence = binOpInfo.precedenceLeft; - ExprNode::Kind kind = binOpInfo.kind; - ASSERT(precedence > pNone); - - // Disqualify assignments, 'in', and comma if the flags - // indicate that these should end the expression. - if (precedence == pPostfix && noAssignment || - kind == ExprNode::In && noIn || - kind == ExprNode::comma && noComma) { - kind = ExprNode::none; - precedence = pExpression; - } - - if (precedence == pPostfix) - ensurePostfix(e); // Ensure that the target of an assignment - // is a postfix subexpression. - else - // Reduce already stacked operators with precedenceLeft or - // higher precedence - while (subexpressionStack.back().precedence >= precedence) { - StackedSubexpression &s = subexpressionStack.pop_back(); - if (s.kind == ExprNode::conditional) { - if (s.op2) - e = new(arena) TernaryExprNode(s.pos, s.kind, - s.op1, s.op2, e); - else { - if (!t.hasKind(Token::colon)) - syntaxError("':' expected", 0); - lexer.get(false); - subexpressionStack.advance_back(); - s.op2 = e; - goto foundColon; - } - } else - e = new(arena) BinaryExprNode(s.pos, s.kind, s.op1, e); - } - - if (kind == ExprNode::none) { - ASSERT(subexpressionStack.size() == 1); - return e; - } - - // Push the current operator onto the subexpressionStack. - lexer.get(false); - StackedSubexpression &s = - *subexpressionStack.reserve_advance_back(); - s.kind = kind; - s.precedence = binOpInfo.precedenceRight; - s.pos = t.getPos(); - s.op1 = e; - s.op2 = 0; - } - } +// Parse and return a ListExpression. If allowSuperStmt is true, also allow the expression to be a +// SuperStatement. +// If noAssignment is false, allow the = and op= operators. If noComma is false, allow the comma +// operator. If the first token was peeked, it should have been done with preferRegExp set to true. +// +// After parseGeneralExpression finishes, the next token might have been peeked with preferRegExp +// set to false. +JS::ExprNode *JS::Parser::parseGeneralExpression(bool allowSuperStmt, bool noIn, bool noAssignment, bool noComma) +{ + ArrayBuffer subexpressionStack; -// Parse an opening parenthesis, an Expression, and a closing parenthesis. -// Return the Expression. If the first token was peeked, it should be have + checkStackSize(); + // Push a limiter onto subexpressionStack. + subexpressionStack.reserve_advance_back()->precedence = pNone; + + ExprNode *e = parseUnaryExpression(allowSuperStmt ? ssStmt : ssExpr); + if (e->hasKind(ExprNode::superStmt)) { + ASSERT(allowSuperStmt); + return e; + } + while (true) { + const Token &t = lexer.peek(false); + const BinaryOperatorInfo &binOpInfo = tokenBinaryOperatorInfos[t.getKind()]; + Precedence precedence = binOpInfo.precedenceLeft; + ExprNode::Kind kind = binOpInfo.kind; + ASSERT(precedence > pNone); + + // Disqualify assignments, 'in', and comma if the flags indicate that these should end the expression. + if (precedence == pPostfix && noAssignment || kind == ExprNode::In && noIn || kind == ExprNode::comma && noComma) { + kind = ExprNode::none; + precedence = pExpression; + } + + if (precedence == pPostfix) { + // Ensure that the target of an assignment is a postfix subexpression or, where permitted, + // a super subexpression. + if (!(binOpInfo.superLeft && e->hasKind(ExprNode::superExpr))) + ensurePostfix(e); + } else + // Reduce already stacked operators with precedenceLeft or higher precedence + while (subexpressionStack.back().precedence >= precedence) { + StackedSubexpression &s = subexpressionStack.pop_back(); + if (e->hasKind(ExprNode::superExpr) && !s.superRight) + syntaxError("super expression not allowed here", 0); + if (s.kind == ExprNode::conditional) { + if (s.op2) + e = new(arena) TernaryExprNode(s.pos, s.kind, s.op1, s.op2, e); + else { + if (!t.hasKind(Token::colon)) + syntaxError("':' expected", 0); + lexer.get(false); + subexpressionStack.advance_back(); + s.op2 = e; + goto foundColon; + } + } else + e = new(arena) BinaryExprNode(s.pos, s.kind, s.op1, e); + } + + if (kind == ExprNode::none) + break; + + // Push the current operator onto the subexpressionStack. + lexer.get(false); + StackedSubexpression &s = *subexpressionStack.reserve_advance_back(); + bool superLeft = binOpInfo.superLeft; + if (e->hasKind(ExprNode::superExpr) && !superLeft) + syntaxError("super expression not allowed here", 1); + s.kind = kind; + s.precedence = binOpInfo.precedenceRight; + s.superRight = superLeft || s.kind == ExprNode::In; + s.pos = t.getPos(); + s.op1 = e; + s.op2 = 0; + foundColon: + e = parseUnaryExpression(ssExpr); + } + + ASSERT(subexpressionStack.size() == 1); + if (e->hasKind(ExprNode::superExpr)) + if (allowSuperStmt && static_cast(e)->op) { + // Convert the superExpr into a superStmt. + ExprPairList *arg = new(arena) ExprPairList(0, static_cast(e)->op); + e = new(arena) InvokeExprNode(e->pos, ExprNode::superStmt, 0, arg); + } else + syntaxError("super expression not allowed here", 0); + return e; +} + + +// Parse an opening parenthesis, a ListExpression, and a closing parenthesis. +// Return the ListExpression. If the first token was peeked, it should be have // been done with preferRegExp set to true. - ExprNode * - Parser::parseParenthesizedExpression() - { - require(true, Token::openParenthesis); - ExprNode *e = parseExpression(false); - require(false, Token::closeParenthesis); - return e; - } - - +JS::ExprNode *JS::Parser::parseParenthesizedListExpression() +{ + require(true, Token::openParenthesis); + ExprNode *e = parseListExpression(false); + require(false, Token::closeParenthesis); + return e; +} + + // Parse and return a TypeExpression. If noIn is false, allow the in operator. // -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. After parseTypeExpression finishes, the next -// token might have been peeked with preferRegExp set to true. - ExprNode * - Parser::parseTypeExpression(bool noIn) - { - ExprNode *type = parseNonAssignmentExpression(noIn); - if (lexer.peek(false).hasKind(Token::divideEquals)) - syntaxError("'/=' not allowed here", 0); - lexer.redesignate(true); // Safe: a '/' would have been interpreted - // as an operator, so it can't be the next - // token; - // a '/=' was outlawed by the check above. - return type; - } +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parseTypeExpression finishes, the next token might have been peeked with preferRegExp set to true. +JS::ExprNode *JS::Parser::parseTypeExpression(bool noIn) +{ + ExprNode *type = parseNonAssignmentExpression(noIn); + if (lexer.peek(false).hasKind(Token::divideEquals)) + syntaxError("'/=' not allowed here", 0); + lexer.redesignate(true); // Safe: a '/' would have been interpreted as an operator, so it can't be the next + // token; a '/=' was outlawed by the check above. + return type; +} // Parse a TypedIdentifier. Return the identifier's name. // If a type was provided, set type to it; otherwise, set type to nil. // After parseTypedIdentifier finishes, the next token might have been peeked // with preferRegExp set to false. - const StringAtom & - Parser::parseTypedIdentifier(ExprNode *&type) - { - const Token &t = lexer.get(true); - if (!t.hasIdentifierKind()) - syntaxError("Identifier expected"); - const StringAtom &name = t.getIdentifier(); +const JS::StringAtom &JS::Parser::parseTypedIdentifier(ExprNode *&type) +{ + const Token &t = lexer.get(true); + if (!t.hasIdentifierKind()) + syntaxError("Identifier expected"); + const StringAtom &name = t.getIdentifier(); + + type = 0; + if (lexer.eat(false, Token::colon)) + type = parseNonAssignmentExpression(false); + return name; +} - type = 0; - if (lexer.eat(false, Token::colon)) - type = parseNonAssignmentExpression(false); - return name; - } // If the next token has the given kind, eat it and parse and return the // following TypeExpression; otherwise return nil. // If noIn is false, allow the in operator. // -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. -// After parseTypeBinding finishes, the next token might have been peeked -// with preferRegExp set to true. - ExprNode * - Parser::parseTypeBinding(Token::Kind kind, bool noIn) - { - ExprNode *type = 0; - if (lexer.eat(true, kind)) - type = parseTypeExpression(noIn); - return type; - } +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parseTypeBinding finishes, the next token might have been peeked with preferRegExp set to true. +JS::ExprNode *JS::Parser::parseTypeBinding(Token::Kind kind, bool noIn) +{ + ExprNode *type = 0; + if (lexer.eat(true, kind)) + type = parseTypeExpression(noIn); + return type; +} + // If the next token has the given kind, eat it and parse and return the // following TypeExpressionList; otherwise return nil. // -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. -// After parseTypeListBinding finishes, the next token might have been peeked -// with preferRegExp set to true. - ExprList * - Parser::parseTypeListBinding(Token::Kind kind) - { - NodeQueue types; - if (lexer.eat(true, kind)) - do types += new(arena) ExprList(parseTypeExpression(false)); - while (lexer.eat(true, Token::comma)); - return types.first; - } +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parseTypeListBinding finishes, the next token might have been peeked with preferRegExp set to true. +JS::ExprList *JS::Parser::parseTypeListBinding(Token::Kind kind) +{ + NodeQueue types; + if (lexer.eat(true, kind)) + do types += new(arena) ExprList(parseTypeExpression(false)); + while (lexer.eat(true, Token::comma)); + return types.first; +} + // Parse and return a VariableBinding. // If noQualifiers is false, allow a QualifiedIdentifier as the variable name; // otherwise, restrict the variable name to be a simple Identifier. // If noIn is false, allow the in operator. // -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. -// After parseVariableBinding finishes, the next token might have been peeked -// with preferRegExp set to true. - VariableBinding * - Parser::parseVariableBinding(bool noQualifiers, bool noIn, bool constant) - { - const Token &t = lexer.get(true); - uint32 pos = t.getPos(); +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parseVariableBinding finishes, the next token might have been peeked with preferRegExp set to true. +// The reason preferRegExp is true is to correctly parse the following case of semicolon insertion: +// var a +// /regexp/ +JS::VariableBinding *JS::Parser::parseVariableBinding(bool noQualifiers, bool noIn, bool constant) +{ + const Token &t = lexer.get(true); + uint32 pos = t.getPos(); + + ExprNode *name; + if (noQualifiers) { + name = makeIdentifierExpression(t); + if (!name) + syntaxError("Identifier expected"); + } else + name = parseQualifiedIdentifier(t, true); + + ExprNode *type = parseTypeBinding(Token::colon, noIn); + + ExprNode *initializer = 0; + if (lexer.eat(true, Token::assignment)) { + initializer = parseAssignmentExpression(noIn); + lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so + // it can't be the next token. + } + + return new(arena) VariableBinding(pos, name, type, initializer, constant); +} - ExprNode *name; - if (noQualifiers) { - name = makeIdentifierExpression(t); - if (!name) - syntaxError("Identifier expected"); - } else - name = parseQualifiedIdentifier(t, true); - - ExprNode *type = parseTypeBinding(Token::colon, noIn); - - ExprNode *initializer = 0; - if (lexer.eat(true, Token::assignment)) { - initializer = parseAssignmentExpression(noIn); - lexer.redesignate(true); // Safe: a '/' or a '/=' would have - // been interpreted as an operator, so - // it can't be the next token. - } - - return new(arena) VariableBinding(pos, name, type, initializer, - constant); - } // Parse a FunctionName and initialize fn with the result. // -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. -// After parseFunctionName finishes, the next token might have been peeked -// with preferRegExp set to true. - void - Parser::parseFunctionName(FunctionName &fn) - { - fn.prefix = FunctionName::normal; - const Token *t = &lexer.get(true); - if (t->hasKind(Token::string)) { - fn.name = NodeFactory::LiteralString(t->getPos(),ExprNode::string,copyTokenChars(*t)); - } - else { - if (t->hasKind(Token::Get) || t->hasKind(Token::Set)) { - const Token *t2 = &lexer.peek(true); - if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowGet)) { - fn.prefix = t->hasKind(Token::Get) ? FunctionName::Get : - FunctionName::Set; - t = &lexer.get(true); - } - } - fn.name = parseQualifiedIdentifier(*t, true); - } - } +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parseFunctionName finishes, the next token might have been peeked with preferRegExp set to true. +void JS::Parser::parseFunctionName(FunctionName &fn) +{ + fn.prefix = FunctionName::normal; + const Token *t = &lexer.get(true); + if (t->hasKind(Token::string)) { + fn.name = NodeFactory::LiteralString(t->getPos(),ExprNode::string,copyTokenChars(*t)); + } + else { + if (t->hasKind(Token::Get) || t->hasKind(Token::Set)) { + const Token *t2 = &lexer.peek(true); + if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowGet)) { + fn.prefix = t->hasKind(Token::Get) ? FunctionName::Get : FunctionName::Set; + t = &lexer.get(true); + } + } + fn.name = parseQualifiedIdentifier(*t, true); + } +} // Parse a FunctionSignature and initialize fd with the result. @@ -992,301 +1079,255 @@ namespace JavaScript // preferRegExp set to true. // After parseFunctionSignature finishes, the next token might have been // peeked with preferRegExp set to true. - void - Parser::parseFunctionSignature(FunctionDefinition &fd) - { - require(true, Token::openParenthesis); - - NodeQueue parameters; - VariableBinding *optParameters = 0; - VariableBinding *namedParameters = 0; - VariableBinding *restParameter = 0; +void JS::Parser::parseFunctionSignature(FunctionDefinition &fd) +{ + require(true, Token::openParenthesis); + + NodeQueue parameters; + VariableBinding *optParameters = 0; + VariableBinding *namedParameters = 0; + VariableBinding *restParameter = 0; #ifdef NEW_PARSER - fd.optParameters = optParameters; - fd.namedParameters = namedParameters; - fd.restParameter = restParameter; + fd.optParameters = optParameters; + fd.namedParameters = namedParameters; + fd.restParameter = restParameter; #endif - if (!lexer.eat(true, Token::closeParenthesis)) { + if (!lexer.eat(true, Token::closeParenthesis)) { #ifdef NEW_PARSER - parseAllParameters(fd,parameters); - match(Token::closeParenthesis); + parseAllParameters(fd,parameters); + match(Token::closeParenthesis); #else - while (true) { - if (lexer.eat(true, Token::tripleDot)) { - const Token &t1 = lexer.peek(true); - if (t1.hasKind(Token::closeParenthesis)) - restParameter = new(arena) VariableBinding(t1.getPos(), - 0, 0, 0, - false); - else - restParameter = parseVariableBinding(true, false, - lexer.eat(true, - Token::Const)); - if (!optParameters) - optParameters = restParameter; - parameters += restParameter; - require(true, Token::closeParenthesis); - break; - } else { - VariableBinding *b = parseVariableBinding(true, false, - lexer.eat(true, - Token::Const)); - if (b->initializer) { - if (!optParameters) - optParameters = b; - } else - if (optParameters) - syntaxError("'=' expected", 0); - parameters += b; - const Token &t = lexer.get(true); - if (!t.hasKind(Token::comma)) - if (t.hasKind(Token::closeParenthesis)) - break; - else - syntaxError("',' or ')' expected"); - } - } + while (true) { + if (lexer.eat(true, Token::tripleDot)) { + const Token &t1 = lexer.peek(true); + if (t1.hasKind(Token::closeParenthesis)) + restParameter = new(arena) VariableBinding(t1.getPos(), 0, 0, 0, false); + else + restParameter = parseVariableBinding(true, false, lexer.eat(true, Token::Const)); + if (!optParameters) + optParameters = restParameter; + parameters += restParameter; + require(true, Token::closeParenthesis); + break; + } else { + VariableBinding *b = parseVariableBinding(true, false, lexer.eat(true, Token::Const)); + if (b->initializer) { + if (!optParameters) + optParameters = b; + } else + if (optParameters) + syntaxError("'=' expected", 0); + parameters += b; + const Token &t = lexer.get(true); + if (!t.hasKind(Token::comma)) + if (t.hasKind(Token::closeParenthesis)) + break; + else + syntaxError("',' or ')' expected"); + } + } #endif - } - fd.parameters = parameters.first; + } + fd.parameters = parameters.first; #ifndef NEW_PARSER - fd.optParameters = optParameters; - fd.restParameter = restParameter; - fd.resultType = parseTypeBinding(Token::colon, false); + fd.optParameters = optParameters; + fd.restParameter = restParameter; + fd.resultType = parseTypeBinding(Token::colon, false); #endif - fd.resultType = parseResultSignature(); - } - + fd.resultType = parseResultSignature(); +} + + // Parse a list of statements ending with a '}'. Return these statements as a // linked list threaded through the StmtNodes' next fields. The opening '{' -// has already been read. If noCloseBrace is true, an end-of-input terminates +// has already been read. If noCloseBrace is true, an end-of-input terminates // the block; the end-of-input token is not read. // If inSwitch is true, allow case : and default: statements. -// If noCloseBrace is true, after parseBlock finishes the next token might +// If noCloseBrace is true, after parseBlockContents finishes the next token might // have been peeked with preferRegExp set to true. - StmtNode * - Parser::parseBlock(bool inSwitch, bool noCloseBrace) - { - NodeQueue q; - SemicolonState semicolonState = semiNone; - - while (true) { - const Token *t = &lexer.peek(true); - if (t->hasKind(Token::semicolon) && semicolonState != semiNone) { - lexer.get(true); - semicolonState = semiNone; - t = &lexer.peek(true); - } - if (noCloseBrace) { - if (t->hasKind(Token::end)) - return q.first; - } else if (t->hasKind(Token::closeBrace)) { - lexer.get(true); - return q.first; - } - if (!(semicolonState == semiNone || - semicolonState == semiInsertable && lineBreakBefore(*t))) - syntaxError("';' expected", 0); - - StmtNode *s = parseStatement(!inSwitch, inSwitch, semicolonState); - if (inSwitch && !q.first && !s->hasKind(StmtNode::Case)) - syntaxError("First statement in a switch block must be " - "'case expr:' or 'default:'", 0); - q += s; - } - } - - -// Parse an optional block of statements beginning with a '{' and ending -// with a '}'. Return these statements as a BlockStmtNode. +JS::StmtNode *JS::Parser::parseBlockContents(bool inSwitch, bool noCloseBrace) +{ + NodeQueue q; + SemicolonState semicolonState = semiNone; + + while (true) { + const Token *t = &lexer.peek(true); + if (t->hasKind(Token::semicolon) && semicolonState != semiNone) { + lexer.get(true); + semicolonState = semiNone; + t = &lexer.peek(true); + } + if (noCloseBrace) { + if (t->hasKind(Token::end)) + return q.first; + } else if (t->hasKind(Token::closeBrace)) { + lexer.get(true); + return q.first; + } + if (!(semicolonState == semiNone || + semicolonState == semiInsertable && lineBreakBefore(*t))) + syntaxError("';' expected", 0); + + StmtNode *s = parseStatement(!inSwitch, inSwitch, semicolonState); + if (inSwitch && !q.first && !s->hasKind(StmtNode::Case)) + syntaxError("First statement in a switch block must be 'case expr:' or 'default:'", 0); + q += s; + } +} + + +// Parse an optional block of statements beginning with a '{' and ending with a '}'. +// Return these statements as a BlockStmtNode. // If semicolonState is nil, the block is required; otherwise, the block is // optional and if it is omitted, *semicolonState is set to semiInsertable. // -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. After parseBody finishes, the next token might -// have been peeked with preferRegExp set to true. - BlockStmtNode * - Parser::parseBody(SemicolonState *semicolonState) - { - const Token *tBrace = lexer.eat(true, Token::openBrace); - if (tBrace) { - uint32 pos = tBrace->getPos(); - return new(arena) BlockStmtNode(pos, StmtNode::block, 0, - parseBlock(false, false)); - } else { - if (!semicolonState) - syntaxError("'{' expected", 0); - *semicolonState = semiInsertable; - return 0; - } - } - +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parseBody finishes, the next token might have been peeked with preferRegExp set to true. +JS::BlockStmtNode *JS::Parser::parseBody(SemicolonState *semicolonState) +{ + const Token *tBrace = lexer.eat(true, Token::openBrace); + if (tBrace) { + uint32 pos = tBrace->getPos(); + return new(arena) BlockStmtNode(pos, StmtNode::block, 0, parseBlockContents(false, false)); + } else { + if (!semicolonState) + syntaxError("'{' expected", 0); + *semicolonState = semiInsertable; + return 0; + } +} + + // Parse and return a statement that takes zero or more initial attributes, // which have already been parsed. If noIn is false, allow the in operator. // -// If the statement ends with an optional semicolon, that semicolon is not -// parsed. Instead, parseAttributeStatement returns in semicolonState one of -// three values: -// semiNone: No semicolon is needed to close the statement -// semiNoninsertable: A NoninsertableSemicolon is needed to close the -// statement; a line break is not enough -// semiInsertable: A Semicolon is needed to close the statement; a -// line break is also sufficient -// -// pos is the position of the beginning of the statement (its first attribute -// if it has attributes). The first token of the statement has already been -// read and is provided in t. After parseAttributeStatement finishes, the next -// token might have been peeked with preferRegExp set to true. - StmtNode * - Parser::parseAttributeStatement(uint32 pos, IdentifierList *attributes, - const Token &t, bool noIn, - SemicolonState &semicolonState) - { - semicolonState = semiNone; - StmtNode::Kind sKind; - - switch (t.getKind()) { - case Token::openBrace: - return new(arena) BlockStmtNode(pos, StmtNode::block, - attributes, - parseBlock(false, false)); - - case Token::Const: - sKind = StmtNode::Const; - goto constOrVar; - case Token::Var: - sKind = StmtNode::Var; - constOrVar: - { - NodeQueue bindings; - - do bindings += parseVariableBinding(false, noIn, - sKind == StmtNode::Const); - while (lexer.eat(true, Token::comma)); - semicolonState = semiInsertable; - return new(arena) VariableStmtNode(pos, sKind, - attributes, - bindings.first); - } - - case Token::Function: - sKind = StmtNode::Function; - { - FunctionStmtNode *f = - new(arena) FunctionStmtNode(pos, sKind, attributes); - parseFunctionName(f->function); - parseFunctionSignature(f->function); - f->function.body = parseBody(&semicolonState); - return f; - } - - case Token::Interface: - sKind = StmtNode::Interface; - goto classOrInterface; - case Token::Class: - sKind = StmtNode::Class; - classOrInterface: - { - ExprNode *name = parseQualifiedIdentifier(lexer.get(true), - true); - ExprNode *superclass = 0; - if (sKind == StmtNode::Class) - superclass = parseTypeBinding(Token::Extends, false); - ExprList *superinterfaces = - parseTypeListBinding(sKind == StmtNode::Class ? - Token::Implements : - Token::Extends); - BlockStmtNode *body = - parseBody(superclass || superinterfaces ? - 0 : &semicolonState); - return new(arena) ClassStmtNode(pos, sKind, attributes, - name, superclass, - superinterfaces, body); - } - - case Token::Namespace: - { - const Token &t2 = lexer.get(false); - ExprNode *name; - if (lineBreakBefore(t2) || - !(name = makeIdentifierExpression(t2))) - syntaxError("Namespace name expected"); - ExprList *supernamespaces = - parseTypeListBinding(Token::Extends); - semicolonState = semiInsertable; - return new(arena) NamespaceStmtNode(pos, StmtNode::Namespace, - attributes, name, - supernamespaces); - } - - default: - syntaxError("Bad declaration"); - return 0; - } - } - - -// Parse and return a statement that takes zero or more initial attributes. -// semicolonState behaves as in parseAttributeStatement. -// -// as restricts the kinds of statements that are allowed after the attributes: -// asAny Any statements that takes attributes can follow -// asBlock Only a block can follow -// asConstVar Only a const or var declaration can follow, and the 'in' -// operator is not allowed at its top level +// If the statement ends with an optional semicolon, then that semicolon is not parsed. +// Instead, parseAttributeStatement returns in semicolonState one of three values: +// semiNone: No semicolon is needed to close the statement +// semiNoninsertable: A NoninsertableSemicolon is needed to close the +// statement; a line break is not enough +// semiInsertable: A Semicolon is needed to close the statement; a +// line break is also sufficient // +// pos is the position of the beginning of the statement (its first attribute if it has attributes). // The first token of the statement has already been read and is provided in t. -// If the second token was peeked, it should be have been done with -// preferRegExp set to false; the second token should have been peeked only -// if t is an attribute. -// After parseAttributesAndStatement finishes, the next token might have -// been peeked with preferRegExp set to true. - StmtNode * - Parser::parseAttributesAndStatement(const Token *t, AttributeStatement as, - SemicolonState &semicolonState) - { - uint32 pos = t->getPos(); - NodeQueue attributes; - while (t->getFlag(Token::isAttribute)) { - attributes += new(arena) IdentifierList(t->getIdentifier()); - t = &lexer.get(false); - if (lineBreakBefore(*t)) - syntaxError("Line break not allowed here"); - } - - switch (as) { - case asAny: - break; - - case asBlock: - if (!t->hasKind(Token::openBrace)) - syntaxError("'{' expected"); - break; - - case asConstVar: - if (!t->hasKind(Token::Const) && !t->hasKind(Token::Var)) - syntaxError("const or var expected"); - break; - } - return parseAttributeStatement(pos, attributes.first, *t, - as == asConstVar, semicolonState); - } - - -// Parse and return an AnnotatedBlock. - StmtNode * - Parser::parseAnnotatedBlock() - { - const Token &t = lexer.get(true); - SemicolonState semicolonState; +// After parseAttributeStatement finishes, the next token might have been peeked with +// preferRegExp set to true. +JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, ExprList *attributes, const Token &t, bool noIn, + SemicolonState &semicolonState) +{ + semicolonState = semiNone; + StmtNode::Kind sKind; - // If package is the first attribute then it must be the only - // attribute. - if (t.hasKind(Token::Package) && - !lexer.peek(false).hasKind(Token::openBrace)) - syntaxError("'{' expected", 0); - return parseAttributesAndStatement(&t, asBlock, semicolonState); - } + switch (t.getKind()) { + case Token::openBrace: + return new(arena) BlockStmtNode(pos, StmtNode::block, attributes, parseBlockContents(false, false)); + + case Token::Const: + sKind = StmtNode::Const; + goto constOrVar; + case Token::Var: + sKind = StmtNode::Var; + constOrVar: + { + NodeQueue bindings; + + do bindings += parseVariableBinding(false, noIn, sKind == StmtNode::Const); + while (lexer.eat(true, Token::comma)); + semicolonState = semiInsertable; + return new(arena) VariableStmtNode(pos, sKind, attributes, bindings.first); + } + + case Token::Function: + sKind = StmtNode::Function; + { + FunctionStmtNode *f = + new(arena) FunctionStmtNode(pos, sKind, attributes); + parseFunctionName(f->function); + parseFunctionSignature(f->function); + f->function.body = parseBody(&semicolonState); + return f; + } + + case Token::Interface: + sKind = StmtNode::Interface; + goto classOrInterface; + case Token::Class: + sKind = StmtNode::Class; + classOrInterface: + { + ExprNode *name = parseQualifiedIdentifier(lexer.get(true), true); + ExprNode *superclass = 0; + if (sKind == StmtNode::Class) + superclass = parseTypeBinding(Token::Extends, false); + ExprList *superinterfaces = + parseTypeListBinding(sKind == StmtNode::Class ? Token::Implements : Token::Extends); + BlockStmtNode *body = + parseBody(superclass || superinterfaces ? 0 : &semicolonState); + return new(arena) ClassStmtNode(pos, sKind, attributes, name, superclass, superinterfaces, body); + } + + case Token::Namespace: + { + const Token &t2 = lexer.get(false); + ExprNode *name; + if (lineBreakBefore(t2) || !(name = makeIdentifierExpression(t2))) + syntaxError("Namespace name expected"); + ExprList *supernamespaces = + parseTypeListBinding(Token::Extends); + semicolonState = semiInsertable; + return new(arena) NamespaceStmtNode(pos, StmtNode::Namespace, attributes, name, supernamespaces); + } + + default: + syntaxError("Bad declaration"); + return 0; + } +} + + +// Parse and return a statement that takes initial attributes. +// semicolonState behaves as in parseAttributeStatement. +// as restricts the kinds of statements that are allowed after the attributes: +// asAny Any statements that takes attributes can follow +// asBlock Only a block can follow +// asConstVar Only a const or var declaration can follow, and the 'in' +// operator is not allowed at its top level +// +// The first attribute has already been read and is provided in e. +// pos is the position of the first attribute. +// If the next token was peeked, it should be have been done with preferRegExp set to true. +// After parseAttributesAndStatement finishes, the next token might have been peeked with +// preferRegExp set to true. +JS::StmtNode *JS::Parser::parseAttributesAndStatement(uint32 pos, ExprNode *e, AttributeStatement as, SemicolonState &semicolonState) +{ + NodeQueue attributes; + while (true) { + attributes += new(arena) ExprList(e); + const Token &t = lexer.get(true); + if (lineBreakBefore(t)) + syntaxError("Line break not allowed here"); + + if (!t.getFlag(Token::isAttribute)) { + switch (as) { + case asAny: + break; + + case asBlock: // ***** This is dead code. + if (!t.hasKind(Token::openBrace)) + syntaxError("'{' expected"); + break; + + case asConstVar: + if (!t.hasKind(Token::Const) && !t.hasKind(Token::Var)) + syntaxError("const or var expected"); + break; + } + return parseAttributeStatement(pos, attributes.first, t, as == asConstVar, semicolonState); + } + e = parseAttribute(t); + } +} // Parse and return a ForStatement. The 'for' token has already been read; @@ -1296,1347 +1337,1166 @@ namespace JavaScript // // After parseFor finishes, the next token might have been peeked with // preferRegExp set to true. - StmtNode * - Parser::parseFor(uint32 pos, SemicolonState &semicolonState) - { - require(true, Token::openParenthesis); - const Token &t = lexer.get(true); - uint32 tPos = t.getPos(); - const Token *t2; - StmtNode *initializer = 0; - ExprNode *expr1 = 0; - ExprNode *expr2 = 0; - ExprNode *expr3 = 0; - StmtNode::Kind sKind = StmtNode::For; - - switch (t.getKind()) { - case Token::semicolon: - goto threeExpr; - - case Token::Const: - case Token::Var: - case Token::Final: - case Token::Static: - case Token::Volatile: - makeAttribute: - initializer = parseAttributesAndStatement(&t, asConstVar, - semicolonState); - break; - - case CASE_TOKEN_NONRESERVED: - case Token::Public: - case Token::Package: - case Token::Private: - t2 = &lexer.peek(false); - if (!lineBreakBefore(*t2) && - t2->getFlag(Token::canFollowAttribute)) - goto makeAttribute; - default: - lexer.unget(); - expr1 = parseExpression(true); - initializer = new(arena) ExprStmtNode(tPos, - StmtNode::expression, - expr1); - lexer.redesignate(true); // Safe: a '/' or a '/=' would have - // been interpreted as an operator, - // so it can't be the next token. - break; - } - - if (lexer.eat(true, Token::semicolon)) - threeExpr: { - if (!lexer.eat(true, Token::semicolon)) { - expr2 = parseExpression(false); - require(false, Token::semicolon); - } - if (lexer.peek(true).hasKind(Token::closeParenthesis)) - lexer.redesignate(false); // Safe: the token is ')'. - else - expr3 = parseExpression(false); - } - else if (lexer.eat(true, Token::In)) { - sKind = StmtNode::ForIn; - if (expr1) { - ASSERT(initializer->hasKind(StmtNode::expression)); - ensurePostfix(expr1); - } else { - ASSERT(initializer->hasKind(StmtNode::Const) || - initializer->hasKind(StmtNode::Var)); - const VariableBinding *bindings = - static_cast(initializer)->bindings; - if (!bindings || bindings->next) - syntaxError("Only one variable binding can be used in a " - "for-in statement", 0); - } - expr2 = parseExpression(false); - } - else - syntaxError("';' or 'in' expected", 0); - - require(false, Token::closeParenthesis); - return new(arena) ForStmtNode(pos, sKind, initializer, expr2, expr3, - parseStatement(false, false, - semicolonState)); - } - - +JS::StmtNode *JS::Parser::parseFor(uint32 pos, SemicolonState &semicolonState) +{ + require(true, Token::openParenthesis); + const Token &t = lexer.get(true); + uint32 tPos = t.getPos(); + StmtNode *initializer = 0; + ExprNode *expr1 = 0; + ExprNode *expr2 = 0; + ExprNode *expr3 = 0; + StmtNode::Kind sKind = StmtNode::For; + + switch (t.getKind()) { + case Token::semicolon: + goto threeExpr; + + case Token::Const: + case Token::Var: + initializer = parseAttributeStatement(tPos, 0, t, true, semicolonState); + break; + + case Token::Abstract: + case Token::Final: + case Token::Static: + case Token::Volatile: + expr1 = new(arena) IdentifierExprNode(t); + makeAttribute: + initializer = parseAttributesAndStatement(tPos, expr1, asConstVar, semicolonState); + expr1 = 0; + break; + + default: + lexer.unget(); + expr1 = parseListExpression(true); + lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, + // so it can't be the next token. + if (expressionIsAttribute(expr1)) { + const Token &t2 = lexer.peek(true); + if (!lineBreakBefore(t2) && t2.getFlag(Token::canFollowAttribute)) + goto makeAttribute; + } + initializer = new(arena) ExprStmtNode(tPos, StmtNode::expression, expr1); + break; + } + + if (lexer.eat(true, Token::semicolon)) + threeExpr: { + if (!lexer.eat(true, Token::semicolon)) { + expr2 = parseListExpression(false); + require(false, Token::semicolon); + } + if (lexer.peek(true).hasKind(Token::closeParenthesis)) + lexer.redesignate(false); // Safe: the token is ')'. + else + expr3 = parseListExpression(false); + } + else if (lexer.eat(true, Token::In)) { + sKind = StmtNode::ForIn; + if (expr1) { + ASSERT(initializer->hasKind(StmtNode::expression)); + ensurePostfix(expr1); + } else { + ASSERT(initializer->hasKind(StmtNode::Const) || initializer->hasKind(StmtNode::Var)); + const VariableBinding *bindings = static_cast(initializer)->bindings; + if (!bindings || bindings->next) + syntaxError("Only one variable binding can be used in a for-in statement", 0); + } + expr2 = parseListExpression(false); + } + else + syntaxError("';' or 'in' expected", 0); + + require(false, Token::closeParenthesis); + return new(arena) ForStmtNode(pos, sKind, initializer, expr2, expr3, parseStatement(false, false, semicolonState)); +} + + // Parse and return a TryStatement. The 'try' token has already been read; // its position is pos. After parseTry finishes, the next token might have // been peeked with preferRegExp set to true. - StmtNode * - Parser::parseTry(uint32 pos) - { - StmtNode *tryBlock = parseAnnotatedBlock(); - NodeQueue catches; - const Token *t; - - while ((t = lexer.eat(true, Token::Catch)) != 0) { - uint32 catchPos = t->getPos(); - require(true, Token::openParenthesis); - ExprNode *type; - const StringAtom &name = parseTypedIdentifier(type); - require(false, Token::closeParenthesis); - catches += new(arena) CatchClause(catchPos, name, type, - parseAnnotatedBlock()); - } - StmtNode *finally = 0; - if (lexer.eat(true, Token::Finally)) - finally = parseAnnotatedBlock(); - else if (!catches.first) - syntaxError("A try statement must be followed by at least one " - "catch or finally", 0); - - return new(arena) TryStmtNode(pos, tryBlock, catches.first, finally); - } - - -// Parse and return a TopStatement. If topLevel is false, allow only -// Statements. +JS::StmtNode *JS::Parser::parseTry(uint32 pos) +{ + StmtNode *tryBlock = parseBody(0); + NodeQueue catches; + const Token *t; + + while ((t = lexer.eat(true, Token::Catch)) != 0) { + uint32 catchPos = t->getPos(); + require(true, Token::openParenthesis); + ExprNode *type; + const StringAtom &name = parseTypedIdentifier(type); + require(false, Token::closeParenthesis); + catches += new(arena) CatchClause(catchPos, name, type, parseBody(0)); + } + StmtNode *finally = 0; + if (lexer.eat(true, Token::Finally)) + finally = parseBody(0); + else if (!catches.first) + syntaxError("A try statement must be followed by at least one catch or finally", 0); + + return new(arena) TryStmtNode(pos, tryBlock, catches.first, finally); +} + + +// Parse and return a Directive. If directive is false, allow only Statements. // If inSwitch is true, allow case : and default: statements. // // If the statement ends with an optional semicolon, that semicolon is not // parsed. // Instead, parseStatement returns in semicolonState one of three values: -// semiNone: No semicolon is needed to close the statement -// semiNoninsertable: A NoninsertableSemicolon is needed to close the -// statement; a line break is not enough -// semiInsertable: A Semicolon is needed to close the statement; a -// line break is also sufficient +// semiNone: No semicolon is needed to close the statement +// semiNoninsertable: A NoninsertableSemicolon is needed to close the +// statement; a line break is not enough +// semiInsertable: A Semicolon is needed to close the statement; a +// line break is also sufficient // -// If the first token was peeked, it should be have been done with -// preferRegExp set to true. -// After parseStatement finishes, the next token might have been peeked with -// preferRegExp set to true. - StmtNode * - Parser::parseStatement(bool /*topLevel*/, bool inSwitch, - SemicolonState &semicolonState) - { - StmtNode *s; - ExprNode *e = 0; - StmtNode::Kind sKind; - const Token &t = lexer.get(true); - const Token *t2; - uint32 pos = t.getPos(); - semicolonState = semiNone; +// If the first token was peeked, it should be have been done with preferRegExp set to true. +// After parseStatement finishes, the next token might have been peeked with preferRegExp set to true. +JS::StmtNode *JS::Parser::parseStatement(bool /*directive*/, bool inSwitch, SemicolonState &semicolonState) +{ + StmtNode *s; + ExprNode *e = 0; + StmtNode::Kind sKind; + const Token &t = lexer.get(true); + const Token *t2; + uint32 pos = t.getPos(); + semicolonState = semiNone; + + checkStackSize(); + switch (t.getKind()) { + case Token::semicolon: + s = new(arena) StmtNode(pos, StmtNode::empty); + break; + + case Token::openBrace: + case Token::Const: + case Token::Var: + case Token::Function: + case Token::Class: + case Token::Interface: + case Token::Namespace: + s = parseAttributeStatement(pos, 0, t, false, semicolonState); + break; + + case Token::If: + e = parseParenthesizedListExpression(); + s = parseStatementAndSemicolon(semicolonState); + if (lexer.eat(true, Token::Else)) + s = new(arena) BinaryStmtNode(pos, StmtNode::IfElse, e, s, parseStatement(false, false, semicolonState)); + else { + sKind = StmtNode::If; + goto makeUnary; + } + break; + + case Token::Switch: + e = parseParenthesizedListExpression(); + require(true, Token::openBrace); + s = new(arena) SwitchStmtNode(pos, e, parseBlockContents(true, false)); + break; + + case Token::Case: + if (!inSwitch) + goto notInSwitch; + e = parseListExpression(false); + makeSwitchCase: + require(false, Token::colon); + s = new(arena) ExprStmtNode(pos, StmtNode::Case, e); + break; + + case Token::Default: + if (inSwitch) + goto makeSwitchCase; + notInSwitch: + syntaxError("case and default may only be used inside a switch statement"); + break; + + case Token::Do: + { + SemicolonState semiState2; // Ignore semiState2. + s = parseStatementAndSemicolon(semiState2); + require(true, Token::While); + e = parseParenthesizedListExpression(); + sKind = StmtNode::DoWhile; + goto makeUnary; + } + break; + + case Token::With: + sKind = StmtNode::With; + goto makeWhileWith; + + case Token::While: + sKind = StmtNode::While; + makeWhileWith: + e = parseParenthesizedListExpression(); + s = parseStatement(false, false, semicolonState); + makeUnary: + s = new(arena) UnaryStmtNode(pos, sKind, e, s); + break; + + case Token::For: + s = parseFor(pos, semicolonState); + break; + + case Token::Continue: + sKind = StmtNode::Continue; + goto makeGo; + + case Token::Break: + sKind = StmtNode::Break; + makeGo: + { + const StringAtom *label = 0; + t2 = &lexer.peek(true); + if (t2->hasKind(Token::identifier) && !lineBreakBefore(*t2)) { + lexer.get(true); + label = &t2->getIdentifier(); + } + s = new(arena) GoStmtNode(pos, sKind, label); + } + goto insertableSemicolon; + + case Token::Return: + sKind = StmtNode::Return; + t2 = &lexer.peek(true); + if (lineBreakBefore(*t2) || t2->getFlag(Token::canFollowReturn)) + goto makeExprStmtNode; + makeExpressionNode: + e = parseListExpression(false); + // Safe: a '/' or a '/=' would have been interpreted as an + // operator, so it can't be the next token. + lexer.redesignate(true); + goto makeExprStmtNode; + + case Token::Throw: + sKind = StmtNode::Throw; + if (lineBreakBefore()) + syntaxError("throw cannot be followed by a line break", 0); + goto makeExpressionNode; + + case Token::Try: + s = parseTry(pos); + break; + + case Token::Debugger: + s = new(arena) DebuggerStmtNode(pos, StmtNode::Debugger); + break; + + case Token::Abstract: + case Token::Final: + case Token::Static: + case Token::Volatile: + e = new(arena) IdentifierExprNode(t); + makeAttribute: + s = parseAttributesAndStatement(pos, e, asAny, semicolonState); + break; + + case CASE_TOKEN_NONRESERVED: + t2 = &lexer.peek(false); + if (t2->hasKind(Token::colon)) { + lexer.get(false); + // Must do this now because parseStatement can invalidate t. + const StringAtom &name = t.getIdentifier(); + s = new(arena) LabelStmtNode(pos, name, parseStatement(false, false, semicolonState)); + break; + } + default: + lexer.unget(); + e = parseGeneralExpression(true, false, false, false); + // Safe: a '/' or a '/=' would have been interpreted as an + // operator, so it can't be the next token. + lexer.redesignate(true); + if (expressionIsAttribute(e)) { + t2 = &lexer.peek(true); + if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowAttribute)) + goto makeAttribute; + } + sKind = StmtNode::expression; + makeExprStmtNode: + s = new(arena) ExprStmtNode(pos, sKind, e); + insertableSemicolon: + semicolonState = semiInsertable; + break; + } + return s; +} + + +// Same as parseStatement but also swallow the following semicolon if one is present. +JS::StmtNode *JS::Parser::parseStatementAndSemicolon(SemicolonState &semicolonState) +{ + StmtNode *s = parseStatement(false, false, semicolonState); + if (semicolonState != semiNone && lexer.eat(true, Token::semicolon)) + semicolonState = semiNone; + return s; +} + - checkStackSize(); - switch (t.getKind()) { - case Token::semicolon: - s = new(arena) StmtNode(pos, StmtNode::empty); - break; - - case Token::Namespace: - t2 = &lexer.peek(false); - if (lineBreakBefore(*t2) || !t2->hasIdentifierKind()) - goto makeExpression; - case Token::openBrace: - case Token::Const: - case Token::Var: - case Token::Function: - case Token::Class: - case Token::Interface: - s = parseAttributeStatement(pos, 0, t, false, semicolonState); - break; - - case Token::If: - e = parseParenthesizedExpression(); - s = parseStatementAndSemicolon(semicolonState); - if (lexer.eat(true, Token::Else)) - s = new(arena) BinaryStmtNode(pos, StmtNode::IfElse, e, s, - parseStatement(false, false, - semicolonState)); - else { - sKind = StmtNode::If; - goto makeUnary; - } - break; - - case Token::Switch: - e = parseParenthesizedExpression(); - require(true, Token::openBrace); - s = new(arena) SwitchStmtNode(pos, e, parseBlock(true, false)); - break; - - case Token::Case: - if (!inSwitch) - goto notInSwitch; - e = parseExpression(false); - makeSwitchCase: - require(false, Token::colon); - s = new(arena) ExprStmtNode(pos, StmtNode::Case, e); - break; - - case Token::Default: - if (inSwitch) - goto makeSwitchCase; - notInSwitch: - syntaxError("case and default may only be used inside a " - "switch statement"); - break; - - case Token::Do: - { - SemicolonState semiState2; - // Ignore semiState2. - s = parseStatementAndSemicolon(semiState2); - require(true, Token::While); - e = parseParenthesizedExpression(); - sKind = StmtNode::DoWhile; - goto makeUnary; - } - break; - - case Token::With: - sKind = StmtNode::With; - goto makeWhileWith; - - case Token::While: - sKind = StmtNode::While; - makeWhileWith: - e = parseParenthesizedExpression(); - s = parseStatement(false, false, semicolonState); - makeUnary: - s = new(arena) UnaryStmtNode(pos, sKind, e, s); - break; - - case Token::For: - s = parseFor(pos, semicolonState); - break; - - case Token::Continue: - sKind = StmtNode::Continue; - goto makeGo; - - case Token::Break: - sKind = StmtNode::Break; - makeGo: - { - const StringAtom *label = 0; - t2 = &lexer.peek(true); - if (t2->hasKind(Token::identifier) && - !lineBreakBefore(*t2)) { - lexer.get(true); - label = &t2->getIdentifier(); - } - s = new(arena) GoStmtNode(pos, sKind, label); - } - goto insertableSemicolon; - - case Token::Return: - sKind = StmtNode::Return; - t2 = &lexer.peek(true); - if (lineBreakBefore(*t2) || - t2->getFlag(Token::canFollowReturn)) - goto makeExprStmtNode; - goto makeExpressionNode; - - case Token::Throw: - sKind = StmtNode::Throw; - if (lineBreakBefore()) - syntaxError("throw cannot be followed by a line break", 0); - goto makeExpressionNode; - - case Token::Try: - s = parseTry(pos); - break; - - case Token::Debugger: - s = new(arena) DebuggerStmtNode(pos, StmtNode::Debugger); - break; - - case Token::Final: - case Token::Static: - case Token::Volatile: - makeAttribute: - s = parseAttributesAndStatement(&t, asAny, semicolonState); - break; - - case Token::Public: - case Token::Package: - case Token::Private: - t2 = &lexer.peek(false); - goto makeExpressionOrAttribute; - - case CASE_TOKEN_NONRESERVED: - t2 = &lexer.peek(false); - if (t2->hasKind(Token::colon)) { - lexer.get(false); - // Must do this now because parseStatement can - // invalidate t. - const StringAtom &name = t.getIdentifier(); - s = new(arena) LabelStmtNode(pos, name, - parseStatement(false, false, - semicolonState)); - break; - } - makeExpressionOrAttribute: - if (!lineBreakBefore(*t2) && - t2->getFlag(Token::canFollowAttribute)) - goto makeAttribute; - default: - makeExpression: - lexer.unget(); - sKind = StmtNode::expression; - makeExpressionNode: - e = parseExpression(false); - // Safe: a '/' or a '/=' would have been interpreted as an - // operator, so it can't be the next token. - lexer.redesignate(true); - makeExprStmtNode: - s = new(arena) ExprStmtNode(pos, sKind, e); - insertableSemicolon: - semicolonState = semiInsertable; - break; - } - return s; - } - - -// Same as parseStatement but also swallow the following semicolon if one -// is present. - StmtNode * - Parser::parseStatementAndSemicolon(SemicolonState &semicolonState) - { - StmtNode *s = parseStatement(false, false, semicolonState); - if (semicolonState != semiNone && lexer.eat(true, Token::semicolon)) - semicolonState = semiNone; - return s; - } - // BEGIN NEW CODE - bool - Parser::lookahead(Token::Kind kind, bool preferRegExp) - { - const Token &t = lexer.peek(preferRegExp); - if (t.getKind() != kind) - return false; - return true; - } - - const Token * - Parser::match(Token::Kind kind, bool preferRegExp) - { - const Token *t = lexer.eat(preferRegExp,kind); - if (!t || t->getKind() != kind) - return 0; - return t; - } - -/** - * Identifier - * Identifier - * get - * set - */ - - ExprNode * - Parser::parseIdentifier() - { +bool JS::Parser::lookahead(Token::Kind kind, bool preferRegExp) +{ + const Token &t = lexer.peek(preferRegExp); + if (t.getKind() != kind) + return false; + return true; +} - ExprNode *result = NULL; - - if(lookahead(Token::Get)) { - result = NodeFactory::Identifier(*match(Token::Get)); - } else if(lookahead(Token::Set)) { - result = NodeFactory::Identifier(*match(Token::Set)); - } else if(lookahead(Token::identifier)) { - result = NodeFactory::Identifier(*match(Token::identifier)); - } else { - // throw new Exception("Expecting an Identifier when encountering " - // "input: " + scanner.getErrorText()); - } - - return result; - } - -/** - * LiteralField - * FieldName : AssignmentExpressionallowIn - */ +const JS::Token *JS::Parser::match(Token::Kind kind, bool preferRegExp) +{ + const Token *t = lexer.eat(preferRegExp,kind); + if (!t || t->getKind() != kind) + return 0; + return t; +} - ExprPairList * - Parser::parseLiteralField() - { - - ExprPairList *result=NULL; - ExprNode *first; - ExprNode *second; - - first = parseFieldName(); - match(Token::colon); - second = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash punctuation. - result = NodeFactory::LiteralField(first,second); - - return result; - } /** - * FieldName - * Identifier - * String - * Number - * ParenthesizedExpression - */ +* LiteralField +* FieldName : AssignmentExpressionallowIn +*/ - ExprNode * - Parser::parseFieldName() - { +JS::ExprPairList *JS::Parser::parseLiteralField() +{ - ExprNode *result; + ExprPairList *result=NULL; + ExprNode *first; + ExprNode *second; - if( lookahead(Token::string) ) { - const Token *t = match(Token::string); - result = NodeFactory::LiteralString(t->getPos(), ExprNode::string, - copyTokenChars(*t)); - } else if(lookahead(Token::number)) { - const Token *t = match(Token::number); - result = NodeFactory::LiteralNumber(*t); - } else if( lookahead(Token::openParenthesis) ) { - result = parseParenthesizedExpression(); - } else { - result = parseIdentifier(); - } - - return result; - } + first = parseFieldName(); + match(Token::colon); + second = parseAssignmentExpression(false); + lexer.redesignate(true); // Safe: looking for non-slash punctuation. + result = NodeFactory::LiteralField(first,second); + + return result; +} /** - * ArgumentList - * - * LiteralField NamedArgumentListPrime - * AssignmentExpression[allowIn] ArgumentListPrime - */ +* FieldName +* Identifier +* String +* Number +* ParenthesizedExpression +*/ - ExprPairList * - Parser::parseArgumentList(NodeQueue &args) - { +JS::ExprNode *JS::Parser::parseFieldName() +{ + + ExprNode *result; + + if( lookahead(Token::string) ) { + const Token *t = match(Token::string); + result = NodeFactory::LiteralString(t->getPos(), ExprNode::string, copyTokenChars(*t)); + } else if(lookahead(Token::number)) { + const Token *t = match(Token::number); + result = NodeFactory::LiteralNumber(*t); + } else if( lookahead(Token::openParenthesis) ) { + result = parseParenthesizedListExpression(); + } else { + result = parseIdentifier(); + } + + return result; +} - ExprPairList *result=NULL; - - if (lookahead(Token::closeParenthesis)) { - } else { - ExprNode *first; - first = parseAssignmentExpression(); - lexer.redesignate(true); //Safe: looking for non-slash punctuation. - //if( AssignmentExpressionNode.isFieldName(first) && - //lookahead(colon_token) ) { - if( lookahead(Token::colon) ) { - ExprNode *second; - match(Token::colon); - // Finish parsing the LiteralField. - second = parseAssignmentExpression(); - // Safe: looking for non-slash punctuation. - lexer.redesignate(true); - args += NodeFactory::LiteralField(first,second); - result = parseNamedArgumentListPrime(args); - } else { - args += NodeFactory::LiteralField(NULL,first); - result = parseArgumentListPrime(args); - } - } - return result; - } /** - * ArgumentListPrime - * - * , AssignmentExpression[allowIn] ArgumentListPrime - * , LiteralField NamedArgumentListPrime - */ +* AllParameters +* Parameter +* Parameter , AllParameters +* Parameter OptionalParameterPrime +* Parameter OptionalParameterPrime , OptionalNamedRestParameters +* | NamedRestParameters +* RestParameter +* RestParameter , | NamedParameters +*/ - ExprPairList * - Parser::parseArgumentListPrime(NodeQueue &args) - { +JS::VariableBinding *JS::Parser::parseAllParameters(FunctionDefinition &fd, NodeQueue ¶ms) +{ - ExprPairList *result; - - if(lookahead(Token::comma)) { + VariableBinding *result; - match(Token::comma); - ExprNode *first; - first = parseAssignmentExpression(); - lexer.redesignate(true); //Safe: looking for non-slash punctuation. - //if( AssignmentExpressionNode.isFieldName(second) && - // lookahead(colon_token) ) { - if( lookahead(Token::colon) ) { - ExprNode *second; - - match(Token::colon); - // Finish parsing the literal field. - second = parseAssignmentExpression(); - // Safe: looking for non-slash punctuation. - lexer.redesignate(true); - args += NodeFactory::LiteralField(first,second); - result = parseNamedArgumentListPrime(args); - - } else { - args += NodeFactory::LiteralField(NULL,first); - result = parseArgumentListPrime(args); - - } - - } else { - result = args.first; - } - - return result; - } - -/** - * NamedArgumentListPrime - * - * , LiteralField NamedArgumentListPrime - */ + if(lookahead(Token::tripleDot)) { + fd.restParameter = parseRestParameter(); + params += fd.restParameter; + if( lookahead(Token::comma) ) { + match(Token::comma); + match(Token::bitwiseOr); + result = parseNamedParameters(fd,params); + } else { + result = params.first; + } + } else if( lookahead(Token::bitwiseOr) ) { + match(Token::bitwiseOr); + result = parseNamedRestParameters(fd,params); + } else { + VariableBinding *first; + first = parseParameter(); + if( lookahead(Token::comma) ) { + params += first; + match(Token::comma); + result = parseAllParameters(fd,params); + } else if( lookahead(Token::assignment) ) { + first = parseOptionalParameterPrime(first); + if (!fd.optParameters) { + fd.optParameters = first; + } + params += first; + if( lookahead(Token::comma) ) { + match(Token::comma); + result = parseOptionalNamedRestParameters(fd,params); + } + } else { + params += first; + result = params.first; + } + } - ExprPairList * - Parser::parseNamedArgumentListPrime(NodeQueue &args) - { - - ExprPairList *result; - - if(lookahead(Token::comma)) { - match(Token::comma); - args += parseLiteralField(); - result = parseNamedArgumentListPrime(args); - } else { - result = args.first; - } - - return result; - } - + return result; +} /** - * AllParameters - * Parameter - * Parameter , AllParameters - * Parameter OptionalParameterPrime - * Parameter OptionalParameterPrime , OptionalNamedRestParameters - * | NamedRestParameters - * RestParameter - * RestParameter , | NamedParameters - */ +* OptionalNamedRestParameters +* OptionalParameter +* OptionalParameter , OptionalNamedRestParameters +* | NamedRestParameters +* RestParameter +* RestParameter , | NamedParameters +*/ - VariableBinding * - Parser::parseAllParameters(FunctionDefinition &fd, - NodeQueue ¶ms) - { +JS::VariableBinding *JS::Parser::parseOptionalNamedRestParameters (FunctionDefinition &fd, NodeQueue ¶ms) +{ - VariableBinding *result; - - if(lookahead(Token::tripleDot)) { - fd.restParameter = parseRestParameter(); - params += fd.restParameter; - if( lookahead(Token::comma) ) { - match(Token::comma); - match(Token::bitwiseOr); - result = parseNamedParameters(fd,params); - } else { - result = params.first; - } - } else if( lookahead(Token::bitwiseOr) ) { - match(Token::bitwiseOr); - result = parseNamedRestParameters(fd,params); - } else { - VariableBinding *first; - first = parseParameter(); - if( lookahead(Token::comma) ) { - params += first; - match(Token::comma); - result = parseAllParameters(fd,params); - } else if( lookahead(Token::assignment) ) { - first = parseOptionalParameterPrime(first); - if (!fd.optParameters) { - fd.optParameters = first; - } - params += first; - if( lookahead(Token::comma) ) { - match(Token::comma); - result = parseOptionalNamedRestParameters(fd,params); - } - } else { - params += first; - result = params.first; - } - } - - return result; - } - -/** - * OptionalNamedRestParameters - * OptionalParameter - * OptionalParameter , OptionalNamedRestParameters - * | NamedRestParameters - * RestParameter - * RestParameter , | NamedParameters - */ + VariableBinding *result; - VariableBinding * - Parser::parseOptionalNamedRestParameters (FunctionDefinition &fd, - NodeQueue ¶ms) - { + if( lookahead(Token::tripleDot) ) { + fd.restParameter = parseRestParameter(); + params += fd.restParameter; + if( lookahead(Token::comma) ) { + match(Token::comma); + match(Token::bitwiseOr); + result = parseNamedParameters(fd,params); + } else { + result = params.first; + } + } else if( lookahead(Token::bitwiseOr) ) { + match(Token::bitwiseOr); + result = parseNamedRestParameters(fd,params); + } else { + VariableBinding *first; + first = parseOptionalParameter(); + if (!fd.optParameters) { + fd.optParameters = first; + } + params += first; + if( lookahead(Token::comma) ) { + match(Token::comma); + result = parseOptionalNamedRestParameters(fd,params); + } else { + result = params.first; + } + } - VariableBinding *result; - - if( lookahead(Token::tripleDot) ) { - fd.restParameter = parseRestParameter(); - params += fd.restParameter; - if( lookahead(Token::comma) ) { - match(Token::comma); - match(Token::bitwiseOr); - result = parseNamedParameters(fd,params); - } else { - result = params.first; - } - } else if( lookahead(Token::bitwiseOr) ) { - match(Token::bitwiseOr); - result = parseNamedRestParameters(fd,params); - } else { - VariableBinding *first; - first = parseOptionalParameter(); - if (!fd.optParameters) { - fd.optParameters = first; - } - params += first; - if( lookahead(Token::comma) ) { - match(Token::comma); - result = parseOptionalNamedRestParameters(fd,params); - } else { - result = params.first; - } - } - - return result; - } - -/** - * NamedRestParameters - * NamedParameter - * NamedParameter , NamedRestParameters - * RestParameter - */ - - VariableBinding * - Parser::parseNamedRestParameters(FunctionDefinition &fd, - NodeQueue ¶ms) - { - - VariableBinding *result; - - if (lookahead(Token::tripleDot)) { - fd.restParameter = parseRestParameter(); - params += fd.restParameter; - result = params.first; - } else { - NodeQueue aliases; - VariableBinding *first; - first = parseNamedParameter(aliases); - // The following marks the position in the list that named - // parameters may occur. It is not required that this - // particular parameter has - // aliases associated with it. - if (!fd.namedParameters) { - fd.namedParameters = first; - } - if (!fd.optParameters && first->initializer) { - fd.optParameters = first; - } - if( lookahead(Token::comma) ) { - params += first; - match(Token::comma); - result = parseNamedRestParameters(fd,params); - } else { - params += first; - result = params.first; - } - } - - return result; - } - -/** - * NamedParameters - * NamedParameter - * NamedParameter , NamedParameters - */ - - VariableBinding * - Parser::parseNamedParameters(FunctionDefinition &fd, - NodeQueue ¶ms) - { - - VariableBinding *result,*first; - NodeQueue aliases; // List of aliases. - first = parseNamedParameter(aliases); - // The following marks the position in the list that named parameters - // may occur. It is not required that this particular parameter has - // aliases associated with it. - if (!fd.namedParameters) { - fd.namedParameters = first; - } - if (!fd.optParameters && first->initializer) { - fd.optParameters = first; - } - if (lookahead(Token::comma)) { - params += first; - match(Token::comma); - result = parseNamedParameters(fd,params); - } else { - params += first; - result = params.first; - } - - return result; - } - -/** - * RestParameter - * ... - * ... Parameter - */ - - VariableBinding * - Parser::parseRestParameter() - { - - VariableBinding *result; - - match(Token::tripleDot); - if (lookahead(Token::closeParenthesis) || - lookahead(Token::comma)) { - result = NodeFactory::Parameter(0, 0, false); - } else { - result = parseParameter(); - } - - return result; - } - -/** - * Parameter - * Identifier - * Identifier : TypeExpression[allowIn] - */ - - VariableBinding * - Parser::parseParameter() - { - bool constant = lexer.eat (true, Token::Const); - ExprNode *first = parseIdentifier(); - ExprNode *second = parseTypeBinding (Token::colon, false); - - return NodeFactory::Parameter(first, second, constant); - } - -/** - * OptionalParameter - * Parameter = AssignmentExpression[allowIn] - */ - - VariableBinding * - Parser::parseOptionalParameter() - { - - VariableBinding *result,*first; - - first = parseParameter(); - result = parseOptionalParameterPrime(first); - - return result; - } - - VariableBinding * - Parser::parseOptionalParameterPrime(VariableBinding *first) - { - - VariableBinding* result=NULL; - - match(Token::assignment); - first->initializer = parseAssignmentExpression(); - lexer.redesignate(true); // Safe: looking for non-slash puncutation. - result = first; - - return result; - } + return result; +} /** - * NamedParameter - * Parameter - * OptionalParameter - * String NamedParameter - */ +* NamedRestParameters +* NamedParameter +* NamedParameter , NamedRestParameters +* RestParameter +*/ - VariableBinding * - Parser::parseNamedParameter(NodeQueue &aliases) - { +JS::VariableBinding *JS::Parser::parseNamedRestParameters(FunctionDefinition &fd, NodeQueue ¶ms) +{ - VariableBinding *result; - - if(lookahead(Token::string)) { - const Token *t = match(Token::string); - aliases += NodeFactory::ListedIdentifier(copyTokenChars(*t)); - result = parseNamedParameter(aliases); - } else { - result = parseParameter(); - result->aliases = aliases.first; - if(lookahead(Token::assignment)) { - result = parseOptionalParameterPrime(result); - } - } - return result; - } + VariableBinding *result; + + if (lookahead(Token::tripleDot)) { + fd.restParameter = parseRestParameter(); + params += fd.restParameter; + result = params.first; + } else { + NodeQueue aliases; + VariableBinding *first; + first = parseNamedParameter(aliases); + // The following marks the position in the list that named + // parameters may occur. It is not required that this + // particular parameter has + // aliases associated with it. + if (!fd.namedParameters) { + fd.namedParameters = first; + } + if (!fd.optParameters && first->initializer) { + fd.optParameters = first; + } + if( lookahead(Token::comma) ) { + params += first; + match(Token::comma); + result = parseNamedRestParameters(fd,params); + } else { + params += first; + result = params.first; + } + } + + return result; +} /** - * ResultSignature - * - * : TypeExpression[allowIn] - */ +* NamedParameters +* NamedParameter +* NamedParameter , NamedParameters +*/ - ExprNode * - Parser::parseResultSignature() - { +JS::VariableBinding *JS::Parser::parseNamedParameters(FunctionDefinition &fd, NodeQueue ¶ms) +{ - ExprNode* result=NULL; - - if (lookahead(Token::colon)) - { - match(Token::colon); - result = parseTypeExpression(); // allowIn is default. - } else { - result = NULL; - } + VariableBinding *result,*first; + NodeQueue aliases; // List of aliases. + first = parseNamedParameter(aliases); + // The following marks the position in the list that named parameters + // may occur. It is not required that this particular parameter has + // aliases associated with it. + if (!fd.namedParameters) { + fd.namedParameters = first; + } + if (!fd.optParameters && first->initializer) { + fd.optParameters = first; + } + if (lookahead(Token::comma)) { + params += first; + match(Token::comma); + result = parseNamedParameters(fd,params); + } else { + params += first; + result = params.first; + } + + return result; +} + +/** +* RestParameter +* ... +* ... Parameter +*/ + +JS::VariableBinding *JS::Parser::parseRestParameter() +{ + + VariableBinding *result; + + match(Token::tripleDot); + if (lookahead(Token::closeParenthesis) || + lookahead(Token::comma)) { + result = NodeFactory::Parameter(0, 0, false); + } else { + result = parseParameter(); + } + + return result; +} + +/** +* Parameter +* Identifier +* Identifier : TypeExpression[allowIn] +*/ + +JS::VariableBinding *JS::Parser::parseParameter() +{ + bool constant = lexer.eat (true, Token::Const); + ExprNode *first = parseIdentifier(); + ExprNode *second = parseTypeBinding (Token::colon, false); + + return NodeFactory::Parameter(first, second, constant); +} + +/** +* OptionalParameter +* Parameter = AssignmentExpression[allowIn] +*/ + +JS::VariableBinding *JS::Parser::parseOptionalParameter() +{ + + VariableBinding *result,*first; + + first = parseParameter(); + result = parseOptionalParameterPrime(first); + + return result; +} + +JS::VariableBinding *JS::Parser::parseOptionalParameterPrime(VariableBinding *first) +{ + + VariableBinding* result=NULL; + + match(Token::assignment); + first->initializer = parseAssignmentExpression(false); + lexer.redesignate(true); // Safe: looking for non-slash puncutation. + result = first; + + return result; +} + +/** +* NamedParameter +* Parameter +* OptionalParameter +* String NamedParameter +*/ + +JS::VariableBinding *JS::Parser::parseNamedParameter(NodeQueue &aliases) +{ + + VariableBinding *result; + + if(lookahead(Token::string)) { + const Token *t = match(Token::string); + aliases += new(arena) IdentifierList(*new StringAtom(copyTokenChars(*t))); + result = parseNamedParameter(aliases); + } else { + result = parseParameter(); + // ****** result->aliases = aliases.first; + if(lookahead(Token::assignment)) { + result = parseOptionalParameterPrime(result); + } + } + return result; +} + +/** +* ResultSignature +* +* : TypeExpression[allowIn] +*/ + +JS::ExprNode *JS::Parser::parseResultSignature() +{ + + ExprNode* result=NULL; + + if (lookahead(Token::colon)) + { + match(Token::colon); + result = parseTypeExpression(); // allowIn is default. + } else { + result = NULL; + } + + return result; +} - return result; - } - bool - IdentifierList::contains(Token::Kind kind) - { - if (name.tokenKind == kind) - return true; - else - return (next) ? next->contains(kind) : false; - } - // // Parser Utilities // - // Print extra parentheses around subexpressions? - const bool debugExprNodePrint = true; - // Size of one level of statement indentation - const int32 basicIndent = 4; - // Indentation before a case or default statement - const int32 caseIndent = basicIndent/2; - // Indentation of var or const statement bindings - const int32 varIndent = 2; - // Size of one level of expression indentation - const int32 subexpressionIndent = 4; - // Indentation of function signature - const int32 functionHeaderIndent = 9; - // Indentation of class, interface, or namespace header - const int32 namespaceHeaderIndent = 4; +// Print extra parentheses around subexpressions? +const bool debugExprNodePrint = true; +// Size of one level of statement indentation +const int32 basicIndent = 4; +// Indentation before a case or default statement +const int32 caseIndent = basicIndent/2; +// Indentation of var or const statement bindings +const int32 varIndent = 2; +// Size of one level of expression indentation +const int32 subexpressionIndent = 4; +// Indentation of function signature +const int32 functionHeaderIndent = 9; +// Indentation of class, interface, or namespace header +const int32 namespaceHeaderIndent = 4; - static const char functionPrefixNames[3][5] = {"", "get ", "set " }; +static const char functionPrefixNames[3][5] = {"", "get ", "set " }; + // Print this onto f. name must be non-nil. - void - FunctionName::print(PrettyPrinter &f) const - { - f << functionPrefixNames[prefix]; - f << name; - } - +void JS::FunctionName::print(PrettyPrinter &f) const +{ + f << functionPrefixNames[prefix]; + f << name; +} + // Print this onto f. if printConst is false, inhibit printing of the // const keyword. - void - VariableBinding::print(PrettyPrinter &f, bool printConst) const - { - PrettyPrinter::Block b(f); +void JS::VariableBinding::print(PrettyPrinter &f, bool printConst) const +{ + PrettyPrinter::Block b(f); #ifdef NEW_PARSER - if (aliases) { - IdentifierList *id = aliases; - f << "| "; - while (id) { - f << "'"; - f << id->name; - f << "' "; - id = id->next; - } - } + if (aliases) { + IdentifierList *id = aliases; + f << "| "; + while (id) { + f << "'"; + f << id->name; + f << "' "; + id = id->next; + } + } #endif - if (printConst && constant) - f << "const "; - - if (name) - f << name; - PrettyPrinter::Indent i(f, subexpressionIndent); - if (type) { - f.fillBreak(0); - f << ": "; - f << type; - } - if (initializer) { - f.linearBreak(1); - f << "= "; - f << initializer; - } - } - - + if (printConst && constant) + f << "const "; + + if (name) + f << name; + PrettyPrinter::Indent i(f, subexpressionIndent); + if (type) { + f.fillBreak(0); + f << ": "; + f << type; + } + if (initializer) { + f.linearBreak(1); + f << "= "; + f << initializer; + } +} + + // Print this onto f. If attributes is null, this is a function expression; // if attributes is non-null, this is a function statement with the given // attributes. // When there is no function body, print a trailing semicolon unless noSemi is // true. - void - FunctionDefinition::print(PrettyPrinter &f, - const AttributeStmtNode *attributes, - bool noSemi) const - { - PrettyPrinter::Block b(f); - if (attributes) - attributes->printAttributes(f); - - f << "function"; - - if (name) { - f << ' '; - FunctionName::print(f); - } - { - PrettyPrinter::Indent i(f, functionHeaderIndent); - f.fillBreak(0); - f << '('; - { - PrettyPrinter::Block b2(f); - const VariableBinding *p = parameters; - if (p) - while (true) { - if (p == restParameter) { - f << "..."; - if (p->name) - f << ' '; - } - p->print(f, true); - p = p->next; - if (!p) - break; - f << ','; - f.fillBreak(1); - } - f << ')'; - } - if (resultType) { - f.fillBreak(0); - f << ": "; - f << resultType; - } - } - if (body) { - bool loose = attributes != 0; - f.linearBreak(1, loose); - body->printBlock(f, loose); - } else - StmtNode::printSemi(f, noSemi); - } - -// Print a comma-separated ExprList on to f. Since a method can't be called -// on nil, the list has at least one element. - void - ExprList::printCommaList(PrettyPrinter &f) const - { - PrettyPrinter::Block b(f); - const ExprList *list = this; - while (true) { - f << list->expr; - list = list->next; - if (!list) - break; - f << ','; - f.fillBreak(1); - } - } - - -// If list is nil, do nothing. Otherwise, emit a linear line break of size 1, -// the name, a space, and the contents of list separated by commas. - void - ExprList::printOptionalCommaList(PrettyPrinter &f, const char *name, - const ExprList *list) - { - if (list) { - f.linearBreak(1); - f << name << ' '; - list->printCommaList(f); - } - } - - +void JS::FunctionDefinition::print(PrettyPrinter &f, const AttributeStmtNode *attributes, bool noSemi) const +{ + PrettyPrinter::Block b(f); + if (attributes) + attributes->printAttributes(f); + + f << "function"; + + if (name) { + f << ' '; + FunctionName::print(f); + } + { + PrettyPrinter::Indent i(f, functionHeaderIndent); + f.fillBreak(0); + f << '('; + { + PrettyPrinter::Block b2(f); + const VariableBinding *p = parameters; + if (p) + while (true) { + if (p == restParameter) { + f << "..."; + if (p->name) + f << ' '; + } + p->print(f, true); + p = p->next; + if (!p) + break; + f << ','; + f.fillBreak(1); + } + f << ')'; + } + if (resultType) { + f.fillBreak(0); + f << ": "; + f << resultType; + } + } + if (body) { + bool loose = attributes != 0; + f.linearBreak(1, loose); + body->printBlock(f, loose); + } else + StmtNode::printSemi(f, noSemi); +} + + // // ExprNode // - const char *const ExprNode::kindNames[kindsEnd] = { - "NIL", // none - 0, // identifier - 0, // number - 0, // string - 0, // regExp - "null", // Null - "true", // True - "false", // False - "this", // This - "super", // Super - - 0, // parentheses - 0, // numUnit - 0, // exprUnit - "::", // qualify - - 0, // objectLiteral - 0, // arrayLiteral - 0, // functionLiteral - - 0, // call - 0, // New - 0, // index - - ".", // dot - ".class", // dotClass - ".(", // dotParen - "@", // at - - "delete ", // Delete - "typeof ", // Typeof - "eval ", // Eval - "++ ", // preIncrement - "-- ", // preDecrement - " ++", // postIncrement - " --", // postDecrement - "+ ", // plus - "- ", // minus - "~ ", // complement - "! ", // logicalNot +const char *const JS::ExprNode::kindNames[kindsEnd] = { + "NIL", // none + 0, // identifier + 0, // number + 0, // string + 0, // regExp + "null", // Null + "true", // True + "false", // False + "this", // This - "+", // add - "-", // subtract - "*", // multiply - "/", // divide - "%", // modulo - "<<", // leftShift - ">>", // rightShift - ">>>", // logicalRightShift - "&", // bitwiseAnd - "^", // bitwiseXor - "|", // bitwiseOr - "&&", // logicalAnd - "^^", // logicalXor - "||", // logicalOr + 0, // parentheses + 0, // numUnit + 0, // exprUnit + "::", // qualify - "==", // equal - "!=", // notEqual - "<", // lessThan - "<=", // lessThanOrEqual - ">", // greaterThan - ">=", // greaterThanOrEqual - "===", // identical - "!==", // notIdentical - "in", // In - "instanceof", // Instanceof + 0, // objectLiteral + 0, // arrayLiteral + 0, // functionLiteral - "=", // assignment - "+=", // addEquals - "-=", // subtractEquals - "*=", // multiplyEquals - "/=", // divideEquals - "%=", // moduloEquals - "<<=", // leftShiftEquals - ">>=", // rightShiftEquals - ">>>=", // logicalRightShiftEquals - "&=", // bitwiseAndEquals - "^=", // bitwiseXorEquals - "|=", // bitwiseOrEquals - "&&=", // logicalAndEquals - "^^=", // logicalXorEquals - "||=", // logicalOrEquals + 0, // call + 0, // New + 0, // index - "?", // conditional - "," // comma + ".", // dot + ".class", // dotClass + ".(", // dotParen + + 0, // superExpr + 0, // superStmt + + "const ", // Const + "delete ", // Delete + "void ", // Void + "typeof ", // Typeof + "++ ", // preIncrement + "-- ", // preDecrement + " ++", // postIncrement + " --", // postDecrement + "+ ", // plus + "- ", // minus + "~ ", // complement + "! ", // logicalNot + + "+", // add + "-", // subtract + "*", // multiply + "/", // divide + "%", // modulo + "<<", // leftShift + ">>", // rightShift + ">>>", // logicalRightShift + "&", // bitwiseAnd + "^", // bitwiseXor + "|", // bitwiseOr + "&&", // logicalAnd + "^^", // logicalXor + "||", // logicalOr + + "==", // equal + "!=", // notEqual + "<", // lessThan + "<=", // lessThanOrEqual + ">", // greaterThan + ">=", // greaterThanOrEqual + "===", // identical + "!==", // notIdentical + "as", // As + "in", // In + "instanceof", // Instanceof + + "=", // assignment + "+=", // addEquals + "-=", // subtractEquals + "*=", // multiplyEquals + "/=", // divideEquals + "%=", // moduloEquals + "<<=", // leftShiftEquals + ">>=", // rightShiftEquals + ">>>=", // logicalRightShiftEquals + "&=", // bitwiseAndEquals + "^=", // bitwiseXorEquals + "|=", // bitwiseOrEquals + "&&=", // logicalAndEquals + "^^=", // logicalXorEquals + "||=", // logicalOrEquals + + "?", // conditional + "," // comma }; // Print this onto f. - void - ExprNode::print(PrettyPrinter &f) const - { - f << kindName(kind); - } +void JS::ExprNode::print(PrettyPrinter &f) const +{ + f << kindName(kind); +} - void - IdentifierExprNode::print(PrettyPrinter &f) const - { - f << name; - } - - void - NumberExprNode::print(PrettyPrinter &f) const - { - f << value; - } - - void - StringExprNode::print(PrettyPrinter &f) const - { - quoteString(f, str, '"'); - } - - void - RegExpExprNode::print(PrettyPrinter &f) const - { - f << '/' << re << '/' << flags; - } +void JS::IdentifierExprNode::print(PrettyPrinter &f) const +{ + f << name; +} + +void JS::NumberExprNode::print(PrettyPrinter &f) const +{ + f << value; +} + +void JS::StringExprNode::print(PrettyPrinter &f) const +{ + quoteString(f, str, '"'); +} + +void JS::RegExpExprNode::print(PrettyPrinter &f) const +{ + f << '/' << re << '/' << flags; +} + +void JS::NumUnitExprNode::print(PrettyPrinter &f) const +{ + f << numStr; + StringExprNode::print(f); +} + +void JS::ExprUnitExprNode::print(PrettyPrinter &f) const +{ + f << op; + StringExprNode::print(f); +} + +void JS::FunctionExprNode::print(PrettyPrinter &f) const +{ + function.print(f, 0, false); +} + + +void JS::PairListExprNode::print(PrettyPrinter &f) const +{ + char beginBracket; + char endBracket; + + switch (getKind()) { + case objectLiteral: + beginBracket = '{'; + endBracket = '}'; + break; + + case arrayLiteral: + case index: + beginBracket = '['; + endBracket = ']'; + break; + + case superStmt: + case call: + case New: + beginBracket = '('; + endBracket = ')'; + break; + + default: + NOT_REACHED("Bad kind"); + return; + } + + f << beginBracket; + PrettyPrinter::Block b(f); + const ExprPairList *p = pairs; + if (p) + while (true) { + const ExprNode *field = p->field; + if (field) { + f << field << ':'; + f.fillBreak(0); + } + + const ExprNode *value = p->value; + if (value) + f << value; + + p = p->next; + if (!p) + break; + f << ','; + f.linearBreak(static_cast(field || value)); + } + f << endBracket; +} + + +void JS::InvokeExprNode::print(PrettyPrinter &f) const +{ + PrettyPrinter::Block b(f); + if (hasKind(New)) + f << "new "; + if (hasKind(superStmt)) + f << "super"; + else + f << op; + PrettyPrinter::Indent i(f, subexpressionIndent); + f.fillBreak(0); + PairListExprNode::print(f); +} + + +void JS::SuperExprNode::print(PrettyPrinter &f) const +{ + f << "super"; + if (op) { + f << '('; + f << op; + f << ')'; + } +} + + +void JS::UnaryExprNode::print(PrettyPrinter &f) const +{ + if (hasKind(parentheses)) { + f << '('; + f << op; + f << ')'; + } else { + if (debugExprNodePrint) + f << '('; + const char *name = kindName(getKind()); + if (hasKind(postIncrement) || hasKind(postDecrement) || hasKind(dotClass)) { + f << op; + f << name; + } else { + f << name; + f << op; + } + if (debugExprNodePrint) + f << ')'; + } +} + + +void JS::BinaryExprNode::print(PrettyPrinter &f) const +{ + if (debugExprNodePrint && !hasKind(qualify)) + f << '('; + PrettyPrinter::Block b(f); + f << op1; + uint32 nSpaces = hasKind(dot) || hasKind(dotParen) || hasKind(qualify) ? (uint32)0 : (uint32)1; + f.fillBreak(nSpaces); + f << kindName(getKind()); + f.fillBreak(nSpaces); + f << op2; + if (hasKind(dotParen)) + f << ')'; + if (debugExprNodePrint && !hasKind(qualify)) + f << ')'; +} + + +void JS::TernaryExprNode::print(PrettyPrinter &f) const +{ + if (debugExprNodePrint) + f << '('; + PrettyPrinter::Block b(f); + f << op1; + f.fillBreak(1); + f << '?'; + f.fillBreak(1); + f << op2; + f.fillBreak(1); + f << ':'; + f.fillBreak(1); + f << op3; + if (debugExprNodePrint) + f << ')'; +} + + +// +// ExprList +// + + +// Print a comma-separated ExprList on to f. Since a method can't be called +// on nil, the list has at least one element. +void JS::ExprList::printCommaList(PrettyPrinter &f) const +{ + PrettyPrinter::Block b(f); + const ExprList *list = this; + while (true) { + f << list->expr; + list = list->next; + if (!list) + break; + f << ','; + f.fillBreak(1); + } +} + + +// If list is nil, do nothing. Otherwise, emit a linear line break of size 1, +// the name, a space, and the contents of list separated by commas. +void JS::ExprList::printOptionalCommaList(PrettyPrinter &f, const char *name, const ExprList *list) +{ + if (list) { + f.linearBreak(1); + f << name << ' '; + list->printCommaList(f); + } +} - void - NumUnitExprNode::print(PrettyPrinter &f) const - { - f << numStr; - StringExprNode::print(f); - } - - void - ExprUnitExprNode::print(PrettyPrinter &f) const - { - f << op; - StringExprNode::print(f); - } - void - FunctionExprNode::print(PrettyPrinter &f) const - { - function.print(f, 0, false); - } - - void - PairListExprNode::print(PrettyPrinter &f) const - { - char beginBracket; - char endBracket; - - switch (getKind()) { - case objectLiteral: - beginBracket = '{'; - endBracket = '}'; - break; - - case arrayLiteral: - case index: - beginBracket = '['; - endBracket = ']'; - break; - - case call: - case New: - beginBracket = '('; - endBracket = ')'; - break; - - default: - NOT_REACHED("Bad kind"); - return; - } - - f << beginBracket; - PrettyPrinter::Block b(f); - const ExprPairList *p = pairs; - if (p) - while (true) { - const ExprNode *field = p->field; - if (field) { - f << field << ':'; - f.fillBreak(0); - } - - const ExprNode *value = p->value; - if (value) - f << value; - - p = p->next; - if (!p) - break; - f << ','; - f.linearBreak(static_cast(field || value)); - } - f << endBracket; - } - - void - InvokeExprNode::print(PrettyPrinter &f) const - { - PrettyPrinter::Block b(f); - if (hasKind(New)) - f << "new "; - f << op; - PrettyPrinter::Indent i(f, subexpressionIndent); - f.fillBreak(0); - PairListExprNode::print(f); - } - - void - UnaryExprNode::print(PrettyPrinter &f) const - { - if (hasKind(parentheses)) { - f << '('; - f << op; - f << ')'; - } else { - if (debugExprNodePrint) - f << '('; - const char *name = kindName(getKind()); - if (hasKind(postIncrement) || hasKind(postDecrement) || - hasKind(dotClass)) { - f << op; - f << name; - } else { - f << name; - f << op; - } - if (debugExprNodePrint) - f << ')'; - } - } - - void - BinaryExprNode::print(PrettyPrinter &f) const - { - if (debugExprNodePrint && !hasKind(qualify)) - f << '('; - PrettyPrinter::Block b(f); - f << op1; - uint32 nSpaces = hasKind(dot) || hasKind(dotParen) || hasKind(at) || - hasKind(qualify) ? (uint32)0 : (uint32)1; - f.fillBreak(nSpaces); - f << kindName(getKind()); - f.fillBreak(nSpaces); - f << op2; - if (hasKind(dotParen)) - f << ')'; - if (debugExprNodePrint && !hasKind(qualify)) - f << ')'; - } - - void - TernaryExprNode::print(PrettyPrinter &f) const - { - if (debugExprNodePrint) - f << '('; - PrettyPrinter::Block b(f); - f << op1; - f.fillBreak(1); - f << '?'; - f.fillBreak(1); - f << op2; - f.fillBreak(1); - f << ':'; - f.fillBreak(1); - f << op3; - if (debugExprNodePrint) - f << ')'; - } - // // StmtNode // + // Print statements on separate lines onto f. Do not print a line break // after the last statement. - void - StmtNode::printStatements(PrettyPrinter &f, const StmtNode *statements) - { - if (statements) { - PrettyPrinter::Block b(f); - while (true) { - const StmtNode *next = statements->next; - statements->print(f, !next); - statements = next; - if (!statements) - break; - f.requiredBreak(); - } - } - } +void JS::StmtNode::printStatements(PrettyPrinter &f, const StmtNode *statements) +{ + if (statements) { + PrettyPrinter::Block b(f); + while (true) { + const StmtNode *next = statements->next; + statements->print(f, !next); + statements = next; + if (!statements) + break; + f.requiredBreak(); + } + } +} + // Print statements as a block enclosed in curly braces onto f. // If loose is false, do not insist on each statement being on a separate // line; instead, make breaks between statements be linear breaks in the // enclosing PrettyPrinter::Block scope. The caller must have placed this // call inside a PrettyPrinter::Block scope. - void - StmtNode::printBlockStatements(PrettyPrinter &f, - const StmtNode *statements, bool loose) - { - f << '{'; - if (statements) { - { - PrettyPrinter::Indent i(f, basicIndent); - uint32 nSpaces = 0; - while (statements) { - if (statements->hasKind(Case)) { - PrettyPrinter::Indent i2(f, caseIndent - basicIndent); - f.linearBreak(nSpaces, loose); - statements->print(f, false); - } else { - f.linearBreak(nSpaces, loose); - statements->print(f, !statements->next); - } - statements = statements->next; - nSpaces = 1; - } - } - f.linearBreak(0, loose); - } else - f.fillBreak(0); - f << '}'; - } - - +void JS::StmtNode::printBlockStatements(PrettyPrinter &f, const StmtNode *statements, bool loose) +{ + f << '{'; + if (statements) { + { + PrettyPrinter::Indent i(f, basicIndent); + uint32 nSpaces = 0; + while (statements) { + if (statements->hasKind(Case)) { + PrettyPrinter::Indent i2(f, caseIndent - basicIndent); + f.linearBreak(nSpaces, loose); + statements->print(f, false); + } else { + f.linearBreak(nSpaces, loose); + statements->print(f, !statements->next); + } + statements = statements->next; + nSpaces = 1; + } + } + f.linearBreak(0, loose); + } else + f.fillBreak(0); + f << '}'; +} + + // Print a closing statement semicolon onto f unless noSemi is true. - void - StmtNode::printSemi(PrettyPrinter &f, bool noSemi) - { - if (!noSemi) - f << ';'; - } - - +void JS::StmtNode::printSemi(PrettyPrinter &f, bool noSemi) +{ + if (!noSemi) + f << ';'; +} + + // Print this as a substatement of a statement such as if or with. // If this statement is a block without attributes, begin it on the current // line and do not indent it -- the block itself will provide the indent. @@ -2648,342 +2508,332 @@ namespace JavaScript // If noSemi is true, do not print the semicolon unless it is required by the // statement. The caller must have placed this call inside a // PrettyPrinter::Block scope that encloses the containining statement. - void - StmtNode::printSubstatement(PrettyPrinter &f, bool noSemi, - const char *continuation) const - { - if (hasKind(block) && - !static_cast(this)->attributes) { - f << ' '; - static_cast(this)->printBlock(f, true); - if (continuation) - f << ' ' << continuation; - } else { - { - PrettyPrinter::Indent i(f, basicIndent); - f.requiredBreak(); - this->print(f, noSemi); - } - if (continuation) { - f.requiredBreak(); - f << continuation; - } - } - } - - +void JS::StmtNode::printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation) const +{ + if (hasKind(block) && + !static_cast(this)->attributes) { + f << ' '; + static_cast(this)->printBlock(f, true); + if (continuation) + f << ' ' << continuation; + } else { + { + PrettyPrinter::Indent i(f, basicIndent); + f.requiredBreak(); + this->print(f, noSemi); + } + if (continuation) { + f.requiredBreak(); + f << continuation; + } + } +} + + // Print the attributes on a single line separated with and followed by a // space. - void AttributeStmtNode::printAttributes(PrettyPrinter &f) const - { - for (const IdentifierList *a = attributes; a; a = a->next) - f << a->name << ' '; - } - - +void JS::AttributeStmtNode::printAttributes(PrettyPrinter &f) const +{ + for (const ExprList *a = attributes; a; a = a->next) + f << a->expr << ' '; +} + + // Print this block, including attributes, onto f. // If loose is false, do not insist on each statement being on a separate // line; instead, make breaks between statements be linear breaks in the // enclosing PrettyPrinter::Block scope. // The caller must have placed this call inside a PrettyPrinter::Block scope. - void BlockStmtNode::printBlock(PrettyPrinter &f, bool loose) const - { - printAttributes(f); - printBlockStatements(f, statements, loose); - } - +void JS::BlockStmtNode::printBlock(PrettyPrinter &f, bool loose) const +{ + printAttributes(f); + printBlockStatements(f, statements, loose); +} + + // Print this onto f. // If noSemi is true, do not print the trailing semicolon unless it is // required by the statement. - void - StmtNode::print(PrettyPrinter &f, bool /*noSemi*/) const - { - ASSERT(hasKind(empty)); - f << ';'; - } +void JS::StmtNode::print(PrettyPrinter &f, bool /*noSemi*/) const +{ + ASSERT(hasKind(empty)); + f << ';'; +} + +void JS::ExprStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + const ExprNode *e = expr; + + switch (getKind()) { + case Case: + if (e) { + f << "case "; + f << e; + } else + f << "default"; + f << ':'; + break; + + case Return: + f << "return"; + if (e) { + f << ' '; + goto showExpr; + } else + goto showSemicolon; + + case Throw: + f << "throw "; + case expression: + showExpr: + f << e; + showSemicolon: + printSemi(f, noSemi); + break; + + default: + NOT_REACHED("Bad kind"); + } +} + +void JS::DebuggerStmtNode::print(PrettyPrinter &f, bool) const +{ + f << "debugger;"; +} + +void JS::BlockStmtNode::print(PrettyPrinter &f, bool) const +{ + PrettyPrinter::Block b(f, 0); + printBlock(f, true); +} + +void JS::LabelStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + PrettyPrinter::Block b(f, basicIndent); + f << name << ':'; + f.linearBreak(1); + stmt->print(f, noSemi); +} + +void JS::UnaryStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + PrettyPrinter::Block b(f, 0); + printContents(f, noSemi); +} - void - ExprStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - const ExprNode *e = expr; - - switch (getKind()) { - case Case: - if (e) { - f << "case "; - f << e; - } else - f << "default"; - f << ':'; - break; - - case Return: - f << "return"; - if (e) { - f << ' '; - goto showExpr; - } else - goto showSemicolon; - - case Throw: - f << "throw "; - case expression: - showExpr: - f << e; - showSemicolon: - printSemi(f, noSemi); - break; - - default: - NOT_REACHED("Bad kind"); - } - } - - void - DebuggerStmtNode::print(PrettyPrinter &f, bool) const - { - f << "debugger;"; - } - - void - BlockStmtNode::print(PrettyPrinter &f, bool) const - { - PrettyPrinter::Block b(f, 0); - printBlock(f, true); - } - - void - LabelStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - PrettyPrinter::Block b(f, basicIndent); - f << name << ':'; - f.linearBreak(1); - stmt->print(f, noSemi); - } - - void - UnaryStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - PrettyPrinter::Block b(f, 0); - printContents(f, noSemi); - } // Same as print except that uses the caller's PrettyPrinter::Block. - void - UnaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const - { - ASSERT(stmt); - const char *kindName = 0; - - switch (getKind()) { - case If: - kindName = "if"; - break; - - case While: - kindName = "while"; - break; - - case DoWhile: - f << "do"; - stmt->printSubstatement(f, true, "while ("); - f << expr << ')'; - printSemi(f, noSemi); - return; - - case With: - kindName = "with"; - break; - - default: - NOT_REACHED("Bad kind"); - } - - f << kindName << " ("; - f << expr << ')'; - stmt->printSubstatement(f, noSemi); - } - - void - BinaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const - { - ASSERT(stmt && stmt2 && hasKind(IfElse)); - - f << "if ("; - f << expr << ')'; - stmt->printSubstatement(f, true, "else"); - if (stmt2->hasKind(If) || stmt2->hasKind(IfElse)) { - f << ' '; - static_cast(stmt2)->printContents(f, - noSemi); - } else - stmt2->printSubstatement(f, noSemi); - } - - void - ForStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - ASSERT(stmt && (hasKind(For) || hasKind(ForIn))); - - PrettyPrinter::Block b(f, 0); - f << "for ("; - { - PrettyPrinter::Block b2(f); - if (initializer) - initializer->print(f, true); - if (hasKind(ForIn)) { - f.fillBreak(1); - f << "in"; - f.fillBreak(1); - ASSERT(expr2 && !expr3); - f << expr2; - } else { - f << ';'; - if (expr2) { - f.linearBreak(1); - f << expr2; - } - f << ';'; - if (expr3) { - f.linearBreak(1); - f << expr3; - } - } - f << ')'; - } - stmt->printSubstatement(f, noSemi); - } - - void - SwitchStmtNode::print(PrettyPrinter &f, bool) const - { - PrettyPrinter::Block b(f); - f << "switch ("; - f << expr << ") "; - printBlockStatements(f, statements, true); - } - - void - GoStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - const char *kindName = 0; - - switch (getKind()) { - case Break: - kindName = "break"; - break; - - case Continue: - kindName = "continue"; - break; - - default: - NOT_REACHED("Bad kind"); - } - - f << kindName; - if (name) - f << " " << *name; - printSemi(f, noSemi); - } - - void - TryStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - PrettyPrinter::Block b(f, 0); - f << "try"; - const StmtNode *s = stmt; - for (const CatchClause *c = catches; c; c = c->next) { - s->printSubstatement(f, true, "catch ("); - PrettyPrinter::Block b2(f); - f << c->name; - ExprNode *t = c->type; - if (t) { - f << ':'; - f.linearBreak(1); - f << t; - } - f << ')'; - s = c->stmt; - } - if (finally) { - s->printSubstatement(f, true, "finally"); - s = finally; - } - s->printSubstatement(f, noSemi); - } - - void - VariableStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - printAttributes(f); - ASSERT(hasKind(Const) || hasKind(Var)); - f << (hasKind(Const) ? "const" : "var"); - { - PrettyPrinter::Block b(f, basicIndent); - const VariableBinding *binding = bindings; - if (binding) - while (true) { - f.linearBreak(1); - binding->print(f, false); - binding = binding->next; - if (!binding) - break; - f << ','; - } - } - printSemi(f, noSemi); - } - - void - FunctionStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - function.print(f, this, noSemi); - } - - void - NamespaceStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - printAttributes(f); - ASSERT(hasKind(Namespace)); - - PrettyPrinter::Block b(f, namespaceHeaderIndent); - f << "namespace "; - f << name; - ExprList::printOptionalCommaList(f, "extends", supers); - printSemi(f, noSemi); - } - - void - ClassStmtNode::print(PrettyPrinter &f, bool noSemi) const - { - printAttributes(f); - ASSERT(hasKind(Class) || hasKind(Interface)); - - { - PrettyPrinter::Block b(f, namespaceHeaderIndent); - const char *keyword; - const char *superlistKeyword; - if (hasKind(Class)) { - keyword = "class "; - superlistKeyword = "implements"; - } else { - keyword = "interface "; - superlistKeyword = "extends"; - } - f << keyword; - f << name; - if (superclass) { - f.linearBreak(1); - f << "extends "; - f << superclass; - } - ExprList::printOptionalCommaList(f, superlistKeyword, supers); - } - if (body) { - f.requiredBreak(); - body->printBlock(f, true); - } else - printSemi(f, noSemi); - } +void JS::UnaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const +{ + ASSERT(stmt); + const char *kindName = 0; + + switch (getKind()) { + case If: + kindName = "if"; + break; + + case While: + kindName = "while"; + break; + + case DoWhile: + f << "do"; + stmt->printSubstatement(f, true, "while ("); + f << expr << ')'; + printSemi(f, noSemi); + return; + + case With: + kindName = "with"; + break; + + default: + NOT_REACHED("Bad kind"); + } + + f << kindName << " ("; + f << expr << ')'; + stmt->printSubstatement(f, noSemi); +} + +void JS::BinaryStmtNode::printContents(PrettyPrinter &f, bool noSemi) const +{ + ASSERT(stmt && stmt2 && hasKind(IfElse)); + + f << "if ("; + f << expr << ')'; + stmt->printSubstatement(f, true, "else"); + if (stmt2->hasKind(If) || stmt2->hasKind(IfElse)) { + f << ' '; + static_cast(stmt2)->printContents(f, noSemi); + } else + stmt2->printSubstatement(f, noSemi); +} + + +void JS::ForStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + ASSERT(stmt && (hasKind(For) || hasKind(ForIn))); + + PrettyPrinter::Block b(f, 0); + f << "for ("; + { + PrettyPrinter::Block b2(f); + if (initializer) + initializer->print(f, true); + if (hasKind(ForIn)) { + f.fillBreak(1); + f << "in"; + f.fillBreak(1); + ASSERT(expr2 && !expr3); + f << expr2; + } else { + f << ';'; + if (expr2) { + f.linearBreak(1); + f << expr2; + } + f << ';'; + if (expr3) { + f.linearBreak(1); + f << expr3; + } + } + f << ')'; + } + stmt->printSubstatement(f, noSemi); +} + + +void JS::SwitchStmtNode::print(PrettyPrinter &f, bool) const +{ + PrettyPrinter::Block b(f); + f << "switch ("; + f << expr << ") "; + printBlockStatements(f, statements, true); +} + + +void JS::GoStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + const char *kindName = 0; + + switch (getKind()) { + case Break: + kindName = "break"; + break; + + case Continue: + kindName = "continue"; + break; + + default: + NOT_REACHED("Bad kind"); + } + + f << kindName; + if (name) + f << " " << *name; + printSemi(f, noSemi); +} + + +void JS::TryStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + PrettyPrinter::Block b(f, 0); + f << "try"; + const StmtNode *s = stmt; + for (const CatchClause *c = catches; c; c = c->next) { + s->printSubstatement(f, true, "catch ("); + PrettyPrinter::Block b2(f); + f << c->name; + ExprNode *t = c->type; + if (t) { + f << ':'; + f.linearBreak(1); + f << t; + } + f << ')'; + s = c->stmt; + } + if (finally) { + s->printSubstatement(f, true, "finally"); + s = finally; + } + s->printSubstatement(f, noSemi); +} + + +void JS::VariableStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + printAttributes(f); + ASSERT(hasKind(Const) || hasKind(Var)); + f << (hasKind(Const) ? "const" : "var"); + { + PrettyPrinter::Block b(f, basicIndent); + const VariableBinding *binding = bindings; + if (binding) + while (true) { + f.linearBreak(1); + binding->print(f, false); + binding = binding->next; + if (!binding) + break; + f << ','; + } + } + printSemi(f, noSemi); +} + + +void JS::FunctionStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + function.print(f, this, noSemi); +} + + +void JS::NamespaceStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + printAttributes(f); + ASSERT(hasKind(Namespace)); + + PrettyPrinter::Block b(f, namespaceHeaderIndent); + f << "namespace "; + f << name; + ExprList::printOptionalCommaList(f, "extends", supers); + printSemi(f, noSemi); +} + + +void JS::ClassStmtNode::print(PrettyPrinter &f, bool noSemi) const +{ + printAttributes(f); + ASSERT(hasKind(Class) || hasKind(Interface)); + + { + PrettyPrinter::Block b(f, namespaceHeaderIndent); + const char *keyword; + const char *superlistKeyword; + if (hasKind(Class)) { + keyword = "class "; + superlistKeyword = "implements"; + } else { + keyword = "interface "; + superlistKeyword = "extends"; + } + f << keyword; + f << name; + if (superclass) { + f.linearBreak(1); + f << "extends "; + f << superclass; + } + ExprList::printOptionalCommaList(f, superlistKeyword, supers); + } + if (body) { + f.requiredBreak(); + body->printBlock(f, true); + } else + printSemi(f, noSemi); } diff --git a/mozilla/js2/src/parser.h b/mozilla/js2/src/parser.h index 27da0925dd1..e73ccb586c1 100644 --- a/mozilla/js2/src/parser.h +++ b/mozilla/js2/src/parser.h @@ -13,11 +13,11 @@ * The Original Code is the JavaScript 2 Prototype. * * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are + * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License (the "GPL"), in which case the @@ -46,20 +46,18 @@ namespace JavaScript { // Language Selectors // - class Language { - enum { - minorVersion = 0, // Single BCD digit representing the minor - // JavaScript version - minorVersionBits = 4, - majorVersion = 4, // Single BCD digit representing the major - // JavaScript version - majorVersionBits = 4, - strictSemantics = 8, // True when strict semantics are in use - strictSyntax = 9, // True when strict syntax is in use - unknown = 31 // True when language is unknown - }; - uint32 flags; // Bitmap of flags at locations as above - }; + class Language { + enum { + minorVersion = 0, // Single BCD digit representing the minor JavaScript version + minorVersionBits = 4, + majorVersion = 4, // Single BCD digit representing the major JavaScript version + majorVersionBits = 4, + strictSemantics = 8, // True when strict semantics are in use + strictSyntax = 9, // True when strict syntax is in use + unknown = 31 // True when language is unknown + }; + uint32 flags; // Bitmap of flags at locations as above + }; // // Parser @@ -70,892 +68,744 @@ namespace JavaScript { // hold onto any data that needs to be destroyed explicitly. Strings are // allocated via newArenaString. - struct ParseNode: ArenaObject { - uint32 pos; // Position of this statement or expression - - explicit ParseNode(uint32 pos): pos(pos) {} - }; + struct ParseNode: ArenaObject { + uint32 pos; // Position of this statement or expression + + explicit ParseNode(uint32 pos): pos(pos) {} + }; + // A helper template for creating linked lists of ParseNode subtypes. N should // be derived from a ParseNode and should have an instance variable called // of type N* and that is initialized to nil when an N instance is // created. - template - class NodeQueue { - public: - N *first; // Head of queue - private: - N **last; // Next link of last element of queue - - public: - NodeQueue(): first(0), last(&first) {} - private: - NodeQueue(const NodeQueue&); // No copy constructor - void operator=(const NodeQueue&); // No assignment operator - public: - void operator+=(N *elt) { - ASSERT(elt && !elt->next); *last = elt; last = &elt->next; - } - }; - - struct ExprNode; - struct AttributeStmtNode; - struct BlockStmtNode; - - struct IdentifierList; - struct VariableBinding: ParseNode { - VariableBinding *next; // Next binding in a linked list of - // variable or parameter bindings - IdentifierList *aliases; - ExprNode *name; // The variable's name; nil if omitted, - // which currently can only happen - // for ... parameters - ExprNode *type; // Type expression or nil if not - // provided - ExprNode *initializer; // Initial value expression or nil if - // not provided - bool constant; // true for const variables and - // parameters - VariableBinding(uint32 pos, ExprNode *name, ExprNode *type, - ExprNode *initializer, bool constant): - ParseNode(pos), next(0), aliases(0), name(name), type(type), - initializer(initializer), constant(constant) {} - - void print(PrettyPrinter &f, bool printConst) const; - }; - - struct ExprNode: ParseNode { - // Keep synchronized with kindNames - enum Kind { // Actual class Operands - none, - identifier, // IdentifierExprNode - - // Begin of isPostfix() - - number, // NumberExprNode - string, // StringExprNode - regExp, // RegExpExprNode // - Null, // ExprNode null - True, // ExprNode true - False, // ExprNode false - This, // ExprNode this - Super, // ExprNode super - - parentheses, // UnaryExprNode () - numUnit, // NumUnitExprNode "" or - exprUnit, // ExprUnitExprNode () "" - qualify, // BinaryExprNode :: - // (right-associative: a::b::c represented as - // a::(b::c)) - - objectLiteral, // PairListExprNode {:, - // :, ..., :} - arrayLiteral, // PairListExprNode [, , ..., - // ] - functionLiteral, // FunctionExprNode function - - call, // InvokeExprNode (:, - // :, ..., :) - New, // InvokeExprNode new (:, - // :, ..., :) - index, // InvokeExprNode [:, - // :, ..., :] - - dot, // BinaryExprNode . - // must be identifier or qualify - dotClass, // UnaryExprNode .class - dotParen, // BinaryExprNode .( ) - at, // BinaryExprNode @ or - // @( ) - - // End of isPostfix() - - Delete, // UnaryExprNode delete - Typeof, // UnaryExprNode typeof - Eval, // UnaryExprNode eval - preIncrement, // UnaryExprNode ++ - preDecrement, // UnaryExprNode -- - postIncrement, // UnaryExprNode ++ - postDecrement, // UnaryExprNode -- - plus, // UnaryExprNode + - minus, // UnaryExprNode - - complement, // UnaryExprNode ~ - logicalNot, // UnaryExprNode ! - - add, // BinaryExprNode + - subtract, // BinaryExprNode - - multiply, // BinaryExprNode * - divide, // BinaryExprNode / - modulo, // BinaryExprNode % - leftShift, // BinaryExprNode << - rightShift, // BinaryExprNode >> - logicalRightShift, // BinaryExprNode >>> - bitwiseAnd, // BinaryExprNode & - bitwiseXor, // BinaryExprNode ^ - bitwiseOr, // BinaryExprNode | - logicalAnd, // BinaryExprNode && - logicalXor, // BinaryExprNode ^^ - logicalOr, // BinaryExprNode || - - equal, // BinaryExprNode == - notEqual, // BinaryExprNode != - lessThan, // BinaryExprNode < - lessThanOrEqual, // BinaryExprNode <= - greaterThan, // BinaryExprNode > - greaterThanOrEqual,// BinaryExprNode >= - identical, // BinaryExprNode === - notIdentical, // BinaryExprNode !== - In, // BinaryExprNode in - Instanceof, // BinaryExprNode instanceof - - assignment, // BinaryExprNode = - - // Begin of isAssigningKind() - - addEquals, // BinaryExprNode += - subtractEquals, // BinaryExprNode -= - multiplyEquals, // BinaryExprNode *= - divideEquals, // BinaryExprNode /= - moduloEquals, // BinaryExprNode %= - leftShiftEquals, // BinaryExprNode <<= - rightShiftEquals, // BinaryExprNode >>= - logicalRightShiftEquals, // BinaryExprNode >>>= - bitwiseAndEquals, // BinaryExprNode &= - bitwiseXorEquals, // BinaryExprNode ^= - bitwiseOrEquals, // BinaryExprNode |= - logicalAndEquals, // BinaryExprNode &&= - logicalXorEquals, // BinaryExprNode ^^= - logicalOrEquals, // BinaryExprNode ||= - - // End of isAssigningKind() - - conditional, // TernaryExprNode ? : - comma, // BinaryExprNode , - // Comma expressions only - - kindsEnd - }; - - private: - Kind kind; // The node's kind - static const char *const kindNames[kindsEnd]; - public: - - ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {} - - Kind getKind() const {return kind;} - bool hasKind(Kind k) const {return kind == k;} - - static bool isFieldKind(Kind kind) { - return kind == identifier || - kind == number || kind == string || kind == qualify; - } - static bool isAssigningKind(Kind kind) { - return kind >= assignment && kind <= logicalOrEquals; - } - static const char *kindName(Kind kind) { - ASSERT(uint(kind) < kindsEnd); - return kindNames[kind]; - } - bool isPostfix() const {return kind >= identifier && kind <= at;} - - virtual void print(PrettyPrinter &f) const; - friend Formatter &operator<<(Formatter &f, Kind k) { - f << kindName(k); - return f; - } - }; - - // Print e onto f. - inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) { - ASSERT(e); e->print(f); return f; - } - - struct FunctionName { - enum Prefix { - normal, // No prefix - Get, // get - Set // set - }; - - Prefix prefix; // The name's prefix, if any - ExprNode *name; // The name; nil if omitted - - FunctionName(): prefix(normal), name(0) {} - - void print(PrettyPrinter &f) const; - }; - - struct FunctionDefinition: FunctionName { - VariableBinding *parameters; // Linked list of all parameters, - // including optional and rest - // parameters, if any - VariableBinding *optParameters; // Pointer to first non-required - // parameter inside parameters list; - // nil if none - VariableBinding *namedParameters; // The first parameter after the - // named parameter marker. May or may - // not have aliases. - VariableBinding *restParameter; // Pointer to rest parameter inside - // parameters list; nil if none - ExprNode *resultType; // Result type expression or nil if not - // provided - BlockStmtNode *body; // Body; nil if none - - void print(PrettyPrinter &f, const AttributeStmtNode *attributes, - bool noSemi) const; - }; - - - struct IdentifierExprNode: ExprNode { - const StringAtom &name; // The identifier - - IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name) : - ExprNode(pos, kind), name(name) {} - explicit IdentifierExprNode(const Token &t) : - ExprNode(t.getPos(), identifier), name(t.getIdentifier()) {} - - void print(PrettyPrinter &f) const; - }; - - struct NumberExprNode: ExprNode { - float64 value; // The number's value - - NumberExprNode(uint32 pos, float64 value) : - ExprNode(pos, number), value(value) {} - explicit NumberExprNode(const Token &t) : - ExprNode(t.getPos(), number), value(t.getValue()) {} - - void print(PrettyPrinter &f) const; - }; - - struct StringExprNode: ExprNode { - String &str; // The string - - StringExprNode(uint32 pos, Kind kind, String &str) : - ExprNode(pos, kind), str(str) {} - - void print(PrettyPrinter &f) const; - }; - - struct RegExpExprNode: ExprNode { - const StringAtom &re; // The regular expression's contents - String &flags; // The regular expression's flags - - RegExpExprNode(uint32 pos, Kind kind, const StringAtom &re, - String &flags) : - ExprNode(pos, kind), re(re), flags(flags) {} - - void print(PrettyPrinter &f) const; - }; - - struct NumUnitExprNode: StringExprNode { // str is the unit string - String &numStr; // The number's source string - float64 num; // The number's value - - NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, - String &unitStr): - StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {} - - void print(PrettyPrinter &f) const; - }; - - struct ExprUnitExprNode: StringExprNode { // str is the unit string - ExprNode *op; // The expression to which the - // unit is applied; non-nil only - - ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr) : - StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);} - - void print(PrettyPrinter &f) const; - }; - - struct FunctionExprNode: ExprNode { - FunctionDefinition function; // Function definition - - explicit FunctionExprNode(uint32 pos) : - ExprNode(pos, functionLiteral) {} - - void print(PrettyPrinter &f) const; - }; - - struct ExprPairList: ArenaObject { - ExprPairList *next; // Next pair in linked list - ExprNode *field; // Field expression or nil if not - // provided - ExprNode *value; // Value expression or nil if not - // provided - - explicit ExprPairList(ExprNode *field = 0, ExprNode *value = 0) : - next(0), field(field), value(value) {} - }; - - struct PairListExprNode: ExprNode { - ExprPairList *pairs; // Linked list of pairs - - PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs) : - ExprNode(pos, kind), pairs(pairs) {} - - void print(PrettyPrinter &f) const; - }; - - struct InvokeExprNode: PairListExprNode { - ExprNode *op; // The called function, called - // constructor, or indexed object; - // non-nil only - - InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs): - PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op);} - - void print(PrettyPrinter &f) const; - }; - - struct UnaryExprNode: ExprNode { - ExprNode *op; // The unary operator's operand; - // non-nil only - - UnaryExprNode(uint32 pos, Kind kind, ExprNode *op) : - ExprNode(pos, kind), op(op) {ASSERT(op);} - - void print(PrettyPrinter &f) const; - }; - - struct BinaryExprNode: ExprNode { - ExprNode *op1; // The binary operator's first operand; - // non-nil only - ExprNode *op2; // The binary operator's second operand; - // non-nil only - - BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2) : - ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);} - - void print(PrettyPrinter &f) const; - }; - - struct TernaryExprNode: ExprNode { - ExprNode *op1; // The ternary operator's first operand; - // non-nil only - ExprNode *op2; // The ternary operator's second operand; - // non-nil only - ExprNode *op3; // The ternary operator's third operand; - // non-nil only - - TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, - ExprNode *op3) : - ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) { - ASSERT(op1 && op2 && op3); - } - - void print(PrettyPrinter &f) const; - }; - - struct StmtNode: ParseNode { - enum Kind { // Actual class Operands - empty, // StmtNode ; - expression, // ExprStmtNode ; - block, // BlockStmtNode { } - label, // LabelStmtNode : - If, // UnaryStmtNode if ( ) - IfElse, // BinaryStmtNode if ( ) else - // - Switch, // SwitchStmtNode switch ( ) - While, // UnaryStmtNode while ( ) - DoWhile, // UnaryStmtNode do while ( ) - With, // UnaryStmtNode with ( ) - For, // ForStmtNode for ( ; - // ; ) - ForIn, // ForStmtNode for ( in - // ) - Case, // ExprStmtNode case : or default : - // Only occurs directly inside a Switch - Break, // GoStmtNode break ; or break ; - Continue, // GoStmtNode continue ; or continue ; - Return, // ExprStmtNode return ; or return ; - Throw, // ExprStmtNode throw ; - Try, // TryStmtNode try - Import, // ImportStmtNode import ; - UseImport, // ImportStmtNode use import ; - Use, // UseStmtNode use namespace ; - Export, // ExportStmtNode export - // ; - Const, // VariableStmtNode const - // ; - Var, // VariableStmtNode var ; - Function, // FunctionStmtNode function - // - Class, // ClassStmtNode class - // extends implements - Interface, // ClassStmtNode interface - // extends - Namespace, // NamespaceStmtNode namespace - // extends - Language, // LanguageStmtNode language ; - Package, // PackageStmtNode package - Debugger // ExprStmtNode debugger ; - }; - - private: - Kind kind; // The node's kind - public: - StmtNode *next; // Next statement in a linked list of statements in - // this block - - StmtNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind), next(0) {} - - Kind getKind() const {return kind;} - bool hasKind(Kind k) const {return kind == k;} - - static void printStatements(PrettyPrinter &f, - const StmtNode *statements); - static void printBlockStatements(PrettyPrinter &f, - const StmtNode *statements, bool loose); - static void printSemi(PrettyPrinter &f, bool noSemi); - void printSubstatement(PrettyPrinter &f, bool noSemi, - const char *continuation = 0) const; - virtual void print(PrettyPrinter &f, bool noSemi) const; - }; - - - struct ExprStmtNode: StmtNode { - ExprNode *expr; // The expression statement's expression. - // May be nil for default: or - // return-with-no-expression statements. - - ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr) : - StmtNode(pos, kind), expr(expr) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct DebuggerStmtNode: StmtNode { - DebuggerStmtNode(uint32 pos, Kind kind): StmtNode(pos, kind) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct IdentifierList: ArenaObject { - IdentifierList *next; // Next identifier in linked list - const StringAtom &name; // The identifier - - explicit IdentifierList(const StringAtom &name): next(0), name(name) {} - bool contains(Token::Kind kind); - }; - - struct AttributeStmtNode: StmtNode { - IdentifierList *attributes; // Linked list of block or definition's - // attributes - - AttributeStmtNode(uint32 pos, Kind kind, IdentifierList *attributes) : - StmtNode(pos, kind), attributes(attributes) {} - - void printAttributes(PrettyPrinter &f) const; - }; - - struct BlockStmtNode: AttributeStmtNode { - StmtNode *statements; // Linked list of block's statements - - BlockStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, - StmtNode *statements) : - AttributeStmtNode(pos, kind, attributes), statements(statements) - {} - - void print(PrettyPrinter &f, bool noSemi) const; - void printBlock(PrettyPrinter &f, bool loose) const; - }; - - struct LabelStmtNode: StmtNode { - const StringAtom &name; // The label - StmtNode *stmt; // Labeled statement; non-nil only - - LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt) : - StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct UnaryStmtNode: ExprStmtNode { - StmtNode *stmt; // First substatement; non-nil only - - UnaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt): - ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);} - - void print(PrettyPrinter &f, bool noSemi) const; - virtual void printContents(PrettyPrinter &f, bool noSemi) const; - }; - - struct BinaryStmtNode: UnaryStmtNode { - StmtNode *stmt2; // Second substatement; non-nil only - - BinaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt1, - StmtNode *stmt2) : - UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) { - ASSERT(stmt2); - } - - void printContents(PrettyPrinter &f, bool noSemi) const; - }; - - struct ForStmtNode: StmtNode { - StmtNode *initializer; // For: First item in parentheses; - // either nil (if not provided), an - // expression, or a Var, or a Const. - // ForIn: Expression or declaration - // before 'in'; either an expression, - // or a Var or a Const with exactly one - // binding. - ExprNode *expr2; // For: Second item in parentheses; nil - // if not provided - // ForIn: Subexpression after 'in'; - // non-nil only - ExprNode *expr3; // For: Third item in parentheses; nil - // if not provided - // ForIn: nil - StmtNode *stmt; // Substatement; non-nil only - - ForStmtNode(uint32 pos, Kind kind, StmtNode *initializer, - ExprNode *expr2, ExprNode *expr3, StmtNode *stmt) : - StmtNode(pos, kind), initializer(initializer), expr2(expr2), - expr3(expr3), stmt(stmt) { - ASSERT(stmt); - } - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct SwitchStmtNode: ExprStmtNode { - StmtNode *statements; // Linked list of switch block's - // statements, which may include Case - // and Default statements - - SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements) : - ExprStmtNode(pos, Switch, expr), statements(statements) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct GoStmtNode: StmtNode { - const StringAtom *name; // The label; nil if none - - GoStmtNode(uint32 pos, Kind kind, const StringAtom *name) : - StmtNode(pos, kind), name(name) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct CatchClause: ParseNode { - CatchClause *next; // Next catch clause in a linked list of - // catch clauses - const StringAtom &name; // The name of the variable that will - // hold the exception - ExprNode *type; // Type expression or nil if not provided - StmtNode *stmt; // The catch clause's body; non-nil only - - CatchClause(uint32 pos, const StringAtom &name, ExprNode *type, - StmtNode *stmt) : - ParseNode(pos), next(0), name(name), type(type), stmt(stmt) { - ASSERT(stmt); - } - }; - - struct TryStmtNode: StmtNode { - StmtNode *stmt; // Substatement being tried; usually a - // block; non-nil only - CatchClause *catches; // Linked list of catch blocks; may be - // nil - StmtNode *finally; // Finally block or nil if none - - TryStmtNode(uint32 pos, StmtNode *stmt, CatchClause *catches, - StmtNode *finally) : - StmtNode(pos, Try), stmt(stmt), catches(catches), - finally(finally) { - ASSERT(stmt); - } - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct PackageName: ArenaObject { // Either idList or str may be null, but - // not both - IdentifierList *idList; // The package name as an identifier list - String *str; // The package name as a string - - explicit PackageName(IdentifierList *idList): idList(idList), str(0) { - ASSERT(idList); - } - explicit PackageName(String &str): idList(0), str(&str) {} - }; - - struct ImportBinding: ParseNode { - ImportBinding *next; // Next binding in a linked list of - // import bindings - const StringAtom *name; // The package variable's name; nil if - // omitted - PackageName &packageName; // The package's name - - ImportBinding(uint32 pos, const StringAtom *name, - PackageName &packageName): - ParseNode(pos), next(0), name(name), packageName(packageName) {} - }; - - struct ImportStmtNode: StmtNode { - ImportBinding *bindings; // Linked list of import bindings - - ImportStmtNode(uint32 pos, Kind kind, ImportBinding *bindings) : - StmtNode(pos, kind), bindings(bindings) {} - }; - - struct ExprList: ArenaObject { - ExprList *next; // Next expression in linked list - ExprNode *expr; // Attribute expression; non-nil only - - explicit ExprList(ExprNode *expr): next(0), expr(expr) {ASSERT(expr);} - - void printCommaList(PrettyPrinter &f) const; - static void printOptionalCommaList(PrettyPrinter &f, const char *name, - const ExprList *list); - }; - - struct UseStmtNode: StmtNode { - ExprList *exprs; // Linked list of namespace expressions - - UseStmtNode(uint32 pos, Kind kind, ExprList *exprs) : - StmtNode(pos, kind), exprs(exprs) {} - }; - - struct ExportBinding: ParseNode { - ExportBinding *next; // Next binding in a linked list of - // export bindings - FunctionName name; // The exported variable's name - FunctionName *initializer; // The original variable's name or nil - // if not provided - - ExportBinding(uint32 pos, FunctionName *initializer) : - ParseNode(pos), next(0), initializer(initializer) {} - }; - - struct ExportStmtNode: AttributeStmtNode { - ExportBinding *bindings; // Linked list of export bindings - - ExportStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, - ExportBinding *bindings) : - AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} - }; - - struct VariableStmtNode: AttributeStmtNode { - VariableBinding *bindings; // Linked list of variable bindings - - VariableStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, - VariableBinding *bindings): - AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct FunctionStmtNode: AttributeStmtNode { - FunctionDefinition function; // Function definition - - FunctionStmtNode(uint32 pos, Kind kind, IdentifierList *attributes) : - AttributeStmtNode(pos, kind, attributes) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct NamespaceStmtNode: AttributeStmtNode { - ExprNode *name; // The namespace's, interfaces, or - // class's name; non-nil only - ExprList *supers; // Linked list of supernamespace or - // superinterface expressions - - NamespaceStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, - ExprNode *name, ExprList *supers) : - AttributeStmtNode(pos, kind, attributes), name(name), - supers(supers) { - ASSERT(name); - } - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct ClassStmtNode: NamespaceStmtNode { - ExprNode *superclass; // Superclass expression (classes only); - // nil if omitted - BlockStmtNode *body; // The class's body; nil if omitted - - ClassStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, - ExprNode *name, ExprNode *superclass, - ExprList *superinterfaces, BlockStmtNode *body) : - NamespaceStmtNode(pos, kind, attributes, name, superinterfaces), - superclass(superclass), body(body) {} - - void print(PrettyPrinter &f, bool noSemi) const; - }; - - struct LanguageStmtNode: StmtNode { - JavaScript::Language language; // The selected language - - LanguageStmtNode(uint32 pos, Kind kind, JavaScript::Language language): - StmtNode(pos, kind), language(language) {} - }; - - struct PackageStmtNode: StmtNode { - PackageName &packageName; // The package's name - BlockStmtNode *body; // The package's body; non-nil only - - PackageStmtNode(uint32 pos, Kind kind, PackageName &packageName, - BlockStmtNode *body) : - StmtNode(pos, kind), packageName(packageName), body(body) { - ASSERT(body); - } - }; - - - class Parser { - public: - Lexer lexer; - Arena &arena; - bool lineBreaksSignificant; // If false, line breaks between tokens - // are treated as though they were - // spaces instead - - Parser(World &world, Arena &arena, const String &source, - const String &sourceLocation, uint32 initialLineNum = 1); - - private: - Reader &getReader() {return lexer.reader;} - World &getWorld() {return lexer.world;} - - public: - void syntaxError(const char *message, uint backUp = 1); - void syntaxError(const String &message, uint backUp = 1); - const Token &require(bool preferRegExp, Token::Kind kind); - private: - String ©TokenChars(const Token &t); - bool lineBreakBefore(const Token &t) const { - return lineBreaksSignificant && t.getLineBreak(); - } - bool lineBreakBefore() { - return lineBreaksSignificant && lexer.peek(true).getLineBreak(); - } - - ExprNode *makeIdentifierExpression(const Token &t) const; - ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, - bool preferRegExp); - ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, - bool &foundQualifiers, - bool preferRegExp); - ExprNode *parseQualifiedIdentifier(const Token &t, bool preferRegExp); - PairListExprNode *parseArrayLiteral(const Token &initialToken); - PairListExprNode *parseObjectLiteral(const Token &initialToken); - ExprNode *parsePrimaryExpression(); - BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, - ExprNode::Kind kind, - ExprNode::Kind parenKind); - InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, - Token::Kind closingTokenKind, - ExprNode::Kind invokeKind); - ExprNode *parsePostfixExpression(bool newExpression = false); - void ensurePostfix(const ExprNode *e); - ExprNode *parseUnaryExpression(); - - enum Precedence { - pNone, // End tag - pExpression, // Expression - pAssignment, // AssignmentExpression - pConditional, // ConditionalExpression - pLogicalOr, // LogicalOrExpression - pLogicalXor, // LogicalXorExpression - pLogicalAnd, // LogicalAndExpression - pBitwiseOr, // BitwiseOrExpression - pBitwiseXor, // BitwiseXorExpression - pBitwiseAnd, // BitwiseAndExpression - pEquality, // EqualityExpression - pRelational, // RelationalExpression - pShift, // ShiftExpression - pAdditive, // AdditiveExpression - pMultiplicative, // MultiplicativeExpression - pUnary, // UnaryExpression - pPostfix // PostfixExpression - }; - - struct BinaryOperatorInfo { - ExprNode::Kind kind; // The kind of BinaryExprNode the - // operator should generate; - // ExprNode::none if not a binary - // operator - Precedence precedenceLeft; // Operators in this operator's left - // subexpression with precedenceLeft or - // higher are reduced - Precedence precedenceRight; // This operator's precedence - }; - - static const BinaryOperatorInfo tokenBinaryOperatorInfos[Token::kindsEnd]; - struct StackedSubexpression; - - public: - ExprNode *parseExpression(bool noIn, bool noAssignment = false, - bool noComma = false); - ExprNode *parseNonAssignmentExpression(bool noIn) { - return parseExpression(noIn, true, true); - } - ExprNode *parseAssignmentExpression(bool noIn=false) { - return parseExpression(noIn, false, true); - } - - private: - ExprNode *parseParenthesizedExpression(); - ExprNode *parseTypeExpression(bool noIn=false); - const StringAtom &parseTypedIdentifier(ExprNode *&type); - ExprNode *parseTypeBinding(Token::Kind kind, bool noIn); - ExprList *parseTypeListBinding(Token::Kind kind); - VariableBinding *parseVariableBinding(bool noQualifiers, bool noIn, - bool constant); - void parseFunctionName(FunctionName &fn); - void parseFunctionSignature(FunctionDefinition &fd); - - enum SemicolonState {semiNone, semiNoninsertable, semiInsertable}; - enum AttributeStatement {asAny, asBlock, asConstVar}; - StmtNode *parseBlock(bool inSwitch, bool noCloseBrace); - BlockStmtNode *parseBody(SemicolonState *semicolonState); - ExprNode::Kind validateOperatorName(const Token &name); - StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, - const Token &t, bool noIn, - SemicolonState &semicolonState); - StmtNode *parseAttributesAndStatement(const Token *t, - AttributeStatement as, - SemicolonState &semicolonState); - StmtNode *parseAnnotatedBlock(); - StmtNode *parseFor(uint32 pos, SemicolonState &semicolonState); - StmtNode *parseTry(uint32 pos); - - public: - StmtNode *parseStatement(bool topLevel, bool inSwitch, - SemicolonState &semicolonState); - StmtNode *parseStatementAndSemicolon(SemicolonState &semicolonState); - StmtNode *parseProgram() {return parseBlock(false, true);} - - private: - bool lookahead(Token::Kind kind,bool preferRegExp=true); - const Token *match(Token::Kind kind, bool preferRegExp=true); - ExprNode *parseIdentifier(); - ExprPairList *parseLiteralField(); - ExprNode *parseFieldName(); - ExprPairList *parseArgumentList(NodeQueue &args); - ExprPairList *parseArgumentListPrime(NodeQueue &args); - ExprPairList *parseNamedArgumentListPrime(NodeQueue &args); - VariableBinding *parseAllParameters(FunctionDefinition &fd, - NodeQueue ¶ms); - VariableBinding *parseNamedParameters(FunctionDefinition &fd, - NodeQueue ¶ms); - VariableBinding *parseRestParameter(); - VariableBinding *parseParameter(); - VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd, - NodeQueue ¶ms); - VariableBinding *parseNamedRestParameters(FunctionDefinition &fd, - NodeQueue ¶ms); - VariableBinding *parseOptionalParameter(); - VariableBinding *parseOptionalParameterPrime(VariableBinding* binding); - VariableBinding *parseNamedParameter(NodeQueue &aliases); - ExprNode *parseResultSignature(); - }; + template + class NodeQueue { + public: + N *first; // Head of queue + private: + N **last; // Next link of last element of queue + + public: + NodeQueue(): first(0), last(&first) {} + private: + NodeQueue(const NodeQueue&); // No copy constructor + void operator=(const NodeQueue&); // No assignment operator + public: + void operator+=(N *elt) { + ASSERT(elt && !elt->next); *last = elt; last = &elt->next; + } + }; + + + struct ExprNode; + struct AttributeStmtNode; + struct BlockStmtNode; + + + struct VariableBinding: ParseNode { + VariableBinding *next; // Next binding in a linked list of variable or parameter bindings + ExprNode *name; // The variable's name; + // nil if omitted, which currently can only happen for ... parameters + ExprNode *type; // Type expression or nil if not provided + ExprNode *initializer; // Initial value expression or nil if not provided + bool constant; // true for const variables and parameters + VariableBinding(uint32 pos, ExprNode *name, ExprNode *type, ExprNode *initializer, bool constant): + ParseNode(pos), next(0), name(name), type(type), initializer(initializer), constant(constant) {} + + void print(PrettyPrinter &f, bool printConst) const; + }; + + + struct ExprNode: ParseNode { + // Keep synchronized with kindNames and simpleLookup + enum Kind { // Actual class Operands + none, + identifier, // IdentifierExprNode + + // Begin of isPostfix() + number, // NumberExprNode + string, // StringExprNode + regExp, // RegExpExprNode // + Null, // ExprNode null + True, // ExprNode true + False, // ExprNode false + This, // ExprNode this + + parentheses, // UnaryExprNode () + numUnit, // NumUnitExprNode "" or + exprUnit, // ExprUnitExprNode () "" or + qualify, // BinaryExprNode :: ( must be identifier) + + objectLiteral, // PairListExprNode {:, :, ..., :} + arrayLiteral, // PairListExprNode [, , ..., ] + functionLiteral, // FunctionExprNode function + + call, // InvokeExprNode (:, :, ..., :) + New, // InvokeExprNode new (:, :, ..., :) + index, // InvokeExprNode [:, :, ..., :] + + dot, // BinaryExprNode . ( must be identifier or qualify) + dotClass, // UnaryExprNode .class + dotParen, // BinaryExprNode .( ) + // End of isPostfix() + + superExpr, // SuperExprNode super or super() + superStmt, // InvokeExprNode super(:, :, ..., :) + // A superStmt will only appear at the top level of an expression StmtNode. + + Const, // UnaryExprNode const + Delete, // UnaryExprNode delete + Void, // UnaryExprNode void + Typeof, // UnaryExprNode typeof + preIncrement, // UnaryExprNode ++ + preDecrement, // UnaryExprNode -- + postIncrement, // UnaryExprNode ++ + postDecrement, // UnaryExprNode -- + plus, // UnaryExprNode + + minus, // UnaryExprNode - + complement, // UnaryExprNode ~ + logicalNot, // UnaryExprNode ! + + add, // BinaryExprNode + + subtract, // BinaryExprNode - + multiply, // BinaryExprNode * + divide, // BinaryExprNode / + modulo, // BinaryExprNode % + leftShift, // BinaryExprNode << + rightShift, // BinaryExprNode >> + logicalRightShift, // BinaryExprNode >>> + bitwiseAnd, // BinaryExprNode & + bitwiseXor, // BinaryExprNode ^ + bitwiseOr, // BinaryExprNode | + logicalAnd, // BinaryExprNode && + logicalXor, // BinaryExprNode ^^ + logicalOr, // BinaryExprNode || + + equal, // BinaryExprNode == + notEqual, // BinaryExprNode != + lessThan, // BinaryExprNode < + lessThanOrEqual, // BinaryExprNode <= + greaterThan, // BinaryExprNode > + greaterThanOrEqual, // BinaryExprNode >= + identical, // BinaryExprNode === + notIdentical, // BinaryExprNode !== + As, // BinaryExprNode as + In, // BinaryExprNode in + Instanceof, // BinaryExprNode instanceof + + assignment, // BinaryExprNode = + + // Begin of isAssigningKind() + addEquals, // BinaryExprNode += + subtractEquals, // BinaryExprNode -= + multiplyEquals, // BinaryExprNode *= + divideEquals, // BinaryExprNode /= + moduloEquals, // BinaryExprNode %= + leftShiftEquals, // BinaryExprNode <<= + rightShiftEquals, // BinaryExprNode >>= + logicalRightShiftEquals, // BinaryExprNode >>>= + bitwiseAndEquals, // BinaryExprNode &= + bitwiseXorEquals, // BinaryExprNode ^= + bitwiseOrEquals, // BinaryExprNode |= + logicalAndEquals, // BinaryExprNode &&= + logicalXorEquals, // BinaryExprNode ^^= + logicalOrEquals, // BinaryExprNode ||= + // End of isAssigningKind() + + conditional, // TernaryExprNode ? : + comma, // BinaryExprNode , (Comma expressions only) + + kindsEnd + }; + + private: + Kind kind; // The node's kind + static const char *const kindNames[kindsEnd]; + public: + + ExprNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind) {} + + Kind getKind() const {return kind;} + bool hasKind(Kind k) const {return kind == k;} + + static bool isAssigningKind(Kind kind) {return kind >= assignment && kind <= logicalOrEquals;} + static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];} + bool isPostfix() const {return kind >= identifier && kind <= dotParen;} + + virtual void print(PrettyPrinter &f) const; + friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;} + }; + + // Print e onto f. + inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) { + ASSERT(e); e->print(f); return f; + } + + + struct FunctionName { + enum Prefix { + normal, // No prefix + Get, // get + Set // set + }; + + Prefix prefix; // The name's prefix, if any + ExprNode *name; // The name; nil if omitted + + FunctionName(): prefix(normal), name(0) {} + + void print(PrettyPrinter &f) const; + }; + + + struct FunctionDefinition: FunctionName { + VariableBinding *parameters; // Linked list of all parameters, including optional and rest parameters, if any + VariableBinding *optParameters; // Pointer to first non-required parameter inside parameters list; nil if none + VariableBinding *namedParameters; // The first parameter after the named parameter marker. May or may not have aliases. + VariableBinding *restParameter; // Pointer to rest parameter inside parameters list; nil if none + ExprNode *resultType; // Result type expression or nil if not provided + BlockStmtNode *body; // Body; nil if none + + void print(PrettyPrinter &f, const AttributeStmtNode *attributes, bool noSemi) const; + }; + + + struct IdentifierExprNode: ExprNode { + const StringAtom &name; // The identifier + + IdentifierExprNode(uint32 pos, Kind kind, const StringAtom &name): ExprNode(pos, kind), name(name) {} + explicit IdentifierExprNode(const Token &t): ExprNode(t.getPos(), identifier), name(t.getIdentifier()) {} + + void print(PrettyPrinter &f) const; + }; + + struct NumberExprNode: ExprNode { + float64 value; // The number's value + + NumberExprNode(uint32 pos, float64 value): ExprNode(pos, number), value(value) {} + explicit NumberExprNode(const Token &t): ExprNode(t.getPos(), number), value(t.getValue()) {} + + void print(PrettyPrinter &f) const; + }; + + struct StringExprNode: ExprNode { + String &str; // The string + + StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {} + + void print(PrettyPrinter &f) const; + }; + + struct RegExpExprNode: ExprNode { + const StringAtom &re; // The regular expression's contents + String &flags; // The regular expression's flags + + RegExpExprNode(uint32 pos, Kind kind, const StringAtom &re, String &flags): + ExprNode(pos, kind), re(re), flags(flags) {} + + void print(PrettyPrinter &f) const; + }; + + struct NumUnitExprNode: StringExprNode { // str is the unit string + String &numStr; // The number's source string + float64 num; // The number's value + + NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num, String &unitStr): + StringExprNode(pos, kind, unitStr), numStr(numStr), num(num) {} + + void print(PrettyPrinter &f) const; + }; + + struct ExprUnitExprNode: StringExprNode { // str is the unit string + ExprNode *op; // The expression to which the unit is applied; non-nil only + + ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr): + StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);} + + void print(PrettyPrinter &f) const; + }; + + struct FunctionExprNode: ExprNode { + FunctionDefinition function; // Function definition + + explicit FunctionExprNode(uint32 pos): ExprNode(pos, functionLiteral) {} + + void print(PrettyPrinter &f) const; + }; + + struct ExprPairList: ArenaObject { + ExprPairList *next; // Next pair in linked list + ExprNode *field; // Field expression or nil if not provided + ExprNode *value; // Value expression or nil if not provided + + explicit ExprPairList(ExprNode *field = 0, ExprNode *value = 0): next(0), field(field), value(value) {} + }; + + struct PairListExprNode: ExprNode { + ExprPairList *pairs; // Linked list of pairs + + PairListExprNode(uint32 pos, Kind kind, ExprPairList *pairs): ExprNode(pos, kind), pairs(pairs) {} + + void print(PrettyPrinter &f) const; + }; + + struct InvokeExprNode: PairListExprNode { + ExprNode *op; // The called function, called constructor, or indexed object; nil only for superStmt + + InvokeExprNode(uint32 pos, Kind kind, ExprNode *op, ExprPairList *pairs): + PairListExprNode(pos, kind, pairs), op(op) {ASSERT(op || kind == superStmt);} + + void print(PrettyPrinter &f) const; + }; + + struct SuperExprNode: ExprNode { + ExprNode *op; // The operand or nil if none + + SuperExprNode(uint32 pos, ExprNode *op): ExprNode(pos, superExpr), op(op) {} + + void print(PrettyPrinter &f) const; + }; + + struct UnaryExprNode: ExprNode { + ExprNode *op; // The unary operator's operand; non-nil only + + UnaryExprNode(uint32 pos, Kind kind, ExprNode *op): ExprNode(pos, kind), op(op) {ASSERT(op);} + + void print(PrettyPrinter &f) const; + }; + + struct BinaryExprNode: ExprNode { + ExprNode *op1; // The binary operator's first operand; non-nil only + ExprNode *op2; // The binary operator's second operand; non-nil only + + BinaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2): + ExprNode(pos, kind), op1(op1), op2(op2) {ASSERT(op1 && op2);} + + void print(PrettyPrinter &f) const; + }; + + struct TernaryExprNode: ExprNode { + ExprNode *op1; // The ternary operator's first operand; non-nil only + ExprNode *op2; // The ternary operator's second operand; non-nil only + ExprNode *op3; // The ternary operator's third operand; non-nil only + + TernaryExprNode(uint32 pos, Kind kind, ExprNode *op1, ExprNode *op2, ExprNode *op3): + ExprNode(pos, kind), op1(op1), op2(op2), op3(op3) {ASSERT(op1 && op2 && op3);} + + void print(PrettyPrinter &f) const; + }; + + + struct StmtNode: ParseNode { + enum Kind { // Actual class Operands + empty, // StmtNode ; + expression, // ExprStmtNode ; + block, // BlockStmtNode { } + label, // LabelStmtNode : + If, // UnaryStmtNode if ( ) + IfElse, // BinaryStmtNode if ( ) else + Switch, // SwitchStmtNode switch ( ) + While, // UnaryStmtNode while ( ) + DoWhile, // UnaryStmtNode do while ( ) + With, // UnaryStmtNode with ( ) + For, // ForStmtNode for ( ; ; ) + ForIn, // ForStmtNode for ( in ) + Case, // ExprStmtNode case : or default : + // Only occurs directly inside a Switch + Break, // GoStmtNode break ; or break ; + Continue, // GoStmtNode continue ; or continue ; + Return, // ExprStmtNode return ; or return ; + Throw, // ExprStmtNode throw ; + Try, // TryStmtNode try + Import, // ImportStmtNode import ; + UseImport, // ImportStmtNode use import ; + Use, // UseStmtNode use namespace ; + Export, // ExportStmtNode export ; + Const, // VariableStmtNode const ; + Var, // VariableStmtNode var ; + Function, // FunctionStmtNode function + Class, // ClassStmtNode class extends implements + Interface, // ClassStmtNode interface extends + Namespace, // NamespaceStmtNode namespace extends + Language, // LanguageStmtNode language ; + Package, // PackageStmtNode package + Debugger // ExprStmtNode debugger ; + }; + + private: + Kind kind; // The node's kind + public: + StmtNode *next; // Next statement in a linked list of statements in this block + + StmtNode(uint32 pos, Kind kind): ParseNode(pos), kind(kind), next(0) {} + + Kind getKind() const {return kind;} + bool hasKind(Kind k) const {return kind == k;} + + static void printStatements(PrettyPrinter &f, const StmtNode *statements); + static void printBlockStatements(PrettyPrinter &f, const StmtNode *statements, bool loose); + static void printSemi(PrettyPrinter &f, bool noSemi); + void printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation = 0) const; + virtual void print(PrettyPrinter &f, bool noSemi) const; + }; + + + struct ExprList: ArenaObject { + ExprList *next; // Next expression in linked list + ExprNode *expr; // Attribute expression; non-nil only + + explicit ExprList(ExprNode *expr): next(0), expr(expr) {ASSERT(expr);} + + void printCommaList(PrettyPrinter &f) const; + static void printOptionalCommaList(PrettyPrinter &f, const char *name, const ExprList *list); + }; + + + struct ExprStmtNode: StmtNode { + ExprNode *expr; // The expression statement's expression. May be nil for default: or return-with-no-expression statements. + + ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr): StmtNode(pos, kind), expr(expr) {} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct DebuggerStmtNode: StmtNode { + DebuggerStmtNode(uint32 pos, Kind kind): StmtNode(pos, kind) {} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct AttributeStmtNode: StmtNode { + ExprList *attributes; // Linked list of block or definition's attributes + + AttributeStmtNode(uint32 pos, Kind kind, ExprList *attributes): StmtNode(pos, kind), attributes(attributes) {} + + void printAttributes(PrettyPrinter &f) const; + }; + + struct BlockStmtNode: AttributeStmtNode { + StmtNode *statements; // Linked list of block's statements + + BlockStmtNode(uint32 pos, Kind kind, ExprList *attributes, StmtNode *statements): + AttributeStmtNode(pos, kind, attributes), statements(statements) {} + + void print(PrettyPrinter &f, bool noSemi) const; + void printBlock(PrettyPrinter &f, bool loose) const; + }; + + struct LabelStmtNode: StmtNode { + const StringAtom &name; // The label + StmtNode *stmt; // Labeled statement; non-nil only + + LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt): + StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct UnaryStmtNode: ExprStmtNode { + StmtNode *stmt; // First substatement; non-nil only + + UnaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt): + ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);} + + void print(PrettyPrinter &f, bool noSemi) const; + virtual void printContents(PrettyPrinter &f, bool noSemi) const; + }; + + struct BinaryStmtNode: UnaryStmtNode { + StmtNode *stmt2; // Second substatement; non-nil only + + BinaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt1, StmtNode *stmt2): + UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) {ASSERT(stmt2);} + + void printContents(PrettyPrinter &f, bool noSemi) const; + }; + + struct ForStmtNode: StmtNode { + StmtNode *initializer; // For: First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const. + // ForIn: Expression or declaration before 'in'; either an expression, + // or a Var or a Const with exactly one binding. + ExprNode *expr2; // For: Second item in parentheses; nil if not provided + // ForIn: Subexpression after 'in'; non-nil only + ExprNode *expr3; // For: Third item in parentheses; nil if not provided + // ForIn: nil + StmtNode *stmt; // Substatement; non-nil only + + ForStmtNode(uint32 pos, Kind kind, StmtNode *initializer, ExprNode *expr2, ExprNode *expr3, StmtNode *stmt): + StmtNode(pos, kind), initializer(initializer), expr2(expr2), expr3(expr3), stmt(stmt) {ASSERT(stmt);} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct SwitchStmtNode: ExprStmtNode { + StmtNode *statements; // Linked list of switch block's statements, which may include Case and Default statements + + SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements): + ExprStmtNode(pos, Switch, expr), statements(statements) {} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct GoStmtNode: StmtNode { + const StringAtom *name; // The label; nil if none + + GoStmtNode(uint32 pos, Kind kind, const StringAtom *name): StmtNode(pos, kind), name(name) {} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct CatchClause: ParseNode { + CatchClause *next; // Next catch clause in a linked list of catch clauses + const StringAtom &name; // The name of the variable that will hold the exception + ExprNode *type; // Type expression or nil if not provided + StmtNode *stmt; // The catch clause's body; non-nil only + + CatchClause(uint32 pos, const StringAtom &name, ExprNode *type, StmtNode *stmt): + ParseNode(pos), next(0), name(name), type(type), stmt(stmt) {ASSERT(stmt);} + }; + + struct TryStmtNode: StmtNode { + StmtNode *stmt; // Substatement being tried; usually a block; non-nil only + CatchClause *catches; // Linked list of catch blocks; may be nil + StmtNode *finally; // Finally block or nil if none + + TryStmtNode(uint32 pos, StmtNode *stmt, CatchClause *catches, StmtNode *finally): + StmtNode(pos, Try), stmt(stmt), catches(catches), finally(finally) {ASSERT(stmt);} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct IdentifierList: ArenaObject { + IdentifierList *next; // Next identifier in linked list + const StringAtom &name; // The identifier + + explicit IdentifierList(const StringAtom &name): next(0), name(name) {} + }; + + struct PackageName: ArenaObject { // Either idList or str may be null, but not both + IdentifierList *idList; // The package name as an identifier list + String *str; // The package name as a string + + explicit PackageName(IdentifierList *idList): idList(idList), str(0) {ASSERT(idList);} + explicit PackageName(String &str): idList(0), str(&str) {} + }; + + struct ImportBinding: ParseNode { + ImportBinding *next; // Next binding in a linked list of import bindings + const StringAtom *name; // The package variable's name; nil if omitted + PackageName &packageName; // The package's name + + ImportBinding(uint32 pos, const StringAtom *name, PackageName &packageName): + ParseNode(pos), next(0), name(name), packageName(packageName) {} + }; + + struct ImportStmtNode: StmtNode { + ImportBinding *bindings; // Linked list of import bindings + + ImportStmtNode(uint32 pos, Kind kind, ImportBinding *bindings): + StmtNode(pos, kind), bindings(bindings) {} + }; + + struct UseStmtNode: StmtNode { + ExprList *exprs; // Linked list of namespace expressions + + UseStmtNode(uint32 pos, Kind kind, ExprList *exprs): StmtNode(pos, kind), exprs(exprs) {} + }; + + struct ExportBinding: ParseNode { + ExportBinding *next; // Next binding in a linked list of export bindings + FunctionName name; // The exported variable's name + FunctionName *initializer; // The original variable's name or nil if not provided + + ExportBinding(uint32 pos, FunctionName *initializer): + ParseNode(pos), next(0), initializer(initializer) {} + }; + + struct ExportStmtNode: AttributeStmtNode { + ExportBinding *bindings; // Linked list of export bindings + + ExportStmtNode(uint32 pos, Kind kind, ExprList *attributes, ExportBinding *bindings): + AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} + }; + + struct VariableStmtNode: AttributeStmtNode { + VariableBinding *bindings; // Linked list of variable bindings + + VariableStmtNode(uint32 pos, Kind kind, ExprList *attributes, VariableBinding *bindings): + AttributeStmtNode(pos, kind, attributes), bindings(bindings) {} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct FunctionStmtNode: AttributeStmtNode { + FunctionDefinition function; // Function definition + + FunctionStmtNode(uint32 pos, Kind kind, ExprList *attributes): AttributeStmtNode(pos, kind, attributes) {} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct NamespaceStmtNode: AttributeStmtNode { + ExprNode *name; // The namespace's, interfaces, or class's name; non-nil only + ExprList *supers; // Linked list of supernamespace or superinterface expressions + + NamespaceStmtNode(uint32 pos, Kind kind, ExprList *attributes, ExprNode *name, ExprList *supers): + AttributeStmtNode(pos, kind, attributes), name(name), supers(supers) {ASSERT(name);} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct ClassStmtNode: NamespaceStmtNode { + ExprNode *superclass; // Superclass expression (classes only); nil if omitted + BlockStmtNode *body; // The class's body; nil if omitted + + ClassStmtNode(uint32 pos, Kind kind, ExprList *attributes, ExprNode *name, ExprNode *superclass, + ExprList *superinterfaces, BlockStmtNode *body): + NamespaceStmtNode(pos, kind, attributes, name, superinterfaces), superclass(superclass), body(body) {} + + void print(PrettyPrinter &f, bool noSemi) const; + }; + + struct LanguageStmtNode: StmtNode { + JavaScript::Language language; // The selected language + + LanguageStmtNode(uint32 pos, Kind kind, JavaScript::Language language): + StmtNode(pos, kind), language(language) {} + }; + + struct PackageStmtNode: StmtNode { + PackageName &packageName; // The package's name + BlockStmtNode *body; // The package's body; non-nil only + + PackageStmtNode(uint32 pos, Kind kind, PackageName &packageName, BlockStmtNode *body): + StmtNode(pos, kind), packageName(packageName), body(body) {ASSERT(body);} + }; + + + class Parser { + public: + Lexer lexer; + Arena &arena; + bool lineBreaksSignificant; // If false, line breaks between tokens are treated as though they were spaces instead + + Parser(World &world, Arena &arena, const String &source, const String &sourceLocation, uint32 initialLineNum = 1); + + private: + Reader &getReader() {return lexer.reader;} + World &getWorld() {return lexer.world;} + + public: + void syntaxError(const char *message, uint backUp = 1); + void syntaxError(const String &message, uint backUp = 1); + const Token &require(bool preferRegExp, Token::Kind kind); + private: + String ©TokenChars(const Token &t); + bool lineBreakBefore(const Token &t) const {return lineBreaksSignificant && t.getLineBreak();} + bool lineBreakBefore() {return lineBreaksSignificant && lexer.peek(true).getLineBreak();} + + enum SuperState { + ssNone, // No super operator + ssExpr, // super or super(expr) + ssStmt // super or super(expr) or super(arguments) + }; + + enum Precedence { + pNone, // End tag + pExpression, // ListExpression + pAssignment, // AssignmentExpression + pConditional, // ConditionalExpression + pLogicalOr, // LogicalOrExpression + pLogicalXor, // LogicalXorExpression + pLogicalAnd, // LogicalAndExpression + pBitwiseOr, // BitwiseOrExpression + pBitwiseXor, // BitwiseXorExpression + pBitwiseAnd, // BitwiseAndExpression + pEquality, // EqualityExpression + pRelational, // RelationalExpression + pShift, // ShiftExpression + pAdditive, // AdditiveExpression + pMultiplicative, // MultiplicativeExpression + pUnary, // UnaryExpression + pPostfix // PostfixExpression + }; + + struct BinaryOperatorInfo { + ExprNode::Kind kind; // The kind of BinaryExprNode the operator should generate; + // ExprNode::none if not a binary operator + Precedence precedenceLeft; // Operators in this operator's left subexpression with precedenceLeft or higher are reduced + Precedence precedenceRight; // This operator's precedence + bool superLeft; // True if the left operand can be a SuperExpression + }; + + static const BinaryOperatorInfo tokenBinaryOperatorInfos[Token::kindsEnd]; + struct StackedSubexpression; + + ExprNode *makeIdentifierExpression(const Token &t) const; + ExprNode *parseIdentifier(); + ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp); + ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool noComma, bool &foundQualifiers, bool preferRegExp); + ExprNode *parseQualifiedIdentifier(const Token &t, bool preferRegExp); + PairListExprNode *parseArrayLiteral(const Token &initialToken); + PairListExprNode *parseObjectLiteral(const Token &initialToken); + ExprNode *parseUnitSuffixes(ExprNode *e); + ExprNode *parseSuper(uint32 pos, SuperState superState); + ExprNode *parsePrimaryExpression(SuperState superState); + ExprNode *parseMember(ExprNode *target, const Token &tOperator, bool preferRegExp); + InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind); + ExprNode *parsePostfixOperator(ExprNode *e, bool newExpression, bool attribute); + ExprNode *parsePostfixExpression(SuperState superState, bool newExpression); + void ensurePostfix(const ExprNode *e); + ExprNode *parseAttribute(const Token &t); + static bool expressionIsAttribute(const ExprNode *e); + ExprNode *parseUnaryExpression(SuperState superState); + ExprNode *parseGeneralExpression(bool allowSuperStmt, bool noIn, bool noAssignment, bool noComma); + public: + ExprNode *parseListExpression(bool noIn) {return parseGeneralExpression(false, noIn, false, false);} + ExprNode *parseAssignmentExpression(bool noIn) {return parseGeneralExpression(false, noIn, false, true);} + ExprNode *parseNonAssignmentExpression(bool noIn) {return parseGeneralExpression(false, noIn, true, true);} + + private: + ExprNode *parseParenthesizedListExpression(); + ExprNode *parseTypeExpression(bool noIn=false); + const StringAtom &parseTypedIdentifier(ExprNode *&type); + ExprNode *parseTypeBinding(Token::Kind kind, bool noIn); + ExprList *parseTypeListBinding(Token::Kind kind); + VariableBinding *parseVariableBinding(bool noQualifiers, bool noIn, bool constant); + void parseFunctionName(FunctionName &fn); + void parseFunctionSignature(FunctionDefinition &fd); + + enum SemicolonState {semiNone, semiNoninsertable, semiInsertable}; + enum AttributeStatement {asAny, asBlock, asConstVar}; + StmtNode *parseBlockContents(bool inSwitch, bool noCloseBrace); + BlockStmtNode *parseBody(SemicolonState *semicolonState); + ExprNode::Kind validateOperatorName(const Token &name); + StmtNode *parseAttributeStatement(uint32 pos, ExprList *attributes, const Token &t, bool noIn, SemicolonState &semicolonState); + StmtNode *parseAttributesAndStatement(uint32 pos, ExprNode *e, AttributeStatement as, SemicolonState &semicolonState); + StmtNode *parseFor(uint32 pos, SemicolonState &semicolonState); + StmtNode *parseTry(uint32 pos); + + public: + StmtNode *parseStatement(bool directive, bool inSwitch, SemicolonState &semicolonState); + StmtNode *parseStatementAndSemicolon(SemicolonState &semicolonState); + StmtNode *parseProgram() {return parseBlockContents(false, true);} + + private: + bool lookahead(Token::Kind kind, bool preferRegExp=true); + const Token *match(Token::Kind kind, bool preferRegExp=true); + ExprPairList *parseLiteralField(); + ExprNode *parseFieldName(); + VariableBinding *parseAllParameters(FunctionDefinition &fd, NodeQueue ¶ms); + VariableBinding *parseNamedParameters(FunctionDefinition &fd, NodeQueue ¶ms); + VariableBinding *parseRestParameter(); + VariableBinding *parseParameter(); + VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd, NodeQueue ¶ms); + VariableBinding *parseNamedRestParameters(FunctionDefinition &fd, NodeQueue ¶ms); + VariableBinding *parseOptionalParameter(); + VariableBinding *parseOptionalParameterPrime(VariableBinding *binding); + VariableBinding *parseNamedParameter(NodeQueue &aliases); + ExprNode *parseResultSignature(); + }; } #endif /* parser_h___ */ diff --git a/mozilla/js2/src/reader.cpp b/mozilla/js2/src/reader.cpp index d28cbb92077..2adf1dd4b66 100644 --- a/mozilla/js2/src/reader.cpp +++ b/mozilla/js2/src/reader.cpp @@ -1,84 +1,82 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include #include "reader.h" -namespace JavaScript -{ +namespace JS = JavaScript; + // Create a Reader reading characters from the source string. // sourceLocation describes the origin of the source and may be used for // error messages. initialLineNum is the line number of the first line of the // source string. - Reader::Reader(const String &source, const String &sourceLocation, - uint32 initialLineNum): - source(source + uni::null), sourceLocation(sourceLocation), - initialLineNum(initialLineNum) - { - begin = p = this->source.data(); - end = begin + this->source.size() - 1; +JS::Reader::Reader(const String &source, const String &sourceLocation, uint32 initialLineNum): + source(source + uni::null), sourceLocation(sourceLocation), initialLineNum(initialLineNum) +{ + begin = p = this->source.data(); + end = begin + this->source.size() - 1; #ifdef DEBUG - recordString = 0; + recordString = 0; #endif - beginLine(); - } + beginLine(); +} + // Mark the beginning of a line. Call this after reading every line break to // fill out the line start table. - void - Reader::beginLine() - { - ASSERT(p <= end && (!linePositions.size() || p > linePositions.back())); - linePositions.push_back(p); - } +void JS::Reader::beginLine() +{ + ASSERT(p <= end && (!linePositions.size() || p > linePositions.back())); + linePositions.push_back(p); +} + // Return the number of the line containing the given character position. // The line starts should have been recorded by calling beginLine. - uint32 - Reader::posToLineNum(uint32 pos) const - { - ASSERT(pos <= getPos()); - std::vector::const_iterator i = - std::upper_bound(linePositions.begin(), linePositions.end(), - begin + pos); - ASSERT(i != linePositions.begin()); - - return static_cast(i-1 - linePositions.begin()) + - initialLineNum; - } - +uint32 JS::Reader::posToLineNum(uint32 pos) const +{ + ASSERT(pos <= getPos()); + std::vector::const_iterator i = + std::upper_bound(linePositions.begin(), linePositions.end(), begin + pos); + ASSERT(i != linePositions.begin()); + + return static_cast(i-1 - linePositions.begin()) + + initialLineNum; +} + + // Return the character position as well as pointers to the beginning and end // (not including the line terminator) of the nth line. If lineNum is out of // range, return 0 and two nulls. The line starts should have been recorded by @@ -86,131 +84,126 @@ namespace JavaScript // manually finds the line ending by searching for a line break; otherwise, // getLine assumes that the line ends one character before the beginning // of the next line. - uint32 - Reader::getLine(uint32 lineNum, const char16 *&lineBegin, - const char16 *&lineEnd) const - { - lineBegin = 0; - lineEnd = 0; - if (lineNum < initialLineNum) - return 0; - lineNum -= initialLineNum; - if (lineNum >= linePositions.size()) - return 0; - lineBegin = linePositions[lineNum]; - - const char16 *e; - ++lineNum; - if (lineNum < linePositions.size()) - e = linePositions[lineNum] - 1; - else { - e = lineBegin; - const char16 *end = Reader::end; - while (e != end && !isLineBreak(*e)) - ++e; - } - lineEnd = e; - return static_cast(lineBegin - begin); +uint32 JS::Reader::getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const +{ + lineBegin = 0; + lineEnd = 0; + if (lineNum < initialLineNum) + return 0; + lineNum -= initialLineNum; + if (lineNum >= linePositions.size()) + return 0; + lineBegin = linePositions[lineNum]; + + const char16 *e; + ++lineNum; + if (lineNum < linePositions.size()) + e = linePositions[lineNum] - 1; + else { + e = lineBegin; + const char16 *end = Reader::end; + while (e != end && !isLineBreak(*e)) + ++e; } - + lineEnd = e; + return static_cast(lineBegin - begin); +} + + // Begin accumulating characters into the recordString, whose initial value is // ignored and cleared. Each character passed to recordChar() is added to the // end of the recordString. Recording ends when endRecord() or beginLine() // is called. Recording is significantly optimized when the characters passed // to readChar() are the same characters as read by get(). In this case the -// record String does not get allocated until endRecord() is called or a +// recorded String does not get allocated until endRecord() is called or a // discrepancy appears between get() and recordChar(). - void - Reader::beginRecording(String &recordString) - { - Reader::recordString = &recordString; - recordBase = p; - recordPos = p; - } +void JS::Reader::beginRecording(String &recordString) +{ + Reader::recordString = &recordString; + recordBase = p; + recordPos = p; +} + // Append ch to the recordString. - void - Reader::recordChar(char16 ch) - { - ASSERT(recordString); - if (recordPos) { - if (recordPos != end && *recordPos == ch) { - recordPos++; - return; - } else { - recordString->assign(recordBase, recordPos); - recordPos = 0; - } +void JS::Reader::recordChar(char16 ch) +{ + ASSERT(recordString); + if (recordPos) { + if (recordPos != end && *recordPos == ch) { + recordPos++; + return; + } else { + recordString->assign(recordBase, recordPos); + recordPos = 0; } - *recordString += ch; } - + *recordString += ch; +} + + // Finish recording characters into the recordString that was last passed to // beginRecording(). Return that recordString. - String & - Reader::endRecording() - { - String *rs = recordString; - ASSERT(rs); - if (recordPos) - rs->assign(recordBase, recordPos); - recordString = 0; - return *rs; - } +JS::String &JS::Reader::endRecording() +{ + String *rs = recordString; + ASSERT(rs); + if (recordPos) + rs->assign(recordBase, recordPos); + recordString = 0; + return *rs; +} + // Report an error at the given character position in the source code. - void - Reader::error(Exception::Kind kind, const String &message, uint32 pos) - { - uint32 lineNum = posToLineNum(pos); - const char16 *lineBegin; - const char16 *lineEnd; - uint32 linePos = getLine(lineNum, lineBegin, lineEnd); - ASSERT(lineBegin && lineEnd && linePos <= pos); - - throw Exception(kind, message, sourceLocation, lineNum, pos - linePos, - pos, lineBegin, lineEnd); - } +void JS::Reader::error(Exception::Kind kind, const String &message, uint32 pos) +{ + uint32 lineNum = posToLineNum(pos); + const char16 *lineBegin; + const char16 *lineEnd; + uint32 linePos = getLine(lineNum, lineBegin, lineEnd); + ASSERT(lineBegin && lineEnd && linePos <= pos); + + throw Exception(kind, message, sourceLocation, lineNum, pos - linePos, pos, lineBegin, lineEnd); +} + // Read a line from the input file, including the trailing line break character. // Return the total number of characters read, which is str's length. // Translate and sequences to characters; a sequence // only counts as one character. - size_t - LineReader::readLine(string &str) - { - int ch; - bool oldCRWasLast = crWasLast; - crWasLast = false; +size_t JS::LineReader::readLine(string &str) +{ + int ch; + bool oldCRWasLast = crWasLast; + crWasLast = false; - str.resize(0); - while ((ch = getc(in)) != EOF) { - if (ch == '\n') { - if (!str.size() && oldCRWasLast) - continue; - str += '\n'; - break; - } - if (ch == '\r') { - crWasLast = true; - str += '\n'; - break; - } - str += static_cast(ch); + str.resize(0); + while ((ch = getc(in)) != EOF) { + if (ch == '\n') { + if (!str.size() && oldCRWasLast) + continue; + str += '\n'; + break; } - - return str.size(); + if (ch == '\r') { + crWasLast = true; + str += '\n'; + break; + } + str += static_cast(ch); } - - size_t - LineReader::readLine(String &wstr) - { - string str; - size_t n = readLine(str); - wstr.resize(n); - std::transform(str.begin(), str.end(), wstr.begin(), widen); - return n; - } - -} /* namespace JavaScript */ + return str.size(); +} + + +// Same as readLine of a string except that widens the resulting characters to Unicode. +size_t JS::LineReader::readLine(String &wstr) +{ + string str; + size_t n = readLine(str); + wstr.resize(n); + std::transform(str.begin(), str.end(), wstr.begin(), widen); + return n; +} diff --git a/mozilla/js2/src/reader.h b/mozilla/js2/src/reader.h index c76da3705ae..5a326b632a0 100644 --- a/mozilla/js2/src/reader.h +++ b/mozilla/js2/src/reader.h @@ -17,7 +17,7 @@ * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License (the "GPL"), in which case the @@ -46,31 +46,25 @@ namespace JavaScript { // Calling get() yields all of the characters in sequence. // One character may be read // past the end of the source; that character appears as a null. - class Reader { - const char16 *begin; // Beginning of source text - const char16 *p; // Position in source text - const char16 *end; // End of source text; *end is a null character + const char16 *begin; // Beginning of source text + const char16 *p; // Position in source text + const char16 *end; // End of source text; *end is a null character public: - const String source; // Source text - const String sourceLocation; // Description of location from which - // the source text came + const String source; // Source text + const String sourceLocation; // Description of location from which the source text came private: - const uint32 initialLineNum; // One-based number of current line - std::vector linePositions; // Array of line starts - // recorded by beginLine() + const uint32 initialLineNum; // One-based number of current line + std::vector linePositions; // Array of line starts recorded by beginLine() - String *recordString; // String, if any, into which recordChar() - // records characters; not owned by the Reader - const char16 *recordBase; // Position of last beginRecording() call - const char16 *recordPos; // Position of last recordChar() call; - // nil if a discrepancy occurred - public: - Reader(const String &source, const String &sourceLocation, - uint32 initialLineNum = 1); + String *recordString; // String, if any, into which recordChar() records characters; not owned by the Reader + const char16 *recordBase; // Position of last beginRecording() call + const char16 *recordPos; // Position of last recordChar() call; nil if a discrepancy occurred + public: + Reader(const String &source, const String &sourceLocation, uint32 initialLineNum = 1); private: - Reader(const Reader&); // No copy constructor - void operator=(const Reader&);// No assignment operator + Reader(const Reader&); // No copy constructor + void operator=(const Reader&); // No assignment operator public: char16 get() {ASSERT(p <= end);return *p++;} @@ -78,13 +72,13 @@ namespace JavaScript { void unget(uint32 n = 1) {ASSERT(p >= begin + n); p -= n;} uint32 getPos() const {return static_cast(p - begin);} void setPos(uint32 pos) {ASSERT(pos <= getPos()); p = begin + pos;} - + bool eof() const {ASSERT(p <= end); return p == end;} bool peekEof(char16 ch) const { // Faster version. ch is the result of a peek ASSERT(p <= end && *p == ch); return !ch && p == end; - } + } bool pastEof() const {return p == end+1;} bool getEof(char16 ch) const { // Faster version. ch is the result of a get @@ -92,22 +86,22 @@ namespace JavaScript { } void beginLine(); uint32 posToLineNum(uint32 pos) const; - uint32 getLine(uint32 lineNum, const char16 *&lineBegin, - const char16 *&lineEnd) const; + uint32 getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const; void beginRecording(String &recordString); void recordChar(char16 ch); String &endRecording(); - + void error(Exception::Kind kind, const String &message, uint32 pos); }; - + + class LineReader { - FILE *in; // File from which currently reading - bool crWasLast; // True if a CR character was the last one read - + FILE *in; // File from which currently reading + bool crWasLast; // True if a CR character was the last one read + public: explicit LineReader(FILE *in): in(in), crWasLast(false) {} - + size_t readLine(string &str); size_t readLine(String &wstr); }; diff --git a/mozilla/js2/src/token.cpp b/mozilla/js2/src/token.cpp index 58db8d84a07..ca8bed3ed36 100644 --- a/mozilla/js2/src/token.cpp +++ b/mozilla/js2/src/token.cpp @@ -1,362 +1,360 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include "token.h" #include "formatter.h" #include "world.h" -namespace JavaScript -{ - - const char *const Token::kindNames[kindsEnd] = { +namespace JS = JavaScript; - // Special - "end of input", // end - "number", // number - "string", // string - "unit", // unit - "regular expression", // regExp - // Punctuators - "(", // openParenthesis - ")", // closeParenthesis - "[", // openBracket - "]", // closeBracket - "{", // openBrace - "}", // closeBrace - ",", // comma - ";", // semicolon - ".", // dot - "..", // doubleDot - "...", // tripleDot - "->", // arrow - ":", // colon - "::", // doubleColon - "#", // pound - "@", // at - "++", // increment - "--", // decrement - "~", // complement - "!", // logicalNot - "*", // times - "/", // divide - "%", // modulo - "+", // plus - "-", // minus - "<<", // leftShift - ">>", // rightShift - ">>>", // logicalRightShift - "&&", // logicalAnd - "^^", // logicalXor - "||", // logicalOr - "&", // bitwiseAnd - "^", // bitwiseXor - "|", // bitwiseOr - "=", // assignment - "*=", // timesEquals - "/=", // divideEquals - "%=", // moduloEquals - "+=", // plusEquals - "-=", // minusEquals - "<<=", // leftShiftEquals - ">>=", // rightShiftEquals - ">>>=", // logicalRightShiftEquals - "&&=", // logicalAndEquals - "^^=", // logicalXorEquals - "||=", // logicalOrEquals - "&=", // bitwiseAndEquals - "^=", // bitwiseXorEquals - "|=", // bitwiseOrEquals - "==", // equal - "!=", // notEqual - "<", // lessThan - "<=", // lessThanOrEqual - ">", // greaterThan - ">=", // greaterThanOrEqual - "===", // identical - "!==", // notIdentical - "?", // question +const char *const JS::Token::kindNames[kindsEnd] = { - // Reserved words - "abstract", // Abstract - "break", // Break - "case", // Case - "catch", // Catch - "class", // Class - "const", // Const - "continue", // Continue - "debugger", // Debugger - "default", // Default - "delete", // Delete - "do", // Do - "else", // Else - "enum", // Enum - "export", // Export - "extends", // Extends - "false", // False - "final", // Final - "finally", // Finally - "for", // For - "function", // Function - "goto", // Goto - "if", // If - "implements", // Implements - "import", // Import - "in", // In - "instanceof", // Instanceof - "interface", // Interface - "namespace", // Namespace - "native", // Native - "new", // New - "null", // Null - "package", // Package - "private", // Private - "protected", // Protected - "public", // Public - "return", // Return - "static", // Static - "super", // Super - "switch", // Switch - "synchronized", // Synchronized - "this", // This - "throw", // Throw - "throws", // Throws - "transient", // Transient - "true", // True - "try", // Try - "typeof", // Typeof - "use", // Use - "var", // Var - "void", // Void - "volatile", // Volatile - "while", // While - "with", // With + // Special + "end of input", // end + "number", // number + "string", // string + "unit", // unit + "regular expression", // regExp - // Non-reserved words - "eval", // Eval - "exclude", // Exclude - "get", // Get - "include", // Include - "set" // Set - }; + // Punctuators + "(", // openParenthesis + ")", // closeParenthesis + "[", // openBracket + "]", // closeBracket + "{", // openBrace + "}", // closeBrace + ",", // comma + ";", // semicolon + ".", // dot + "..", // doubleDot + "...", // tripleDot + "->", // arrow + ":", // colon + "::", // doubleColon + "#", // pound + "@", // at + "++", // increment + "--", // decrement + "~", // complement + "!", // logicalNot + "*", // times + "/", // divide + "%", // modulo + "+", // plus + "-", // minus + "<<", // leftShift + ">>", // rightShift + ">>>", // logicalRightShift + "&&", // logicalAnd + "^^", // logicalXor + "||", // logicalOr + "&", // bitwiseAnd + "^", // bitwiseXor + "|", // bitwiseOr + "=", // assignment + "*=", // timesEquals + "/=", // divideEquals + "%=", // moduloEquals + "+=", // plusEquals + "-=", // minusEquals + "<<=", // leftShiftEquals + ">>=", // rightShiftEquals + ">>>=", // logicalRightShiftEquals + "&&=", // logicalAndEquals + "^^=", // logicalXorEquals + "||=", // logicalOrEquals + "&=", // bitwiseAndEquals + "^=", // bitwiseXorEquals + "|=", // bitwiseOrEquals + "==", // equal + "!=", // notEqual + "<", // lessThan + "<=", // lessThanOrEqual + ">", // greaterThan + ">=", // greaterThanOrEqual + "===", // identical + "!==", // notIdentical + "?", // question - const uchar followRet = 1< - colon, // : - doubleColon, // :: - pound, // # - at, // @ - - increment, // ++ - decrement, // -- - - complement, // ~ - logicalNot, // ! - - times, // * - divide, // / - modulo, // % - plus, // + - minus, // - - leftShift, // << - rightShift, // >> - logicalRightShift, // >>> - logicalAnd, // && - logicalXor, // ^^ - logicalOr, // || - bitwiseAnd, // & - - // These must be at constant offsets from logicalAnd ... logicalOr - bitwiseXor, // ^ - bitwiseOr, // | - - assignment, // = + openParenthesis, // ( + closeParenthesis, // ) + openBracket, // [ + closeBracket, // ] + openBrace, // { + closeBrace, // } + comma, // , + semicolon, // ; + dot, // . + doubleDot, // .. + tripleDot, // ... + arrow, // -> + colon, // : + doubleColon, // :: + pound, // # + at, // @ - // These must be at constant offsets from times ... bitwiseOr - timesEquals, // *= - divideEquals, // /= - moduloEquals, // %= - plusEquals, // += - minusEquals, // -= - leftShiftEquals, // <<= - rightShiftEquals, // >>= - logicalRightShiftEquals, // >>>= - logicalAndEquals, // &&= - logicalXorEquals, // ^^= - logicalOrEquals, // ||= - bitwiseAndEquals, // &= - bitwiseXorEquals, // ^= - bitwiseOrEquals, // |= - - equal, // == - notEqual, // != - lessThan, // < - lessThanOrEqual, // <= - greaterThan, // > - - // >, >= must be at constant offsets from <, <= - greaterThanOrEqual, // >= - identical, // === - notIdentical, // !== - - question, // ? + increment, // ++ + decrement, // -- + + complement, // ~ + logicalNot, // ! + + times, // * + divide, // / + modulo, // % + plus, // + + minus, // - + leftShift, // << + rightShift, // >> + logicalRightShift, // >>> + logicalAnd, // && + logicalXor, // ^^ + logicalOr, // || + bitwiseAnd, // & These must be at constant offsets from logicalAnd ... logicalOr + bitwiseXor, // ^ + bitwiseOr, // | + + assignment, // = + timesEquals, // *= These must be at constant offsets from times ... bitwiseOr + divideEquals, // /= + moduloEquals, // %= + plusEquals, // += + minusEquals, // -= + leftShiftEquals, // <<= + rightShiftEquals, // >>= + logicalRightShiftEquals, // >>>= + logicalAndEquals, // &&= + logicalXorEquals, // ^^= + logicalOrEquals, // ||= + bitwiseAndEquals, // &= + bitwiseXorEquals, // ^= + bitwiseOrEquals, // |= + + equal, // == + notEqual, // != + lessThan, // < + lessThanOrEqual, // <= + greaterThan, // > >, >= must be at constant offsets from <, <= + greaterThanOrEqual, // >= + identical, // === + notIdentical, // !== + + question, // ? // Reserved words - Abstract, // abstract - Break, // break - Case, // case - Catch, // catch - Class, // class - Const, // const - Continue, // continue - Debugger, // debugger - Default, // default - Delete, // delete - Do, // do - Else, // else - Enum, // enum - Export, // export - Extends, // extends - False, // false - Final, // final - Finally, // finally - For, // for - Function, // function - Goto, // goto - If, // if - Implements, // implements - Import, // import - In, // in - Instanceof, // instanceof - Interface, // interface - Namespace, // namespace - Native, // native - New, // new - Null, // null - Package, // package - Private, // private - Protected, // protected - Public, // public - Return, // return - Static, // static - Super, // super - Switch, // switch - Synchronized, // synchronized - This, // this - Throw, // throw - Throws, // throws - Transient, // transient - True, // true - Try, // try - Typeof, // typeof - Use, // use - Var, // var - Void, // void - Volatile, // volatile - While, // while - With, // with + Abstract, // abstract + As, // as + Break, // break + Case, // case + Catch, // catch + Class, // class + Const, // const + Continue, // continue + Debugger, // debugger + Default, // default + Delete, // delete + Do, // do + Else, // else + Enum, // enum + Export, // export + Extends, // extends + False, // false + Final, // final + Finally, // finally + For, // for + Function, // function + Goto, // goto + If, // if + Implements, // implements + Import, // import + In, // in + Instanceof, // instanceof + Interface, // interface + Namespace, // namespace + Native, // native + New, // new + Null, // null + Package, // package + Private, // private + Protected, // protected + Public, // public + Return, // return + Static, // static + Super, // super + Switch, // switch + Synchronized, // synchronized + This, // this + Throw, // throw + Throws, // throws + Transient, // transient + True, // true + Try, // try + Typeof, // typeof + Use, // use + Var, // var + Void, // void + Volatile, // volatile + While, // while + With, // with // Non-reserved words - Eval, // eval - Exclude, // exclude - Get, // get - Include, // include - Set, // set - - identifier, // Non-keyword identifier - // (may be same as a keyword if it - // contains an escape code) - kindsEnd, // End of token kinds - - keywordsBegin = Abstract, // Beginning of range of special - // identifier tokens - keywordsEnd = identifier, // End of range of special identifier - // tokens - nonreservedBegin = Eval, // Beginning of range of non-reserved - // words + Eval, // eval + Exclude, // exclude + Get, // get + Include, // include + Set, // set + + identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code) + kindsEnd, // End of token kinds + + keywordsBegin = Abstract, // Beginning of range of special identifier tokens + keywordsEnd = identifier, // End of range of special identifier tokens + nonreservedBegin = Eval, // Beginning of range of non-reserved words nonreservedEnd = identifier, // End of range of non-reserved words - kindsWithCharsBegin = number, // Beginning of range of tokens for - // which the chars field (below) is - // valid - kindsWithCharsEnd = regExp+1 // End of range of tokens for which - // the chars field (below) is valid + kindsWithCharsBegin = number, // Beginning of range of tokens for which the chars field (below) is valid + kindsWithCharsEnd = regExp+1 // End of range of tokens for which the chars field (below) is valid }; - + #define CASE_TOKEN_ATTRIBUTE_IDENTIFIER \ Token::Eval: \ case Token::Exclude: \ @@ -227,13 +213,10 @@ namespace JavaScript case Token::identifier enum Flag { - isAttribute, // True if this token is an attribute - canFollowAttribute, // True if this token is an attribute or can - // follow an attribute - canFollowReturn, // True if this token can follow a return - // without an expression - canFollowGet // True if this token can follow a get or - // set in a FunctionName + isAttribute, // True if this token is an attribute + canFollowAttribute, // True if this token is an attribute or can follow an attribute + canFollowReturn, // True if this token can follow a return without an expression + canFollowGet // True if this token can follow a get or set in a FunctionName }; private: @@ -241,65 +224,38 @@ namespace JavaScript static const uchar kindFlags[kindsEnd]; #ifdef DEBUG - bool valid; // True if this token has been initialized + bool valid; // True if this token has been initialized #endif - Kind kind; // The token's kind - bool lineBreak; // True if line break precedes this token - uint32 pos; // Source position of this token - const StringAtom *id; // The token's characters; non-nil for - // identifiers, keywords, and regular - // expressions only - String chars; // The token's characters; valid for strings, units, - // numbers, and regular expression flags only - float64 value; // The token's value (numbers only) - + Kind kind; // The token's kind + bool lineBreak; // True if line break precedes this token + uint32 pos; // Source position of this token + const StringAtom *id; // The token's characters; non-nil for identifiers, keywords, and regular expressions only + String chars; // The token's characters; valid for strings, units, numbers, and regular expression flags only + float64 value; // The token's value (numbers only) + #ifdef DEBUG Token(): valid(false) {} #endif public: static void initKeywords(World &world); - static bool isSpecialKind(Kind kind) { - return kind <= regExp || kind == identifier; - } - static const char *kindName(Kind kind) { - ASSERT(uint(kind) < kindsEnd); - return kindNames[kind]; - } + static bool isSpecialKind(Kind kind) {return kind <= regExp || kind == identifier;} + static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];} Kind getKind() const {ASSERT(valid); return kind;} bool hasKind(Kind k) const {ASSERT(valid); return kind == k;} - bool hasIdentifierKind() const { - ASSERT(nonreservedEnd == identifier && kindsEnd == identifier+1); - return kind >= nonreservedBegin; - } - bool getFlag(Flag f) const { - ASSERT(valid); - return (kindFlags[kind] & 1<= nonreservedBegin;} + bool getFlag(Flag f) const {ASSERT(valid); return (kindFlags[kind] & 1<= kindsWithCharsBegin && - kind < kindsWithCharsEnd); - return chars; - } - float64 getValue() const { - ASSERT(valid && kind == number); - return value; - } - friend Formatter &operator<<(Formatter &f, Kind k) { - f << kindName(k); - return f; - } + const StringAtom &getIdentifier() const {ASSERT(valid && id); return *id;} + const String &getChars() const {ASSERT(valid && kind >= kindsWithCharsBegin && kind < kindsWithCharsEnd); return chars;} + float64 getValue() const {ASSERT(valid && kind == number); return value;} + friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;} void print(Formatter &f, bool debug = false) const; - + friend class Lexer; }; - + } #endif /* token_h___ */ diff --git a/mozilla/js2/src/utilities.cpp b/mozilla/js2/src/utilities.cpp index 161dc1b3b0b..980c466882a 100644 --- a/mozilla/js2/src/utilities.cpp +++ b/mozilla/js2/src/utilities.cpp @@ -1,35 +1,35 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * The contents of this file are subject to the Netscape Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the JavaScript 2 Prototype. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU Public License (the "GPL"), in which case the - * provisions of the GPL are applicable instead of those above. - * If you wish to allow use of your version of this file only - * under the terms of the GPL and not to allow others to use your - * version of this file under the NPL, indicate your decision by - * deleting the provisions above and replace them with the notice - * and other provisions required by the GPL. If you do not delete - * the provisions above, a recipient may use your version of this - * file under either the NPL or the GPL. - */ +* +* The contents of this file are subject to the Netscape Public +* License Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. You may obtain a copy of +* the License at http://www.mozilla.org/NPL/ +* +* Software distributed under the License is distributed on an "AS +* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr +* implied. See the License for the specific language governing +* rights and limitations under the License. +* +* The Original Code is the JavaScript 2 Prototype. +* +* The Initial Developer of the Original Code is Netscape +* Communications Corporation. Portions created by Netscape are +* Copyright (C) 1998 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU Public License (the "GPL"), in which case the +* provisions of the GPL are applicable instead of those above. +* If you wish to allow use of your version of this file only +* under the terms of the GPL and not to allow others to use your +* version of this file under the NPL, indicate your decision by +* deleting the provisions above and replace them with the notice +* and other provisions required by the GPL. If you do not delete +* the provisions above, a recipient may use your version of this +* file under either the NPL or the GPL. +*/ #include "utilities.h" #ifdef DEBUG @@ -44,9 +44,9 @@ # endif #endif -namespace JavaScript -{ - +namespace JS = JavaScript; + + #ifdef DEBUG #ifdef XP_MAC // PStrFromCStr converts the source C string to a destination @@ -54,112 +54,103 @@ namespace JavaScript // be truncated to fit into an Str255 if necessary. // If the C String pointer is NULL, the pascal string's length is // set to zero. - static void - PStrFromCStr(const char* src, Str255 &dst) - { - int length = 0; - - if (src) - { - char *p = reinterpret_cast(&dst[1]); - int spaceLeft = 255; - char ch; - while ((ch = *src++) != 0) { - *p++ = ch; - if (--spaceLeft == 0) - break; - } - length = 255 - spaceLeft; - } - dst[0] = (uchar)length; - } - - static void - jsdebugstr(const char *debuggerMsg) - { - Str255 pStr; - - PStrFromCStr(debuggerMsg, pStr); - DebugStr(pStr); - } - - static void - dprintf(const char *format, ...) - { - std::va_list ap; - char buffer[4096]; - - va_start(ap, format); - std::vsprintf(buffer, format, ap); - va_end(ap); - - jsdebugstr(buffer); - } -#endif /* XP_MAC */ - - - void - Assert(const char *s, const char *file, int line) - { +static void PStrFromCStr(const char* src, Str255 &dst) +{ + int length = 0; + if (src) + { + char *p = reinterpret_cast(&dst[1]); + int spaceLeft = 255; + char ch; + while ((ch = *src++) != 0) { + *p++ = ch; + if (--spaceLeft == 0) + break; + } + length = 255 - spaceLeft; + } + dst[0] = (uchar)length; +} + +static void jsdebugstr(const char *debuggerMsg) +{ + Str255 pStr; + + PStrFromCStr(debuggerMsg, pStr); + DebugStr(pStr); +} + +static void dprintf(const char *format, ...) +{ + std::va_list ap; + char buffer[4096]; + + va_start(ap, format); + std::vsprintf(buffer, format, ap); + va_end(ap); + + jsdebugstr(buffer); +} +#endif /* XP_MAC */ + + +void JS::Assert(const char *s, const char *file, int line) +{ #if defined(XP_UNIX) || defined(XP_OS2) - fprintf(std::stderr, "Assertion failure: %s, at %s:%d\n", s, file, line); + fprintf(std::stderr, "Assertion failure: %s, at %s:%d\n", s, file, line); #endif #ifdef XP_MAC - dprintf("Assertion failure: %s, at %s:%d\n", s, file, line); + dprintf("Assertion failure: %s, at %s:%d\n", s, file, line); #endif #ifdef WIN32 - DebugBreak(); + DebugBreak(); #endif #ifndef XP_MAC - abort(); + abort(); #endif - } +} #endif /* DEBUG */ // Return lg2 of the least power of 2 greater than or equal to n. // Return 0 if n is 0 or 1. - uint - ceilingLog2(uint32 n) - { - uint log2 = 0; - - if (n & (n-1)) - log2++; - if (n >> 16) - log2 += 16, n >>= 16; - if (n >> 8) - log2 += 8, n >>= 8; - if (n >> 4) - log2 += 4, n >>= 4; - if (n >> 2) - log2 += 2, n >>= 2; - if (n >> 1) - log2++; - return log2; - } - +uint JS::ceilingLog2(uint32 n) +{ + uint log2 = 0; + + if (n & (n-1)) + log2++; + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} + // Return lg2 of the greatest power of 2 less than or equal to n. // This really just finds the highest set bit in the word. // Return 0 if n is 0 or 1. - uint - floorLog2(uint32 n) - { - uint log2 = 0; - - if (n >> 16) - log2 += 16, n >>= 16; - if (n >> 8) - log2 += 8, n >>= 8; - if (n >> 4) - log2 += 4, n >>= 4; - if (n >> 2) - log2 += 2, n >>= 2; - if (n >> 1) - log2++; - return log2; - } - +uint JS::floorLog2(uint32 n) +{ + uint log2 = 0; + + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; } diff --git a/mozilla/js2/src/utilities.h b/mozilla/js2/src/utilities.h index ec9b8774c11..ef709d9c163 100644 --- a/mozilla/js2/src/utilities.h +++ b/mozilla/js2/src/utilities.h @@ -35,7 +35,7 @@ #define utilities_h___ #ifdef MSC_VER - // diasble long identifier warnings +// disable long identifier warnings # pragma warning(disable: 4786) #endif @@ -62,17 +62,15 @@ namespace JavaScript # define DEBUG_ONLY(_stmt) #endif + // -// Random Crap +// Mathematics // -// - + template N min(N v1, N v2) {return v1 <= v2 ? v1 : v2;} template N max(N v1, N v2) {return v1 >= v2 ? v1 : v2;} uint ceilingLog2(uint32 n); uint floorLog2(uint32 n); - } - #endif /* utilities_h___ */ diff --git a/mozilla/js2/src/world.h b/mozilla/js2/src/world.h index b0dc60da600..d3f04eab77d 100644 --- a/mozilla/js2/src/world.h +++ b/mozilla/js2/src/world.h @@ -39,7 +39,7 @@ #include "hash.h" namespace JavaScript { - + // // String atom management // @@ -48,24 +48,19 @@ namespace JavaScript { // StringAtoms A and B have the same character sequences if and only if A and // B are the same StringAtom. - class StringAtom : public String { + class StringAtom: public String { public: // Token::Kind if this is a keyword; Token::identifier if not Token::Kind tokenKind; - explicit StringAtom(const String &s) : - String(s), tokenKind(Token::identifier) {} + explicit StringAtom(const String &s): String(s), tokenKind(Token::identifier) {} private: StringAtom(const StringAtom&); // No copy constructor void operator=(const StringAtom&); // No assignment operator }; - inline bool operator==(const StringAtom &s1, const StringAtom &s2) { - return &s1 == &s2; - } - inline bool operator!=(const StringAtom &s1, const StringAtom &s2) { - return &s1 != &s2; - } + inline bool operator==(const StringAtom &s1, const StringAtom &s2) {return &s1 == &s2;} + inline bool operator!=(const StringAtom &s1, const StringAtom &s2) {return &s1 != &s2;} class StringAtomTable { typedef HashTable HT; @@ -73,10 +68,7 @@ namespace JavaScript { public: StringAtom &operator[](const String &s); - - StringAtom &operator[](const char *s) { - return operator[](widenCString(s)); - } + StringAtom &operator[](const char *s) {return operator[](widenCString(s));} }; class World {