зеркало из https://github.com/mozilla/pjs.git
Updated parser: attributes can be expressions, added new attributes, disallowed nested ::'s, deleted Eval nodes, added const and void nodes, deleted package attribute, deleted super::id syntax, and added super, super(expr), and super(args) syntax
This commit is contained in:
Родитель
8e0358e13a
Коммит
c3cb31ba54
|
@ -1,58 +1,56 @@
|
|||
/* -*- 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)
|
||||
{
|
||||
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 (char16Value(ch) < 0x20 || isLineBreak(ci) || isFormat(ci) || ch == '\\' || ch == quote) {
|
||||
if (begin-1 != chunk)
|
||||
printString(f, chunk, begin-1);
|
||||
chunk = begin;
|
||||
|
@ -75,59 +73,53 @@ namespace JavaScript
|
|||
break;
|
||||
|
||||
case 0x0000:
|
||||
if (begin == end || char16Value(*begin) < '0' ||
|
||||
char16Value(*begin) > '9') {
|
||||
if (begin == end || char16Value(*begin) < '0' || char16Value(*begin) > '9') {
|
||||
f << '0';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (char16Value(ch) <= 0xFF) {
|
||||
f << 'x';
|
||||
printHex(f,
|
||||
static_cast<uint32>(char16Value(ch)),
|
||||
2);
|
||||
printHex(f, static_cast<uint32>(char16Value(ch)), 2);
|
||||
} else {
|
||||
f << 'u';
|
||||
printHex(f,
|
||||
static_cast<uint32>(char16Value(ch)),
|
||||
4);
|
||||
printHex(f, static_cast<uint32>(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
size_t JS::printChars(FILE *file, const char *begin, const char *end)
|
||||
{
|
||||
ASSERT(end >= begin);
|
||||
size_t n = static_cast<size_t>(end - begin);
|
||||
size_t extra = 0;
|
||||
|
@ -143,26 +135,26 @@ namespace JavaScript
|
|||
std::memcpy(buffer, begin, n);
|
||||
translateLFtoCR(buffer, buffer + n);
|
||||
return extra + fwrite(buffer, 1, n, file);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
std::fputc(int c, FILE *file)
|
||||
{
|
||||
|
||||
int std::fputc(int c, FILE *file)
|
||||
{
|
||||
char buffer = static_cast<char>(c);
|
||||
if (buffer == '\n')
|
||||
buffer = '\r';
|
||||
return static_cast<int>(fwrite(&buffer, 1, 1, file));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
std::fputs(const char *s, FILE *file)
|
||||
{
|
||||
|
||||
int std::fputs(const char *s, FILE *file)
|
||||
{
|
||||
return static_cast<int>(printChars(file, s, s + strlen(s)));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
std::fprintf(FILE* file, const char *format, ...)
|
||||
{
|
||||
|
||||
int std::fprintf(FILE* file, const char *format, ...)
|
||||
{
|
||||
Buffer<char, 1024> b;
|
||||
|
||||
while (true) {
|
||||
|
@ -172,52 +164,46 @@ namespace JavaScript
|
|||
va_end(args);
|
||||
if (n >= 0 && n < b.size) {
|
||||
translateLFtoCR(b.buffer, b.buffer + n);
|
||||
return static_cast<int>(fwrite(b.buffer, 1,
|
||||
static_cast<size_t>(n), file));
|
||||
return static_cast<int>(fwrite(b.buffer, 1, static_cast<size_t>(n), file));
|
||||
}
|
||||
b.expand(b.size*2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif // XP_MAC_MPW
|
||||
|
||||
|
||||
// Write ch.
|
||||
void
|
||||
Formatter::printChar8(char ch)
|
||||
{
|
||||
void JS::Formatter::printChar8(char ch)
|
||||
{
|
||||
printStr8(&ch, &ch + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write ch.
|
||||
void
|
||||
Formatter::printChar16(char16 ch)
|
||||
{
|
||||
void JS::Formatter::printChar16(char16 ch)
|
||||
{
|
||||
printStr16(&ch, &ch + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the null-terminated string str.
|
||||
void
|
||||
Formatter::printZStr8(const char *str)
|
||||
{
|
||||
void JS::Formatter::printZStr8(const char *str)
|
||||
{
|
||||
printStr8(str, str + strlen(str));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the String s.
|
||||
void
|
||||
Formatter::printString16(const String &s)
|
||||
{
|
||||
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)
|
||||
{
|
||||
void JS::Formatter::printVFormat8(const char *format, va_list args)
|
||||
{
|
||||
Buffer<char, 1024> b;
|
||||
|
||||
while (true) {
|
||||
|
@ -228,15 +214,14 @@ namespace JavaScript
|
|||
}
|
||||
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)
|
||||
{
|
||||
void JS::printChar(Formatter &f, char ch, int count)
|
||||
{
|
||||
char str[printCharBufferSize];
|
||||
|
||||
while (count > 0) {
|
||||
|
@ -247,13 +232,12 @@ namespace JavaScript
|
|||
STD::memset(str, ch, static_cast<size_t>(c));
|
||||
printString(f, str, str+c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Print ch count times.
|
||||
void
|
||||
printChar(Formatter &f, char16 ch, int count)
|
||||
{
|
||||
void JS::printChar(Formatter &f, char16 ch, int count)
|
||||
{
|
||||
char16 str[printCharBufferSize];
|
||||
|
||||
while (count > 0) {
|
||||
|
@ -265,60 +249,57 @@ namespace JavaScript
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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[] = {
|
||||
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)
|
||||
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;
|
||||
|
@ -326,46 +307,42 @@ namespace JavaScript
|
|||
filter = defaultFilter;
|
||||
#endif
|
||||
filterEmpty = filter.none();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write ch, escaping non-ASCII characters.
|
||||
void
|
||||
AsciiFileFormatter::printChar8(char ch)
|
||||
{
|
||||
void JS::AsciiFileFormatter::printChar8(char ch)
|
||||
{
|
||||
if (filterChar(ch))
|
||||
fprintf(file, unprintableFormat, static_cast<uchar>(ch));
|
||||
else
|
||||
fputc(ch, file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write ch, escaping non-ASCII characters.
|
||||
void
|
||||
AsciiFileFormatter::printChar16(char16 ch)
|
||||
{
|
||||
void JS::AsciiFileFormatter::printChar16(char16 ch)
|
||||
{
|
||||
if (filterChar(ch))
|
||||
fprintf(file, unprintableFormat, char16Value(ch));
|
||||
else
|
||||
fputc(static_cast<char>(ch), file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the null-terminated string str, escaping non-ASCII characters.
|
||||
void
|
||||
AsciiFileFormatter::printZStr8(const char *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)
|
||||
{
|
||||
void JS::AsciiFileFormatter::printStr8(const char *strBegin, const char *strEnd)
|
||||
{
|
||||
if (filterEmpty)
|
||||
printChars(file, strBegin, strEnd);
|
||||
else {
|
||||
|
@ -385,12 +362,12 @@ namespace JavaScript
|
|||
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)
|
||||
{
|
||||
void JS::AsciiFileFormatter::printStr16(const char16 *strBegin, const char16 *strEnd)
|
||||
{
|
||||
char buffer[512];
|
||||
|
||||
ASSERT(strEnd >= strBegin);
|
||||
|
@ -413,58 +390,54 @@ namespace JavaScript
|
|||
}
|
||||
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)
|
||||
{
|
||||
void JS::StringFormatter::printChar8(char ch)
|
||||
{
|
||||
s += ch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write ch.
|
||||
void
|
||||
StringFormatter::printChar16(char16 ch)
|
||||
{
|
||||
void JS::StringFormatter::printChar16(char16 ch)
|
||||
{
|
||||
s += ch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the null-terminated string str.
|
||||
void
|
||||
StringFormatter::printZStr8(const char *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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
void JS::StringFormatter::printStr16(const char16 *strBegin, const char16 *strEnd)
|
||||
{
|
||||
s.append(strBegin, strEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the String str.
|
||||
void
|
||||
StringFormatter::printString16(const String &str)
|
||||
{
|
||||
void JS::StringFormatter::printString16(const String &str)
|
||||
{
|
||||
s += str;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
@ -475,7 +448,7 @@ 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
|
||||
|
@ -483,7 +456,7 @@ namespace JavaScript
|
|||
// 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):
|
||||
JS::PrettyPrinter::PrettyPrinter(Formatter &f, uint32 lineWidth):
|
||||
lineWidth(min(lineWidth, static_cast<uint32>(unlimitedLineWidth))),
|
||||
outputFormatter(f),
|
||||
outputPos(0),
|
||||
|
@ -494,20 +467,20 @@ namespace JavaScript
|
|||
leftSerialPos(0),
|
||||
rightSerialPos(0),
|
||||
itemPool(20)
|
||||
{
|
||||
{
|
||||
#ifdef DEBUG
|
||||
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()
|
||||
{
|
||||
JS::PrettyPrinter::~PrettyPrinter()
|
||||
{
|
||||
ASSERT(!topRegion && !nNestedBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Output either a line break (if sameLine is false) or length spaces (if
|
||||
|
@ -516,9 +489,8 @@ 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)
|
||||
{
|
||||
void JS::PrettyPrinter::outputBreak(bool sameLine, uint32 length)
|
||||
{
|
||||
leftSerialPos += length;
|
||||
|
||||
if (sameLine) {
|
||||
|
@ -532,7 +504,7 @@ namespace JavaScript
|
|||
outputFormatter << '\n';
|
||||
printChar(outputFormatter, ' ', static_cast<int>(margin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check to see whether (rightSerialPos+rightOffset)-leftSerialPos has gotten so large that we may pop items
|
||||
|
@ -542,9 +514,8 @@ 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)
|
||||
{
|
||||
bool JS::PrettyPrinter::reduceLeftActiveItems(uint32 rightOffset)
|
||||
{
|
||||
uint32 newRightSerialPos = rightSerialPos + rightOffset;
|
||||
while (activeItems) {
|
||||
Item *leftItem = &activeItems.front();
|
||||
|
@ -572,8 +543,7 @@ namespace JavaScript
|
|||
char16 *textBegin;
|
||||
char16 *textEnd;
|
||||
do {
|
||||
length -= itemText.pop_front(length, textBegin,
|
||||
textEnd);
|
||||
length -= itemText.pop_front(length, textBegin, textEnd);
|
||||
printString(outputFormatter, textBegin, textEnd);
|
||||
} while (length);
|
||||
}
|
||||
|
@ -607,16 +577,13 @@ namespace JavaScript
|
|||
break;
|
||||
|
||||
case Item::linearBreak:
|
||||
// Exceptions may be thrown below, but only after
|
||||
// updating the PrettyPrinter.
|
||||
// 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);
|
||||
// Exceptions may be thrown below, but only after updating the PrettyPrinter.
|
||||
outputBreak(lastBreak == lineNum && outputPos + leftItem->totalLength <= lineWidth, length);
|
||||
break;
|
||||
}
|
||||
} catch (...) {
|
||||
|
@ -626,7 +593,7 @@ namespace JavaScript
|
|||
itemPool.destroy(leftItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A break or end of input is about to be processed. Check whether there are
|
||||
|
@ -635,9 +602,8 @@ 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()
|
||||
{
|
||||
void JS::PrettyPrinter::reduceRightActiveItems()
|
||||
{
|
||||
uint32 nUnmatchedBlockEnds = 0;
|
||||
while (itemStack) {
|
||||
Item *rightItem = itemStack.pop_back();
|
||||
|
@ -660,32 +626,27 @@ namespace JavaScript
|
|||
case Item::fillBreak:
|
||||
rightItem->computeTotalLength(rightSerialPos);
|
||||
if (!nUnmatchedBlockEnds)
|
||||
// There can be at most one consecutive break posted on
|
||||
// the itemStack.
|
||||
// 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.
|
||||
}
|
||||
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<uint32>(-offset));
|
||||
JS::PrettyPrinter::Item &JS::PrettyPrinter::beginIndent(int32 offset)
|
||||
{
|
||||
Item *unindent = new(itemPool) Item(Item::indent, static_cast<uint32>(-offset));
|
||||
if (activeItems) {
|
||||
try {
|
||||
activeItems.push_back(*new(itemPool) Item(Item::indent,
|
||||
static_cast<uint32>(offset)));
|
||||
activeItems.push_back(*new(itemPool) Item(Item::indent, static_cast<uint32>(offset)));
|
||||
} catch (...) {
|
||||
itemPool.destroy(unindent);
|
||||
throw;
|
||||
|
@ -695,14 +656,13 @@ namespace JavaScript
|
|||
ASSERT(static_cast<int32>(margin) >= 0);
|
||||
}
|
||||
return *unindent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
void JS::PrettyPrinter::endIndent(Item &i)
|
||||
{
|
||||
if (activeItems)
|
||||
activeItems.push_back(i);
|
||||
else {
|
||||
|
@ -710,7 +670,7 @@ namespace JavaScript
|
|||
ASSERT(static_cast<int32>(margin) >= 0);
|
||||
itemPool.destroy(&i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Begin a logical block. If kind is Item::indentBlockBegin, offset is the
|
||||
|
@ -718,17 +678,15 @@ 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)
|
||||
{
|
||||
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<uint32>(offset),
|
||||
rightSerialPos);
|
||||
beginItem = new(itemPool) Item(kind, static_cast<uint32>(offset), rightSerialPos);
|
||||
} catch (...) {
|
||||
itemPool.destroy(endItem);
|
||||
throw;
|
||||
|
@ -739,19 +697,18 @@ namespace JavaScript
|
|||
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)
|
||||
{
|
||||
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
|
||||
|
@ -771,9 +728,8 @@ namespace JavaScript
|
|||
//
|
||||
// If this method throws an exception, it leaves the PrettyPrinter in a
|
||||
// consistent state.
|
||||
void
|
||||
PrettyPrinter::conditionalBreak(uint32 nSpaces, Item::Kind kind)
|
||||
{
|
||||
void JS::PrettyPrinter::conditionalBreak(uint32 nSpaces, Item::Kind kind)
|
||||
{
|
||||
ASSERT(nSpaces <= unlimitedLineWidth && nNestedBlocks);
|
||||
reduceRightActiveItems();
|
||||
itemStack.reserve_back(1 + nNestedBlocks);
|
||||
|
@ -785,7 +741,7 @@ namespace JavaScript
|
|||
rightSerialPos += nSpaces;
|
||||
// End of exception-atomic stack update.
|
||||
reduceLeftActiveItems(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the string between strBegin and strEnd. Any embedded newlines ('\n'
|
||||
|
@ -793,9 +749,8 @@ 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)
|
||||
{
|
||||
void JS::PrettyPrinter::printStr8(const char *strBegin, const char *strEnd)
|
||||
{
|
||||
while (strBegin != strEnd) {
|
||||
const char *sectionEnd = findValue(strBegin, strEnd, '\n');
|
||||
uint32 sectionLength = static_cast<uint32>(sectionEnd - strBegin);
|
||||
|
@ -803,21 +758,17 @@ namespace JavaScript
|
|||
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.
|
||||
// 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));
|
||||
activeItems.push_back(*new(itemPool) Item(Item::text, sectionLength));
|
||||
rightSerialPos += sectionLength;
|
||||
itemText.fast_append(reinterpret_cast<const uchar *>(strBegin),
|
||||
reinterpret_cast<const uchar *>(sectionEnd));
|
||||
itemText.fast_append(reinterpret_cast<const uchar *>(strBegin), reinterpret_cast<const uchar *>(sectionEnd));
|
||||
// End of exception-atomic update.
|
||||
} else {
|
||||
ASSERT(!itemStack && !activeItems && !itemText &&
|
||||
leftSerialPos == rightSerialPos);
|
||||
ASSERT(!itemStack && !activeItems && !itemText && leftSerialPos == rightSerialPos);
|
||||
outputPos += sectionLength;
|
||||
printString(outputFormatter, strBegin, sectionEnd);
|
||||
}
|
||||
|
@ -828,7 +779,7 @@ namespace JavaScript
|
|||
requiredBreak();
|
||||
++strBegin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write the string between strBegin and strEnd. Any embedded newlines ('\n'
|
||||
|
@ -836,9 +787,8 @@ 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)
|
||||
{
|
||||
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<uint32>(sectionEnd - strBegin);
|
||||
|
@ -846,20 +796,17 @@ namespace JavaScript
|
|||
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.
|
||||
// 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));
|
||||
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);
|
||||
ASSERT(!itemStack && !activeItems && !itemText && leftSerialPos == rightSerialPos);
|
||||
outputPos += sectionLength;
|
||||
printString(outputFormatter, strBegin, sectionEnd);
|
||||
}
|
||||
|
@ -870,22 +817,21 @@ namespace JavaScript
|
|||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
void JS::PrettyPrinter::end()
|
||||
{
|
||||
ASSERT(!topRegion);
|
||||
reduceRightActiveItems();
|
||||
reduceLeftActiveItems(infiniteLength);
|
||||
ASSERT(!savedBlocks && !itemStack && !activeItems && !itemText &&
|
||||
rightSerialPos == leftSerialPos && !margin);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ namespace JavaScript
|
|||
}
|
||||
#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
|
||||
|
@ -70,8 +71,7 @@ namespace JavaScript
|
|||
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 printStr16(const char16 *strBegin, const char16 *strEnd) = 0;
|
||||
virtual void printString16(const String &s);
|
||||
virtual void printVFormat8(const char *format, va_list args);
|
||||
public:
|
||||
|
@ -85,13 +85,11 @@ namespace JavaScript
|
|||
return *this;
|
||||
}
|
||||
|
||||
friend void printString(Formatter &f, const char *strBegin,
|
||||
const char *strEnd) {
|
||||
friend void printString(Formatter &f, const char *strBegin, const char *strEnd) {
|
||||
f.printStr8(strBegin, strEnd);
|
||||
}
|
||||
|
||||
friend void printString(Formatter &f, const char16 *strBegin,
|
||||
const char16 *strEnd) {
|
||||
friend void printString(Formatter &f, const char16 *strBegin, const char16 *strEnd) {
|
||||
f.printStr16(strBegin, strEnd);
|
||||
}
|
||||
|
||||
|
@ -103,31 +101,13 @@ namespace JavaScript
|
|||
}
|
||||
};
|
||||
|
||||
void printNum(Formatter &f, uint32 i, int nDigits, char pad,
|
||||
const char *format);
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
@ -138,12 +118,10 @@ namespace JavaScript
|
|||
// 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
|
||||
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
|
||||
static BitSet<256> defaultFilter; // Default value of filter when not given in the constructor
|
||||
|
||||
explicit AsciiFileFormatter(FILE *file, BitSet<256> *filter = 0);
|
||||
|
||||
|
@ -202,43 +180,30 @@ namespace JavaScript
|
|||
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
|
||||
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 lastBreak; // Number of line just after the last break that occurred in this block
|
||||
uint32 margin; // Current left margin in spaces
|
||||
ArrayBuffer<BlockInfo, 20> savedBlocks; // Stack of saved information
|
||||
// about partially printed blocks
|
||||
ArrayBuffer<BlockInfo, 20> savedBlocks; // Stack of saved information about partially printed blocks
|
||||
|
||||
// Variables for the front end that calculates block sizes
|
||||
struct Item: ListQueueEntry {
|
||||
enum Kind {text, blockBegin, indentBlockBegin, blockEnd, indent,
|
||||
linearBreak, fillBreak};
|
||||
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 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) {}
|
||||
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) {}
|
||||
kind(kind), lengthKnown(false), length(length), totalLength(beginSerialPos) {}
|
||||
|
||||
void computeTotalLength(uint32 endSerialPos) {
|
||||
ASSERT(!lengthKnown);
|
||||
|
@ -254,35 +219,21 @@ namespace JavaScript
|
|||
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<Item *, 20> 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<Item> itemPool; // Pool from which to allocate
|
||||
// activeItems
|
||||
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<Item *, 20> 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<Item> itemPool; // Pool from which to allocate activeItems
|
||||
ListQueue<Item> activeItems; // Queue of items left to be printed
|
||||
|
||||
ArrayQueue<char16, 256> itemText; // Text of text items in activeItems,
|
||||
// in the same order as in activeItems
|
||||
ArrayQueue<char16, 256> itemText; // Text of text items in activeItems, in the same order as in activeItems
|
||||
|
||||
public:
|
||||
static uint32 defaultLineWidth; // Default for lineWidth if not given
|
||||
// to the constructor
|
||||
static uint32 defaultLineWidth; // Default for lineWidth if not given to the constructor
|
||||
|
||||
explicit PrettyPrinter(Formatter &f,
|
||||
uint32 lineWidth = defaultLineWidth);
|
||||
explicit PrettyPrinter(Formatter &f, uint32 lineWidth = defaultLineWidth);
|
||||
private:
|
||||
PrettyPrinter(const PrettyPrinter&); // No copy constructor
|
||||
void operator=(const PrettyPrinter&); // No assignment operator
|
||||
|
@ -308,12 +259,9 @@ namespace JavaScript
|
|||
public:
|
||||
|
||||
void requiredBreak();
|
||||
void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces,
|
||||
Item::linearBreak);}
|
||||
void linearBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::linearBreak);}
|
||||
void linearBreak(uint32 nSpaces, bool required);
|
||||
void fillBreak(uint32 nSpaces) {
|
||||
conditionalBreak(nSpaces, Item::fillBreak);
|
||||
}
|
||||
void fillBreak(uint32 nSpaces) {conditionalBreak(nSpaces, Item::fillBreak);}
|
||||
|
||||
void end();
|
||||
|
||||
|
@ -328,9 +276,7 @@ namespace JavaScript
|
|||
protected:
|
||||
PrettyPrinter &pp;
|
||||
|
||||
Region(PrettyPrinter &pp) : pp(pp) {
|
||||
DEBUG_ONLY(next = pp.topRegion; pp.topRegion = this;);
|
||||
}
|
||||
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
|
||||
|
@ -349,8 +295,7 @@ namespace JavaScript
|
|||
class Indent: public Region {
|
||||
Item &endItem; // The Item returned by beginIndent
|
||||
public:
|
||||
Indent(PrettyPrinter &pp, int32 offset) :
|
||||
Region(pp), endItem(pp.beginIndent(offset)) {}
|
||||
Indent(PrettyPrinter &pp, int32 offset): Region(pp), endItem(pp.beginIndent(offset)) {}
|
||||
~Indent() {pp.endIndent(endItem);}
|
||||
};
|
||||
|
||||
|
@ -363,20 +308,14 @@ namespace JavaScript
|
|||
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)) {}
|
||||
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 escapeString(Formatter &f, const char16 *begin, const char16 *end, char16 quote);
|
||||
void quoteString(Formatter &f, const String &s, char16 quote);
|
||||
|
||||
}
|
||||
|
||||
#endif /* formatter_h___ */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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):
|
||||
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;
|
||||
#endif
|
||||
lexingUnit = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get and return the next token. The token remains valid until the next
|
||||
|
@ -62,24 +61,22 @@ 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 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 JS::Token *JS::Lexer::eat(bool preferRegExp, Token::Kind kind)
|
||||
{
|
||||
const Token &t = peek(preferRegExp);
|
||||
if (t.kind != kind)
|
||||
return 0;
|
||||
|
@ -88,7 +85,7 @@ namespace JavaScript
|
|||
--nTokensFwd;
|
||||
DEBUG_ONLY(++nTokensBack);
|
||||
return &t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return the next token without consuming it.
|
||||
|
@ -98,9 +95,8 @@ 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)
|
||||
{
|
||||
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);
|
||||
|
@ -119,7 +115,7 @@ namespace JavaScript
|
|||
#endif
|
||||
}
|
||||
return *nextToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -129,95 +125,93 @@ 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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
void JS::Lexer::syntaxError(const char *message, uint backUp)
|
||||
{
|
||||
reader.unget(backUp);
|
||||
reader.error(Exception::syntaxError, widenCString(message),
|
||||
reader.getPos());
|
||||
}
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
bool JS::Lexer::testChar(char16 ch)
|
||||
{
|
||||
ASSERT(ch); // If ch were null, it could match the eof null.
|
||||
char16 ch2 = peekChar();
|
||||
if (ch == ch2) {
|
||||
|
@ -225,14 +219,14 @@ namespace JavaScript
|
|||
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 JS::Lexer::lexEscape(bool unicodeOnly)
|
||||
{
|
||||
char16 ch = getChar();
|
||||
int nDigits;
|
||||
|
||||
|
@ -287,16 +281,15 @@ namespace JavaScript
|
|||
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)
|
||||
{
|
||||
bool JS::Lexer::lexIdentifier(String &s, bool allowLeadingDigit)
|
||||
{
|
||||
reader.beginRecording(s);
|
||||
bool hasEscape = false;
|
||||
|
||||
|
@ -312,8 +305,7 @@ namespace JavaScript
|
|||
if (!(allowLeadingDigit ? isIdContinuing(chi2) :
|
||||
isIdLeading(chi2))) {
|
||||
if (ch == '\\')
|
||||
syntaxError("Identifier escape expands into "
|
||||
"non-identifier character");
|
||||
syntaxError("Identifier escape expands into non-identifier character");
|
||||
else
|
||||
reader.unget();
|
||||
break;
|
||||
|
@ -323,15 +315,14 @@ namespace JavaScript
|
|||
}
|
||||
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()
|
||||
{
|
||||
bool JS::Lexer::lexNumeral()
|
||||
{
|
||||
int hasDecimalPoint = 0;
|
||||
String &s = nextToken->chars;
|
||||
uint digit;
|
||||
|
@ -396,14 +387,13 @@ namespace JavaScript
|
|||
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)
|
||||
{
|
||||
void JS::Lexer::lexString(String &s, char16 separator)
|
||||
{
|
||||
char16 ch;
|
||||
|
||||
reader.beginRecording(s);
|
||||
|
@ -418,14 +408,14 @@ namespace JavaScript
|
|||
}
|
||||
}
|
||||
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()
|
||||
{
|
||||
void JS::Lexer::lexRegExp()
|
||||
{
|
||||
String s;
|
||||
char16 prevCh = 0;
|
||||
|
||||
|
@ -449,12 +439,13 @@ namespace JavaScript
|
|||
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)
|
||||
{
|
||||
void JS::Lexer::lexToken(bool preferRegExp)
|
||||
{
|
||||
Token &t = *nextToken;
|
||||
t.lineBreak = false;
|
||||
t.id = 0;
|
||||
|
@ -491,8 +482,7 @@ namespace JavaScript
|
|||
String s;
|
||||
bool hasEscape = lexIdentifier(s, false);
|
||||
t.id = &world.identifiers[s];
|
||||
kind = hasEscape ? Token::identifier :
|
||||
t.id->tokenKind;
|
||||
kind = hasEscape ? Token::identifier : t.id->tokenKind;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -568,9 +558,7 @@ namespace JavaScript
|
|||
kind = Token::times; // * *=
|
||||
tryAssignment:
|
||||
if (testChar('='))
|
||||
kind = Token::Kind(kind +
|
||||
Token::timesEquals -
|
||||
Token::times);
|
||||
kind = Token::Kind(kind + Token::timesEquals - Token::times);
|
||||
break;
|
||||
|
||||
case '/':
|
||||
|
@ -592,8 +580,7 @@ namespace JavaScript
|
|||
reader.beginLine();
|
||||
t.lineBreak = true;
|
||||
} else if (reader.getEof(ch))
|
||||
syntaxError("Unterminated /* "
|
||||
"comment");
|
||||
syntaxError("Unterminated /* comment");
|
||||
} while (ch != '/' || ch2 != '*');
|
||||
goto next;
|
||||
} else {
|
||||
|
@ -635,9 +622,7 @@ namespace JavaScript
|
|||
kind = Token::bitwiseAnd; // & && &= &&=
|
||||
logical:
|
||||
if (testChar(ch))
|
||||
kind = Token::Kind(kind -
|
||||
Token::bitwiseAnd +
|
||||
Token::logicalAnd);
|
||||
kind = Token::Kind(kind - Token::bitwiseAnd + Token::logicalAnd);
|
||||
goto tryAssignment;
|
||||
case '^':
|
||||
kind = Token::bitwiseXor; // ^ ^^ ^= ^^=
|
||||
|
@ -663,9 +648,7 @@ namespace JavaScript
|
|||
}
|
||||
comparison:
|
||||
if (testChar('=')) // <= >=
|
||||
kind = Token::Kind(kind +
|
||||
Token::lessThanOrEqual -
|
||||
Token::lessThan);
|
||||
kind = Token::Kind(kind + Token::lessThanOrEqual - Token::lessThan);
|
||||
break;
|
||||
case '>':
|
||||
kind = Token::greaterThan; // >
|
||||
|
@ -678,8 +661,7 @@ namespace JavaScript
|
|||
goto comparison;
|
||||
|
||||
case '\\':
|
||||
goto readIdentifier; // An identifier that
|
||||
// starts with an escape
|
||||
goto readIdentifier; // An identifier that starts with an escape
|
||||
|
||||
case '\'':
|
||||
case '"':
|
||||
|
@ -720,6 +702,4 @@ namespace JavaScript
|
|||
#ifdef DEBUG
|
||||
t.valid = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,46 +42,29 @@
|
|||
|
||||
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);
|
||||
|
@ -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___ */
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
2234
js2/src/parser.cpp
2234
js2/src/parser.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
572
js2/src/parser.h
572
js2/src/parser.h
|
@ -48,11 +48,9 @@ namespace JavaScript {
|
|||
|
||||
class Language {
|
||||
enum {
|
||||
minorVersion = 0, // Single BCD digit representing the minor
|
||||
// JavaScript version
|
||||
minorVersion = 0, // Single BCD digit representing the minor JavaScript version
|
||||
minorVersionBits = 4,
|
||||
majorVersion = 4, // Single BCD digit representing the major
|
||||
// JavaScript version
|
||||
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
|
||||
|
@ -76,6 +74,7 @@ namespace JavaScript {
|
|||
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
|
||||
// <next> of type N* and that is initialized to nil when an N instance is
|
||||
|
@ -98,40 +97,33 @@ namespace JavaScript {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
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) {}
|
||||
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
|
||||
// Keep synchronized with kindNames and simpleLookup
|
||||
enum Kind { // Actual class Operands
|
||||
none,
|
||||
identifier, // IdentifierExprNode <name>
|
||||
|
||||
// Begin of isPostfix()
|
||||
|
||||
number, // NumberExprNode <value>
|
||||
string, // StringExprNode <str>
|
||||
regExp, // RegExpExprNode /<re>/<flags>
|
||||
|
@ -139,40 +131,33 @@ namespace JavaScript {
|
|||
True, // ExprNode true
|
||||
False, // ExprNode false
|
||||
This, // ExprNode this
|
||||
Super, // ExprNode super
|
||||
|
||||
parentheses, // UnaryExprNode (<op>)
|
||||
numUnit, // NumUnitExprNode <num> "<str>" or <num><str>
|
||||
exprUnit, // ExprUnitExprNode (<op>) "<str>"
|
||||
qualify, // BinaryExprNode <op1> :: <op2>
|
||||
// (right-associative: a::b::c represented as
|
||||
// a::(b::c))
|
||||
exprUnit, // ExprUnitExprNode (<op>) "<str>" or <op><str>
|
||||
qualify, // BinaryExprNode <op1> :: <op2> (<op2> must be identifier)
|
||||
|
||||
objectLiteral, // PairListExprNode {<field>:<value>,
|
||||
// <field>:<value>, ..., <field>:<value>}
|
||||
arrayLiteral, // PairListExprNode [<value>, <value>, ...,
|
||||
// <value>]
|
||||
objectLiteral, // PairListExprNode {<field>:<value>, <field>:<value>, ..., <field>:<value>}
|
||||
arrayLiteral, // PairListExprNode [<value>, <value>, ..., <value>]
|
||||
functionLiteral, // FunctionExprNode function <function>
|
||||
|
||||
call, // InvokeExprNode <op>(<field>:<value>,
|
||||
// <field>:<value>, ..., <field>:<value>)
|
||||
New, // InvokeExprNode new <op>(<field>:<value>,
|
||||
// <field>:<value>, ..., <field>:<value>)
|
||||
index, // InvokeExprNode <op>[<field>:<value>,
|
||||
// <field>:<value>, ..., <field>:<value>]
|
||||
call, // InvokeExprNode <op>(<field>:<value>, <field>:<value>, ..., <field>:<value>)
|
||||
New, // InvokeExprNode new <op>(<field>:<value>, <field>:<value>, ..., <field>:<value>)
|
||||
index, // InvokeExprNode <op>[<field>:<value>, <field>:<value>, ..., <field>:<value>]
|
||||
|
||||
dot, // BinaryExprNode <op1> . <op2>
|
||||
// <op2> must be identifier or qualify
|
||||
dot, // BinaryExprNode <op1> . <op2> (<op2> must be identifier or qualify)
|
||||
dotClass, // UnaryExprNode <op1> .class
|
||||
dotParen, // BinaryExprNode <op1> .( <op2> )
|
||||
at, // BinaryExprNode <op1> @ <op2> or
|
||||
// <op1> @( <op2> )
|
||||
|
||||
// End of isPostfix()
|
||||
|
||||
superExpr, // SuperExprNode super or super(<op>)
|
||||
superStmt, // InvokeExprNode super(<field>:<value>, <field>:<value>, ..., <field>:<value>)
|
||||
// A superStmt will only appear at the top level of an expression StmtNode.
|
||||
|
||||
Const, // UnaryExprNode const <op>
|
||||
Delete, // UnaryExprNode delete <op>
|
||||
Void, // UnaryExprNode void <op>
|
||||
Typeof, // UnaryExprNode typeof <op>
|
||||
Eval, // UnaryExprNode eval <op>
|
||||
preIncrement, // UnaryExprNode ++ <op>
|
||||
preDecrement, // UnaryExprNode -- <op>
|
||||
postIncrement, // UnaryExprNode <op> ++
|
||||
|
@ -202,16 +187,16 @@ namespace JavaScript {
|
|||
lessThan, // BinaryExprNode <op1> < <op2>
|
||||
lessThanOrEqual, // BinaryExprNode <op1> <= <op2>
|
||||
greaterThan, // BinaryExprNode <op1> > <op2>
|
||||
greaterThanOrEqual,// BinaryExprNode <op1> >= <op2>
|
||||
greaterThanOrEqual, // BinaryExprNode <op1> >= <op2>
|
||||
identical, // BinaryExprNode <op1> === <op2>
|
||||
notIdentical, // BinaryExprNode <op1> !== <op2>
|
||||
As, // BinaryExprNode <op1> as <op2>
|
||||
In, // BinaryExprNode <op1> in <op2>
|
||||
Instanceof, // BinaryExprNode <op1> instanceof <op2>
|
||||
|
||||
assignment, // BinaryExprNode <op1> = <op2>
|
||||
|
||||
// Begin of isAssigningKind()
|
||||
|
||||
addEquals, // BinaryExprNode <op1> += <op2>
|
||||
subtractEquals, // BinaryExprNode <op1> -= <op2>
|
||||
multiplyEquals, // BinaryExprNode <op1> *= <op2>
|
||||
|
@ -226,12 +211,10 @@ namespace JavaScript {
|
|||
logicalAndEquals, // BinaryExprNode <op1> &&= <op2>
|
||||
logicalXorEquals, // BinaryExprNode <op1> ^^= <op2>
|
||||
logicalOrEquals, // BinaryExprNode <op1> ||= <op2>
|
||||
|
||||
// End of isAssigningKind()
|
||||
|
||||
conditional, // TernaryExprNode <op1> ? <op2> : <op3>
|
||||
comma, // BinaryExprNode <op1> , <op2>
|
||||
// Comma expressions only
|
||||
comma, // BinaryExprNode <op1> , <op2> (Comma expressions only)
|
||||
|
||||
kindsEnd
|
||||
};
|
||||
|
@ -246,24 +229,12 @@ namespace JavaScript {
|
|||
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;}
|
||||
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;
|
||||
}
|
||||
friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;}
|
||||
};
|
||||
|
||||
// Print e onto f.
|
||||
|
@ -271,6 +242,7 @@ namespace JavaScript {
|
|||
ASSERT(e); e->print(f); return f;
|
||||
}
|
||||
|
||||
|
||||
struct FunctionName {
|
||||
enum Prefix {
|
||||
normal, // No prefix
|
||||
|
@ -286,34 +258,24 @@ namespace JavaScript {
|
|||
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
|
||||
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;
|
||||
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()) {}
|
||||
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;
|
||||
};
|
||||
|
@ -321,10 +283,8 @@ namespace JavaScript {
|
|||
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()) {}
|
||||
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;
|
||||
};
|
||||
|
@ -332,8 +292,7 @@ namespace JavaScript {
|
|||
struct StringExprNode: ExprNode {
|
||||
String &str; // The string
|
||||
|
||||
StringExprNode(uint32 pos, Kind kind, String &str) :
|
||||
ExprNode(pos, kind), str(str) {}
|
||||
StringExprNode(uint32 pos, Kind kind, String &str): ExprNode(pos, kind), str(str) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
|
@ -342,8 +301,7 @@ namespace JavaScript {
|
|||
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) :
|
||||
RegExpExprNode(uint32 pos, Kind kind, const StringAtom &re, String &flags):
|
||||
ExprNode(pos, kind), re(re), flags(flags) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
|
@ -353,18 +311,16 @@ namespace JavaScript {
|
|||
String &numStr; // The number's source string
|
||||
float64 num; // The number's value
|
||||
|
||||
NumUnitExprNode(uint32 pos, Kind kind, String &numStr, float64 num,
|
||||
String &unitStr):
|
||||
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
|
||||
ExprNode *op; // The expression to which the unit is applied; non-nil only
|
||||
|
||||
ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr) :
|
||||
ExprUnitExprNode(uint32 pos, Kind kind, ExprNode *op, String &unitStr):
|
||||
StringExprNode(pos, kind, unitStr), op(op) {ASSERT(op);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
|
@ -373,82 +329,74 @@ namespace JavaScript {
|
|||
struct FunctionExprNode: ExprNode {
|
||||
FunctionDefinition function; // Function definition
|
||||
|
||||
explicit FunctionExprNode(uint32 pos) :
|
||||
ExprNode(pos, functionLiteral) {}
|
||||
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
|
||||
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) {}
|
||||
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) {}
|
||||
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
|
||||
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);}
|
||||
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
|
||||
ExprNode *op; // The unary operator's operand; non-nil only
|
||||
|
||||
UnaryExprNode(uint32 pos, Kind kind, ExprNode *op) :
|
||||
ExprNode(pos, kind), op(op) {ASSERT(op);}
|
||||
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
|
||||
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) :
|
||||
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
|
||||
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);
|
||||
}
|
||||
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 ;
|
||||
|
@ -456,16 +404,13 @@ namespace JavaScript {
|
|||
block, // BlockStmtNode <attributes> { <statements> }
|
||||
label, // LabelStmtNode <name> : <stmt>
|
||||
If, // UnaryStmtNode if ( <expr> ) <stmt>
|
||||
IfElse, // BinaryStmtNode if ( <expr> ) <stmt> else
|
||||
// <stmt2>
|
||||
IfElse, // BinaryStmtNode if ( <expr> ) <stmt> else <stmt2>
|
||||
Switch, // SwitchStmtNode switch ( <expr> ) <statements>
|
||||
While, // UnaryStmtNode while ( <expr> ) <stmt>
|
||||
DoWhile, // UnaryStmtNode do <stmt> while ( <expr> )
|
||||
With, // UnaryStmtNode with ( <expr> ) <stmt>
|
||||
For, // ForStmtNode for ( <initializer> ; <expr2>
|
||||
// ; <expr3> ) <stmt>
|
||||
ForIn, // ForStmtNode for ( <initializer> in
|
||||
// <expr2> ) <stmt>
|
||||
For, // ForStmtNode for ( <initializer> ; <expr2> ; <expr3> ) <stmt>
|
||||
ForIn, // ForStmtNode for ( <initializer> in <expr2> ) <stmt>
|
||||
Case, // ExprStmtNode case <expr> : or default :
|
||||
// Only occurs directly inside a Switch
|
||||
Break, // GoStmtNode break ; or break <name> ;
|
||||
|
@ -476,19 +421,13 @@ namespace JavaScript {
|
|||
Import, // ImportStmtNode import <bindings> ;
|
||||
UseImport, // ImportStmtNode use import <bindings> ;
|
||||
Use, // UseStmtNode use namespace <exprs> ;
|
||||
Export, // ExportStmtNode <attributes> export
|
||||
// <bindings> ;
|
||||
Const, // VariableStmtNode <attributes> const
|
||||
// <bindings> ;
|
||||
Export, // ExportStmtNode <attributes> export <bindings> ;
|
||||
Const, // VariableStmtNode <attributes> const <bindings> ;
|
||||
Var, // VariableStmtNode <attributes> var <bindings> ;
|
||||
Function, // FunctionStmtNode <attributes> function
|
||||
// <function>
|
||||
Class, // ClassStmtNode <attributes> class <name>
|
||||
// extends <superclass> implements <supers> <body>
|
||||
Interface, // ClassStmtNode <attributes> interface <name>
|
||||
// extends <supers> <body>
|
||||
Namespace, // NamespaceStmtNode <attributes> namespace <name>
|
||||
// extends <supers>
|
||||
Function, // FunctionStmtNode <attributes> function <function>
|
||||
Class, // ClassStmtNode <attributes> class <name> extends <superclass> implements <supers> <body>
|
||||
Interface, // ClassStmtNode <attributes> interface <name> extends <supers> <body>
|
||||
Namespace, // NamespaceStmtNode <attributes> namespace <name> extends <supers>
|
||||
Language, // LanguageStmtNode language <language> ;
|
||||
Package, // PackageStmtNode package <packageName> <body>
|
||||
Debugger // ExprStmtNode debugger ;
|
||||
|
@ -497,32 +436,36 @@ namespace JavaScript {
|
|||
private:
|
||||
Kind kind; // The node's kind
|
||||
public:
|
||||
StmtNode *next; // Next statement in a linked list of statements in
|
||||
// this block
|
||||
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 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;
|
||||
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.
|
||||
struct ExprList: ArenaObject {
|
||||
ExprList *next; // Next expression in linked list
|
||||
ExprNode *expr; // Attribute expression; non-nil only
|
||||
|
||||
ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr) :
|
||||
StmtNode(pos, kind), expr(expr) {}
|
||||
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;
|
||||
};
|
||||
|
@ -533,20 +476,10 @@ namespace JavaScript {
|
|||
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
|
||||
ExprList *attributes; // Linked list of block or definition's attributes
|
||||
|
||||
AttributeStmtNode(uint32 pos, Kind kind, IdentifierList *attributes) :
|
||||
StmtNode(pos, kind), attributes(attributes) {}
|
||||
AttributeStmtNode(uint32 pos, Kind kind, ExprList *attributes): StmtNode(pos, kind), attributes(attributes) {}
|
||||
|
||||
void printAttributes(PrettyPrinter &f) const;
|
||||
};
|
||||
|
@ -554,10 +487,8 @@ namespace JavaScript {
|
|||
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)
|
||||
{}
|
||||
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;
|
||||
|
@ -567,7 +498,7 @@ namespace JavaScript {
|
|||
const StringAtom &name; // The label
|
||||
StmtNode *stmt; // Labeled statement; non-nil only
|
||||
|
||||
LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt) :
|
||||
LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt):
|
||||
StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);}
|
||||
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
|
@ -586,48 +517,32 @@ namespace JavaScript {
|
|||
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);
|
||||
}
|
||||
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
|
||||
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);
|
||||
}
|
||||
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
|
||||
StmtNode *statements; // Linked list of switch block's statements, which may include Case and Default statements
|
||||
|
||||
SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements) :
|
||||
SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements):
|
||||
ExprStmtNode(pos, Switch, expr), statements(statements) {}
|
||||
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
|
@ -636,116 +551,89 @@ namespace JavaScript {
|
|||
struct GoStmtNode: StmtNode {
|
||||
const StringAtom *name; // The label; nil if none
|
||||
|
||||
GoStmtNode(uint32 pos, Kind kind, const StringAtom *name) :
|
||||
StmtNode(pos, kind), name(name) {}
|
||||
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
|
||||
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);
|
||||
}
|
||||
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 *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);
|
||||
}
|
||||
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
|
||||
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(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
|
||||
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):
|
||||
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) :
|
||||
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) {}
|
||||
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
|
||||
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
|
||||
FunctionName *initializer; // The original variable's name or nil if not provided
|
||||
|
||||
ExportBinding(uint32 pos, FunctionName *initializer) :
|
||||
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) :
|
||||
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, IdentifierList *attributes,
|
||||
VariableBinding *bindings):
|
||||
VariableStmtNode(uint32 pos, Kind kind, ExprList *attributes, VariableBinding *bindings):
|
||||
AttributeStmtNode(pos, kind, attributes), bindings(bindings) {}
|
||||
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
|
@ -754,38 +642,28 @@ namespace JavaScript {
|
|||
struct FunctionStmtNode: AttributeStmtNode {
|
||||
FunctionDefinition function; // Function definition
|
||||
|
||||
FunctionStmtNode(uint32 pos, Kind kind, IdentifierList *attributes) :
|
||||
AttributeStmtNode(pos, kind, attributes) {}
|
||||
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
|
||||
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);
|
||||
}
|
||||
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
|
||||
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) {}
|
||||
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;
|
||||
};
|
||||
|
@ -801,11 +679,8 @@ namespace JavaScript {
|
|||
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);
|
||||
}
|
||||
PackageStmtNode(uint32 pos, Kind kind, PackageName &packageName, BlockStmtNode *body):
|
||||
StmtNode(pos, kind), packageName(packageName), body(body) {ASSERT(body);}
|
||||
};
|
||||
|
||||
|
||||
|
@ -813,12 +688,9 @@ namespace JavaScript {
|
|||
public:
|
||||
Lexer lexer;
|
||||
Arena &arena;
|
||||
bool lineBreaksSignificant; // If false, line breaks between tokens
|
||||
// are treated as though they were
|
||||
// spaces instead
|
||||
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);
|
||||
Parser(World &world, Arena &arena, const String &source, const String &sourceLocation, uint32 initialLineNum = 1);
|
||||
|
||||
private:
|
||||
Reader &getReader() {return lexer.reader;}
|
||||
|
@ -830,36 +702,18 @@ namespace JavaScript {
|
|||
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();
|
||||
}
|
||||
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 SuperState {
|
||||
ssNone, // No super operator
|
||||
ssExpr, // super or super(expr)
|
||||
ssStmt // super or super(expr) or super(arguments)
|
||||
};
|
||||
|
||||
enum Precedence {
|
||||
pNone, // End tag
|
||||
pExpression, // Expression
|
||||
pExpression, // ListExpression
|
||||
pAssignment, // AssignmentExpression
|
||||
pConditional, // ConditionalExpression
|
||||
pLogicalOr, // LogicalOrExpression
|
||||
|
@ -878,82 +732,78 @@ namespace JavaScript {
|
|||
};
|
||||
|
||||
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
|
||||
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 *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);
|
||||
}
|
||||
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 *parseParenthesizedExpression();
|
||||
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);
|
||||
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);
|
||||
StmtNode *parseBlockContents(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 *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 topLevel, bool inSwitch,
|
||||
SemicolonState &semicolonState);
|
||||
StmtNode *parseStatement(bool directive, bool inSwitch, SemicolonState &semicolonState);
|
||||
StmtNode *parseStatementAndSemicolon(SemicolonState &semicolonState);
|
||||
StmtNode *parseProgram() {return parseBlock(false, true);}
|
||||
StmtNode *parseProgram() {return parseBlockContents(false, true);}
|
||||
|
||||
private:
|
||||
bool lookahead(Token::Kind kind,bool preferRegExp=true);
|
||||
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<ExprPairList> &args);
|
||||
ExprPairList *parseArgumentListPrime(NodeQueue<ExprPairList> &args);
|
||||
ExprPairList *parseNamedArgumentListPrime(NodeQueue<ExprPairList> &args);
|
||||
VariableBinding *parseAllParameters(FunctionDefinition &fd,
|
||||
NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseNamedParameters(FunctionDefinition &fd,
|
||||
NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseAllParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseNamedParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseRestParameter();
|
||||
VariableBinding *parseParameter();
|
||||
VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd,
|
||||
NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseNamedRestParameters(FunctionDefinition &fd,
|
||||
NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseNamedRestParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> ¶ms);
|
||||
VariableBinding *parseOptionalParameter();
|
||||
VariableBinding *parseOptionalParameterPrime(VariableBinding* binding);
|
||||
VariableBinding *parseOptionalParameterPrime(VariableBinding *binding);
|
||||
VariableBinding *parseNamedParameter(NodeQueue<IdentifierList> &aliases);
|
||||
ExprNode *parseResultSignature();
|
||||
};
|
||||
|
|
|
@ -1,83 +1,81 @@
|
|||
/* -*- 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 <algorithm>
|
||||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
#endif
|
||||
beginLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mark the beginning of a line. Call this after reading every line break to
|
||||
// fill out the line start table.
|
||||
void
|
||||
Reader::beginLine()
|
||||
{
|
||||
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
|
||||
{
|
||||
uint32 JS::Reader::posToLineNum(uint32 pos) const
|
||||
{
|
||||
ASSERT(pos <= getPos());
|
||||
std::vector<const char16 *>::const_iterator i =
|
||||
std::upper_bound(linePositions.begin(), linePositions.end(),
|
||||
begin + pos);
|
||||
std::upper_bound(linePositions.begin(), linePositions.end(), begin + pos);
|
||||
ASSERT(i != linePositions.begin());
|
||||
|
||||
return static_cast<uint32>(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
|
||||
|
@ -86,10 +84,8 @@ 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
|
||||
{
|
||||
uint32 JS::Reader::getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const
|
||||
{
|
||||
lineBegin = 0;
|
||||
lineEnd = 0;
|
||||
if (lineNum < initialLineNum)
|
||||
|
@ -111,27 +107,27 @@ namespace JavaScript
|
|||
}
|
||||
lineEnd = e;
|
||||
return static_cast<uint32>(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)
|
||||
{
|
||||
void JS::Reader::beginRecording(String &recordString)
|
||||
{
|
||||
Reader::recordString = &recordString;
|
||||
recordBase = p;
|
||||
recordPos = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Append ch to the recordString.
|
||||
void
|
||||
Reader::recordChar(char16 ch)
|
||||
{
|
||||
void JS::Reader::recordChar(char16 ch)
|
||||
{
|
||||
ASSERT(recordString);
|
||||
if (recordPos) {
|
||||
if (recordPos != end && *recordPos == ch) {
|
||||
|
@ -143,42 +139,41 @@ namespace JavaScript
|
|||
}
|
||||
}
|
||||
*recordString += ch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Finish recording characters into the recordString that was last passed to
|
||||
// beginRecording(). Return that recordString.
|
||||
String &
|
||||
Reader::endRecording()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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 <CR> and <CR><LF> sequences to <LF> characters; a <CR><LF> sequence
|
||||
// only counts as one character.
|
||||
size_t
|
||||
LineReader::readLine(string &str)
|
||||
{
|
||||
size_t JS::LineReader::readLine(string &str)
|
||||
{
|
||||
int ch;
|
||||
bool oldCRWasLast = crWasLast;
|
||||
crWasLast = false;
|
||||
|
@ -200,17 +195,15 @@ namespace JavaScript
|
|||
}
|
||||
|
||||
return str.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
LineReader::readLine(String &wstr)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
} /* namespace JavaScript */
|
||||
}
|
||||
|
|
|
@ -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
|
||||
public:
|
||||
const String source; // Source text
|
||||
const String sourceLocation; // Description of location from which
|
||||
// the source text came
|
||||
const String sourceLocation; // Description of location from which the source text came
|
||||
private:
|
||||
const uint32 initialLineNum; // One-based number of current line
|
||||
std::vector<const char16 *> linePositions; // Array of line starts
|
||||
// recorded by beginLine()
|
||||
std::vector<const char16 *> linePositions; // Array of line starts recorded by beginLine()
|
||||
|
||||
String *recordString; // String, if any, into which recordChar()
|
||||
// records characters; not owned by the Reader
|
||||
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
|
||||
const char16 *recordPos; // Position of last recordChar() call; nil if a discrepancy occurred
|
||||
public:
|
||||
Reader(const String &source, const String &sourceLocation,
|
||||
uint32 initialLineNum = 1);
|
||||
Reader(const String &source, const String &sourceLocation, uint32 initialLineNum = 1);
|
||||
private:
|
||||
Reader(const Reader&); // No copy constructor
|
||||
void operator=(const Reader&);// No assignment operator
|
||||
void operator=(const Reader&); // No assignment operator
|
||||
public:
|
||||
|
||||
char16 get() {ASSERT(p <= end);return *p++;}
|
||||
|
@ -92,8 +86,7 @@ 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();
|
||||
|
@ -101,6 +94,7 @@ namespace JavaScript {
|
|||
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
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
/* -*- 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
|
||||
{
|
||||
namespace JS = JavaScript;
|
||||
|
||||
const char *const Token::kindNames[kindsEnd] = {
|
||||
|
||||
const char *const JS::Token::kindNames[kindsEnd] = {
|
||||
|
||||
// Special
|
||||
"end of input", // end
|
||||
|
@ -109,6 +109,7 @@ namespace JavaScript
|
|||
|
||||
// Reserved words
|
||||
"abstract", // Abstract
|
||||
"as", // As
|
||||
"break", // Break
|
||||
"case", // Case
|
||||
"catch", // Catch
|
||||
|
@ -162,22 +163,21 @@ namespace JavaScript
|
|||
"while", // While
|
||||
"with", // With
|
||||
|
||||
// Non-reserved words
|
||||
// Non-reserved words
|
||||
"eval", // Eval
|
||||
"exclude", // Exclude
|
||||
"get", // Get
|
||||
"include", // Include
|
||||
"set" // Set
|
||||
};
|
||||
};
|
||||
|
||||
const uchar followRet = 1<<Token::canFollowReturn;
|
||||
const uchar isAttr = 1<<Token::isAttribute |
|
||||
1<<Token::canFollowAttribute;
|
||||
const uchar followAttr = 1<<Token::canFollowAttribute;
|
||||
const uchar followGet = 1<<Token::canFollowGet;
|
||||
|
||||
const uchar Token::kindFlags[kindsEnd] = {
|
||||
static const uchar followRet = 1<<JS::Token::canFollowReturn;
|
||||
static const uchar isAttr = 1<<JS::Token::isAttribute | 1<<JS::Token::canFollowAttribute;
|
||||
static const uchar followAttr = 1<<JS::Token::canFollowAttribute;
|
||||
static const uchar followGet = 1<<JS::Token::canFollowGet;
|
||||
|
||||
const uchar JS::Token::kindFlags[kindsEnd] = {
|
||||
// Special
|
||||
followRet, // end
|
||||
0, // number
|
||||
|
@ -246,7 +246,8 @@ namespace JavaScript
|
|||
0, // question
|
||||
|
||||
// Reserved words
|
||||
followAttr, // Abstract
|
||||
isAttr, // Abstract
|
||||
0, // As
|
||||
0, // Break
|
||||
0, // Case
|
||||
0, // Catch
|
||||
|
@ -261,7 +262,7 @@ namespace JavaScript
|
|||
0, // Enum
|
||||
followAttr, // Export
|
||||
0, // Extends
|
||||
0, // False
|
||||
isAttr, // False
|
||||
isAttr, // Final
|
||||
0, // Finally
|
||||
0, // For
|
||||
|
@ -290,7 +291,7 @@ namespace JavaScript
|
|||
0, // Throw
|
||||
0, // Throws
|
||||
followAttr, // Transient
|
||||
0, // True
|
||||
isAttr, // True
|
||||
0, // Try
|
||||
0, // Typeof
|
||||
0, // Use
|
||||
|
@ -310,21 +311,20 @@ namespace JavaScript
|
|||
isAttr|followGet // identifier
|
||||
};
|
||||
|
||||
|
||||
// Initialize the keywords in the given world.
|
||||
void
|
||||
Token::initKeywords(World &world)
|
||||
{
|
||||
void JS::Token::initKeywords(World &world)
|
||||
{
|
||||
const char *const*keywordName = kindNames + keywordsBegin;
|
||||
for (Kind kind = keywordsBegin; kind != keywordsEnd;
|
||||
kind = Kind(kind+1))
|
||||
world.identifiers[widenCString(*keywordName++)].tokenKind = kind;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Print a description of the token to f.
|
||||
void
|
||||
Token::print(Formatter &f, bool debug) const
|
||||
{
|
||||
void JS::Token::print(Formatter &f, bool debug) const
|
||||
{
|
||||
switch (getKind()) {
|
||||
case end:
|
||||
f << "[end]";
|
||||
|
@ -357,6 +357,4 @@ namespace JavaScript
|
|||
default:
|
||||
f << getKind();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,8 +47,7 @@ namespace JavaScript
|
|||
class Token {
|
||||
public:
|
||||
enum Kind {
|
||||
// Keep synchronized with kindNames, kindFlags, and
|
||||
// tokenBinaryOperatorInfos tables
|
||||
// Keep synchronized with kindNames, kindFlags, and tokenBinaryOperatorInfos tables
|
||||
|
||||
// Special
|
||||
end, // End of token stream
|
||||
|
@ -92,16 +91,12 @@ namespace JavaScript
|
|||
logicalAnd, // &&
|
||||
logicalXor, // ^^
|
||||
logicalOr, // ||
|
||||
bitwiseAnd, // &
|
||||
|
||||
// These must be at constant offsets from logicalAnd ... logicalOr
|
||||
bitwiseAnd, // & These must be at constant offsets from logicalAnd ... logicalOr
|
||||
bitwiseXor, // ^
|
||||
bitwiseOr, // |
|
||||
|
||||
assignment, // =
|
||||
|
||||
// These must be at constant offsets from times ... bitwiseOr
|
||||
timesEquals, // *=
|
||||
timesEquals, // *= These must be at constant offsets from times ... bitwiseOr
|
||||
divideEquals, // /=
|
||||
moduloEquals, // %=
|
||||
plusEquals, // +=
|
||||
|
@ -120,9 +115,7 @@ namespace JavaScript
|
|||
notEqual, // !=
|
||||
lessThan, // <
|
||||
lessThanOrEqual, // <=
|
||||
greaterThan, // >
|
||||
|
||||
// >, >= must be at constant offsets from <, <=
|
||||
greaterThan, // > >, >= must be at constant offsets from <, <=
|
||||
greaterThanOrEqual, // >=
|
||||
identical, // ===
|
||||
notIdentical, // !==
|
||||
|
@ -131,6 +124,7 @@ namespace JavaScript
|
|||
|
||||
// Reserved words
|
||||
Abstract, // abstract
|
||||
As, // as
|
||||
Break, // break
|
||||
Case, // case
|
||||
Catch, // catch
|
||||
|
@ -191,23 +185,15 @@ namespace JavaScript
|
|||
Include, // include
|
||||
Set, // set
|
||||
|
||||
identifier, // Non-keyword identifier
|
||||
// (may be same as a keyword if it
|
||||
// contains an escape code)
|
||||
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
|
||||
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 \
|
||||
|
@ -228,12 +214,9 @@ namespace JavaScript
|
|||
|
||||
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
|
||||
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:
|
||||
|
@ -246,11 +229,8 @@ namespace JavaScript
|
|||
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
|
||||
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
|
||||
|
@ -259,42 +239,18 @@ namespace JavaScript
|
|||
|
||||
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<<f) != 0;
|
||||
}
|
||||
bool hasIdentifierKind() const {ASSERT(nonreservedEnd == identifier && kindsEnd == identifier+1); return kind >= nonreservedBegin;}
|
||||
bool getFlag(Flag f) const {ASSERT(valid); return (kindFlags[kind] & 1<<f) != 0;}
|
||||
bool getLineBreak() const {ASSERT(valid); return lineBreak;}
|
||||
uint32 getPos() const {ASSERT(valid); return pos;}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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,8 +44,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
namespace JavaScript
|
||||
{
|
||||
namespace JS = JavaScript;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef XP_MAC
|
||||
|
@ -54,9 +54,8 @@ 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)
|
||||
{
|
||||
static void PStrFromCStr(const char* src, Str255 &dst)
|
||||
{
|
||||
int length = 0;
|
||||
|
||||
if (src)
|
||||
|
@ -72,20 +71,18 @@ namespace JavaScript
|
|||
length = 255 - spaceLeft;
|
||||
}
|
||||
dst[0] = (uchar)length;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
jsdebugstr(const char *debuggerMsg)
|
||||
{
|
||||
static void jsdebugstr(const char *debuggerMsg)
|
||||
{
|
||||
Str255 pStr;
|
||||
|
||||
PStrFromCStr(debuggerMsg, pStr);
|
||||
DebugStr(pStr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dprintf(const char *format, ...)
|
||||
{
|
||||
static void dprintf(const char *format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
char buffer[4096];
|
||||
|
||||
|
@ -94,14 +91,12 @@ namespace JavaScript
|
|||
va_end(ap);
|
||||
|
||||
jsdebugstr(buffer);
|
||||
}
|
||||
}
|
||||
#endif /* XP_MAC */
|
||||
|
||||
|
||||
void
|
||||
Assert(const char *s, const char *file, int line)
|
||||
{
|
||||
|
||||
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);
|
||||
#endif
|
||||
|
@ -114,15 +109,14 @@ namespace JavaScript
|
|||
#ifndef XP_MAC
|
||||
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 JS::ceilingLog2(uint32 n)
|
||||
{
|
||||
uint log2 = 0;
|
||||
|
||||
if (n & (n-1))
|
||||
|
@ -138,15 +132,14 @@ namespace JavaScript
|
|||
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 JS::floorLog2(uint32 n)
|
||||
{
|
||||
uint log2 = 0;
|
||||
|
||||
if (n >> 16)
|
||||
|
@ -160,6 +153,4 @@ namespace JavaScript
|
|||
if (n >> 1)
|
||||
log2++;
|
||||
return log2;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#define utilities_h___
|
||||
|
||||
#ifdef MSC_VER
|
||||
// diasble long identifier warnings
|
||||
// disable long identifier warnings
|
||||
# pragma warning(disable: 4786)
|
||||
#endif
|
||||
|
||||
|
@ -62,9 +62,9 @@ namespace JavaScript
|
|||
# define DEBUG_ONLY(_stmt)
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Random Crap
|
||||
//
|
||||
// Mathematics
|
||||
//
|
||||
|
||||
template<class N> N min(N v1, N v2) {return v1 <= v2 ? v1 : v2;}
|
||||
|
@ -72,7 +72,5 @@ namespace JavaScript
|
|||
|
||||
uint ceilingLog2(uint32 n);
|
||||
uint floorLog2(uint32 n);
|
||||
|
||||
}
|
||||
|
||||
#endif /* utilities_h___ */
|
||||
|
|
|
@ -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<StringAtom, const String&> 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 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче