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:
waldemar%netscape.com 2001-06-13 21:24:27 +00:00
Родитель 8e0358e13a
Коммит c3cb31ba54
16 изменённых файлов: 5601 добавлений и 9954 удалений

Просмотреть файл

@ -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 ) {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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 &copyTokenChars(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> &params);
VariableBinding *parseNamedParameters(FunctionDefinition &fd,
NodeQueue<VariableBinding> &params);
VariableBinding *parseAllParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> &params);
VariableBinding *parseNamedParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> &params);
VariableBinding *parseRestParameter();
VariableBinding *parseParameter();
VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd,
NodeQueue<VariableBinding> &params);
VariableBinding *parseNamedRestParameters(FunctionDefinition &fd,
NodeQueue<VariableBinding> &params);
VariableBinding *parseOptionalNamedRestParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> &params);
VariableBinding *parseNamedRestParameters(FunctionDefinition &fd, NodeQueue<VariableBinding> &params);
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 {