Implemented Formatters for output

This commit is contained in:
waldemar%netscape.com 2000-04-06 23:47:33 +00:00
Родитель 5d892e7bf7
Коммит f9ce82ae8e
8 изменённых файлов: 698 добавлений и 322 удалений

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

@ -22,8 +22,6 @@
// JS2 shell.
//
#include <algorithm>
#include "world.h"
#include "interpreter.h"
@ -31,80 +29,7 @@ namespace JS = JavaScript;
using namespace JavaScript;
#ifdef XP_MAC
#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 *str, int length)
{
char *limit = str + length;
while (str != limit) {
if (*str == '\n')
*str = '\r';
str++;
}
}
int fputc(int c, FILE *file)
{
char buffer = c;
if (buffer == '\n')
buffer = '\r';
return fwrite(&buffer, 1, 1, file);
}
int fputs(const char *s, FILE *file)
{
char buffer[4096];
int n = strlen(s);
int extra = 0;
while (n > sizeof buffer) {
memcpy(buffer, s, sizeof buffer);
translateLFtoCR(buffer, sizeof buffer);
extra += fwrite(buffer, 1, sizeof buffer, file);
n -= sizeof buffer;
s += sizeof buffer;
}
memcpy(buffer, s, n);
translateLFtoCR(buffer, n);
return extra + fwrite(buffer, 1, n, file);
}
int fprintf(FILE* file, const char *format, ...)
{
va_list args;
char smallBuffer[4096];
int n;
int bufferSize = sizeof smallBuffer;
char *buffer = smallBuffer;
int result;
va_start(args, format);
n = vsnprintf(buffer, bufferSize, format, args);
va_end(args);
while (n < 0) {
if (buffer != smallBuffer)
free(buffer);
bufferSize <<= 1;
buffer = malloc(bufferSize);
if (!buffer) {
ASSERT(false);
return 0;
}
va_start(args, format);
n = vsnprintf(buffer, bufferSize, format, args);
va_end(args);
}
translateLFtoCR(buffer, n);
result = fwrite(buffer, 1, n, file);
if (buffer != smallBuffer)
free(buffer);
return result;
}
#else /* XP_MAC_MPW */
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
#include <SIOUX.h>
#include <MacTypes.h>
@ -118,65 +43,69 @@ static void initConsole(StringPtr consoleName, const char* startupMessage, int &
// Set up a buffer for stderr (otherwise it's a pig).
setvbuf(stderr, new char[BUFSIZ], _IOLBF, BUFSIZ);
std::cout << startupMessage;
stdOut << startupMessage;
argc = 1;
argv = mac_argv;
}
#endif /* XP_MAC_MPW */
#endif /* XP_MAC */
#endif
// Interactively read a line from the input stream in and put it into s.
static bool promptLine(istream &in, string &s, const char *prompt)
// Return false if reached the end of input before reading anything.
static bool promptLine(LineReader &inReader, string &s, const char *prompt)
{
std::cout << prompt;
#ifdef XP_MAC_MPW
/* Print a CR after the prompt because MPW grabs the entire line when entering an interactive command */
std::cout << std::endl;
#endif
#ifndef _WIN32
return std::getline(in, s) != 0;
#else
char buffer[256];
bool result = fgets(buffer, sizeof(buffer), stdin) != 0;
s = buffer;
return result;
#endif
if (prompt) {
stdOut << prompt;
#ifdef XP_MAC_MPW
// Print a CR after the prompt because MPW grabs the entire line when entering an interactive command.
stdOut << '\n';
#endif
}
return inReader.readLine(s) != 0;
}
static void readEvalPrint(istream &in, World &world)
const bool showTokens = true;
static void readEvalPrint(FILE *in, World &world)
{
String buffer;
string line;
String sourceLocation = widenCString("console");
LineReader inReader(in);
while (promptLine(in, line, buffer.empty() ? "js> " : "")) {
if (!buffer.empty())
buffer += uni::lf;
while (promptLine(inReader, line, buffer.empty() ? "js> " : 0)) {
appendChars(buffer, line.data(), line.size());
if (!buffer.empty()) {
try {
Lexer l(world, buffer, sourceLocation);
try {
Arena a;
Parser p(world, a, buffer, sourceLocation);
if (showTokens) {
Lexer &l = p.lexer;
while (true) {
const Token &t = l.get(true);
if (t.hasKind(Token::end))
break;
String out;
out += ' ';
t.print(out, true);
showString(std::cout, out);
stdOut << ' ';
t.print(stdOut, true);
}
} catch (Exception &e) {
std::cout << std::endl;
showString(std::cout, e.fullMessage());
} else {
ExprNode *parseTree = p.parsePostfixExpression();
}
std::cout << std::endl;
clear(buffer);
stdOut << '\n';
} catch (Exception &e) {
// If we got a syntax error on the end of input, then wait for a continuation
// of input rather than printing the error message.
if (!(e.hasKind(Exception::syntaxError) && e.lineNum && e.pos == buffer.size() &&
e.sourceFile == sourceLocation)) {
stdOut << '\n' << e.fullMessage();
clear(buffer);
}
}
}
std::cout << std::endl;
stdOut << '\n';
#if 0
do {
bufp = buffer;
@ -276,7 +205,7 @@ static int ProcessInputFile(JSContext *cx, JSObject *obj, char *filename)
static int
usage(void)
{
std::cerr << "usage: js [-s] [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n";
stdErr << "usage: js [-s] [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n";
return 2;
}
@ -474,7 +403,7 @@ int main(int argc, char **argv)
testInterpreter(5);
testICG(world);
#endif
readEvalPrint(std::cin, world);
readEvalPrint(stdin, world);
return 0;
//return ProcessArgs(argv + 1, argc - 1);

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

@ -21,7 +21,6 @@
#include <cstdlib>
#include <cstring>
#include <cfloat>
#include <algorithm>
#include "numerics.h"
namespace JS = JavaScript;
@ -2735,10 +2734,22 @@ size_t JS::doubleToBaseStr(char *buffer, double value, uint base)
// A version of doubleToStr that appends to the end of String dst.
void JS::printDouble(String &dst, double value, DToStrMode mode, int precision)
// precision should not exceed 101.
void JS::appendDouble(String &dst, double value, DToStrMode mode, int precision)
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
dst += doubleToStr(buffer, sizeof buffer, value, mode, precision);
}
// A version of doubleToStr that prints to Formatter f.
// precision should not exceed 101.
void JS::printDouble(Formatter &f, double value, DToStrMode mode, int precision)
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
f << doubleToStr(buffer, sizeof buffer, value, mode, precision);
}

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

@ -139,7 +139,9 @@ namespace JavaScript {
char *doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision);
size_t doubleToBaseStr(char *buffer, double value, uint base);
void printDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline String &operator+=(String &s, double value) {printDouble(s, value); return s;}
void appendDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline String &operator+=(String &s, double value) {appendDouble(s, value); return s;}
void printDouble(Formatter &f, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline Formatter &operator<<(Formatter &f, double value) {printDouble(f, value); return f;}
}
#endif

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

@ -20,7 +20,6 @@
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include "utilities.h"
#ifdef WIN32
@ -1563,7 +1562,7 @@ struct JS::Arena::DestructorEntry: JS::ArenaObject {
// Construct an Arena that allocates memory in chunks of the given size.
JS::Arena::Arena(size_t blockSize): blockSize(blockSize), freeBegin(0), freeEnd(0)
JS::Arena::Arena(size_t blockSize): freeBegin(0), freeEnd(0), blockSize(blockSize), destructorEntries(0)
{
ASSERT(blockSize && !(blockSize & basicAlignment-1));
rootDirectory.next = 0;
@ -1691,56 +1690,300 @@ JS::String &JS::newArenaString(Arena &arena, const String &str)
//
// C++ I/O
// Output
//
#ifdef __GNUC__
JS::SaveFormat::SaveFormat(ostream &) {}
JS::SaveFormat::~SaveFormat() {}
#else
JS::SaveFormat::SaveFormat(ostream &out): o(out), flags(out.flags()), fill(out.fill()) {}
JS::SaveFormat::~SaveFormat()
{
o.flags(flags);
o.fill(fill);
}
#endif
// Quotes for printing non-ASCII characters on an ASCII stream
#ifdef XP_MAC
const char beginUnprintable = char(0xC7);
const char endUnprintable = char(0xC8);
#else
const char beginUnprintable = '{';
const char endUnprintable = '}';
#endif
void JS::showChar(ostream &out, char16 ch)
{
#ifdef XP_MAC_MPW
if (ch == '\n')
out << '\r';
else
#endif
if (uchar16(ch) <= 0x7E && (uchar16(ch) >= ' ' || ch == '\n' || ch == '\t'))
out << static_cast<char>(ch);
else {
SaveFormat sf(out);
#ifdef __GNUC__
out << beginUnprintable << std::hex << std::setw(4) << std::setfill('0') << (uint16)ch << endUnprintable;
#else
out << beginUnprintable << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << (uint16)ch << endUnprintable;
#endif
// Macintosh MPW replacements for the ANSI routines. These translate LF's to CR's because
// the MPW libraries supplied by Metrowerks don't do that for some reason.
static void translateLFtoCR(char *begin, char *end)
{
while (begin != end) {
if (*begin == '\n')
*begin = '\r';
++begin;
}
}
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;
char buffer[1024];
while (n > sizeof buffer) {
memcpy(buffer, s, sizeof buffer);
translateLFtoCR(buffer, buffer + sizeof buffer);
extra += fwrite(buffer, 1, sizeof buffer, file);
n -= sizeof buffer;
s += sizeof buffer;
}
memcpy(buffer, s, n);
translateLFtoCR(buffer, buffer + n);
return extra + fwrite(buffer, 1, n, file);
}
int std::fputc(int c, FILE *file)
{
char buffer = c;
if (buffer == '\n')
buffer = '\r';
return fwrite(&buffer, 1, 1, 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, ...)
{
Buffer<char, 1024> b;
while (true) {
va_list args;
va_start(args, format);
int n = vsnprintf(b.buffer, b.size, format, args);
va_end(args);
if (n >= 0 && n < b.size) {
translateLFtoCR(b.buffer, b.buffer + n);
return static_cast<int>(fwrite(b.buffer, 1, n, file));
}
b.expand(b.size*2);
}
}
#endif // XP_MAC_MPW
static const printCharBufferSize = 64;
// Print ch count times.
void JS::printChar(Formatter &f, char ch, int count)
{
char str[printCharBufferSize];
while (count > 0) {
int c = count;
if (c > printCharBufferSize)
c = printCharBufferSize;
count -= c;
STD::memset(str, ch, static_cast<size_t>(count));
printString(f, str, str+c);
}
}
void JS::showString(ostream &out, const String &str)
// Print ch count times.
void JS::printChar(Formatter &f, char16 ch, int count)
{
showString(out, str.begin(), str.end());
char16 str[printCharBufferSize];
while (count > 0) {
int c = count;
if (c > printCharBufferSize)
c = printCharBufferSize;
count -= c;
char16 *strEnd = str + c;
std::fill(str, strEnd, ch);
printString(f, str, strEnd);
}
}
// Print i using the given formatting string, padding on the left with pad characters
// to use at least nDigits characters.
void 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 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
#elif defined _WIN32
static const char unprintableFormat[] = "\xAB%.4X\xBB"; // Use angle quotes
#else
static const char unprintableFormat[] = "<%.4X>";
#endif
static const uint16 defaultFilterRanges[] = {
0x00, 0x09, // Filter all control characters except \t and \n
0x0B, 0x20,
0x7F, 0x100, // Filter all non-ASCII characters
0, 0
};
JS::BitSet<256> JS::AsciiFileFormatter::defaultFilter(defaultFilterRanges);
// Construct an AsciiFileFormatter using the given file and filter.
// If the filter is nil, use the default filter.
JS::AsciiFileFormatter::AsciiFileFormatter(FILE *file, BitSet<256> *filter):
file(file), filter(filter ? *filter : defaultFilter)
{
filterEmpty = AsciiFileFormatter::filter.none();
}
// Write ch, escaping non-ASCII characters.
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 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 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 JS::AsciiFileFormatter::printStr8(const char *strBegin, const char *strEnd)
{
if (filterEmpty)
printChars(file, strBegin, strEnd);
else {
ASSERT(strEnd >= strBegin);
const char *p = strBegin;
while (strBegin != strEnd) {
char ch = *strBegin;
if (filterChar(ch)) {
if (p != strBegin) {
printChars(file, p, strBegin);
p = strBegin;
}
fprintf(file, unprintableFormat, static_cast<uchar>(ch));
}
++strBegin;
}
if (p != strBegin)
printChars(file, p, strBegin);
}
}
// Write the string between strBegin and strEnd, escaping non-ASCII characters.
void JS::AsciiFileFormatter::printStr16(const char16 *strBegin, const char16 *strEnd)
{
char buffer[512];
ASSERT(strEnd >= strBegin);
char *q = buffer;
while (strBegin != strEnd) {
char16 ch = *strBegin++;
if (filterChar(ch)) {
if (q != buffer) {
printChars(file, buffer, q);
q = buffer;
}
fprintf(file, unprintableFormat, char16Value(ch));
} else {
*q++ = static_cast<char>(ch);
if (q == buffer + sizeof buffer) {
printChars(file, buffer, buffer + sizeof buffer);
q = buffer;
}
}
}
if (q != buffer)
printChars(file, buffer, q);
}
// Write the String s, escaping non-ASCII characters.
void JS::AsciiFileFormatter::printString16(const String &s)
{
const char16 *begin = s.data();
printStr16(begin, begin + s.size());
}
// Write the printf format using the supplied args, escaping non-ASCII characters.
void JS::AsciiFileFormatter::printVFormat8(const char *format, va_list args)
{
Buffer<char, 1024> b;
while (true) {
int n = vsnprintf(b.buffer, b.size, format, args);
if (n >= 0 && n < b.size) {
printStr8(b.buffer, b.buffer + n);
return;
}
b.expand(b.size*2);
}
}
JS::AsciiFileFormatter JS::stdOut(stdout);
JS::AsciiFileFormatter JS::stdErr(stderr);
//
// Input
//
// 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 JS::LineReader::readLine(string &str)
{
int ch;
bool oldCRWasLast = crWasLast;
crWasLast = false;
str.resize(0);
while ((ch = getc(in)) != EOF) {
if (ch == '\n') {
if (!str.size() && oldCRWasLast)
continue;
str += '\n';
break;
}
if (ch == '\r') {
crWasLast = true;
str += '\n';
break;
}
str += static_cast<char>(ch);
}
return str.size();
}
@ -1750,7 +1993,8 @@ void JS::showString(ostream &out, const String &str)
static const char *const kindStrings[] = {
"Syntax error" // SyntaxError
"Syntax error", // syntaxError
"Stack overflow" // stackOverflow
};
// Return a null-terminated string describing the exception's kind.
@ -1763,7 +2007,8 @@ const char *JS::Exception::kindString() const
// Return the full error message.
JS::String JS::Exception::fullMessage() const
{
String m(sourceFile);
String m(widenCString("In "));
m += sourceFile;
if (lineNum) {
char b[32];
sprintf(b, ", line %d:\n", lineNum);
@ -1779,6 +2024,7 @@ JS::String JS::Exception::fullMessage() const
m += kindString();
m += ": ";
m += message;
m += '\n';
return m;
}

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

@ -21,7 +21,6 @@
#include <cstdlib>
#include <cstring>
#include <cfloat>
#include <algorithm>
#include "numerics.h"
namespace JS = JavaScript;
@ -2735,10 +2734,22 @@ size_t JS::doubleToBaseStr(char *buffer, double value, uint base)
// A version of doubleToStr that appends to the end of String dst.
void JS::printDouble(String &dst, double value, DToStrMode mode, int precision)
// precision should not exceed 101.
void JS::appendDouble(String &dst, double value, DToStrMode mode, int precision)
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
dst += doubleToStr(buffer, sizeof buffer, value, mode, precision);
}
// A version of doubleToStr that prints to Formatter f.
// precision should not exceed 101.
void JS::printDouble(Formatter &f, double value, DToStrMode mode, int precision)
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
f << doubleToStr(buffer, sizeof buffer, value, mode, precision);
}

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

@ -139,7 +139,9 @@ namespace JavaScript {
char *doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision);
size_t doubleToBaseStr(char *buffer, double value, uint base);
void printDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline String &operator+=(String &s, double value) {printDouble(s, value); return s;}
void appendDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline String &operator+=(String &s, double value) {appendDouble(s, value); return s;}
void printDouble(Formatter &f, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline Formatter &operator<<(Formatter &f, double value) {printDouble(f, value); return f;}
}
#endif

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

@ -20,7 +20,6 @@
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include "utilities.h"
#ifdef WIN32
@ -1563,7 +1562,7 @@ struct JS::Arena::DestructorEntry: JS::ArenaObject {
// Construct an Arena that allocates memory in chunks of the given size.
JS::Arena::Arena(size_t blockSize): blockSize(blockSize), freeBegin(0), freeEnd(0)
JS::Arena::Arena(size_t blockSize): freeBegin(0), freeEnd(0), blockSize(blockSize), destructorEntries(0)
{
ASSERT(blockSize && !(blockSize & basicAlignment-1));
rootDirectory.next = 0;
@ -1691,56 +1690,300 @@ JS::String &JS::newArenaString(Arena &arena, const String &str)
//
// C++ I/O
// Output
//
#ifdef __GNUC__
JS::SaveFormat::SaveFormat(ostream &) {}
JS::SaveFormat::~SaveFormat() {}
#else
JS::SaveFormat::SaveFormat(ostream &out): o(out), flags(out.flags()), fill(out.fill()) {}
JS::SaveFormat::~SaveFormat()
{
o.flags(flags);
o.fill(fill);
}
#endif
// Quotes for printing non-ASCII characters on an ASCII stream
#ifdef XP_MAC
const char beginUnprintable = char(0xC7);
const char endUnprintable = char(0xC8);
#else
const char beginUnprintable = '{';
const char endUnprintable = '}';
#endif
void JS::showChar(ostream &out, char16 ch)
{
#ifdef XP_MAC_MPW
if (ch == '\n')
out << '\r';
else
#endif
if (uchar16(ch) <= 0x7E && (uchar16(ch) >= ' ' || ch == '\n' || ch == '\t'))
out << static_cast<char>(ch);
else {
SaveFormat sf(out);
#ifdef __GNUC__
out << beginUnprintable << std::hex << std::setw(4) << std::setfill('0') << (uint16)ch << endUnprintable;
#else
out << beginUnprintable << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << (uint16)ch << endUnprintable;
#endif
// Macintosh MPW replacements for the ANSI routines. These translate LF's to CR's because
// the MPW libraries supplied by Metrowerks don't do that for some reason.
static void translateLFtoCR(char *begin, char *end)
{
while (begin != end) {
if (*begin == '\n')
*begin = '\r';
++begin;
}
}
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;
char buffer[1024];
while (n > sizeof buffer) {
memcpy(buffer, s, sizeof buffer);
translateLFtoCR(buffer, buffer + sizeof buffer);
extra += fwrite(buffer, 1, sizeof buffer, file);
n -= sizeof buffer;
s += sizeof buffer;
}
memcpy(buffer, s, n);
translateLFtoCR(buffer, buffer + n);
return extra + fwrite(buffer, 1, n, file);
}
int std::fputc(int c, FILE *file)
{
char buffer = c;
if (buffer == '\n')
buffer = '\r';
return fwrite(&buffer, 1, 1, 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, ...)
{
Buffer<char, 1024> b;
while (true) {
va_list args;
va_start(args, format);
int n = vsnprintf(b.buffer, b.size, format, args);
va_end(args);
if (n >= 0 && n < b.size) {
translateLFtoCR(b.buffer, b.buffer + n);
return static_cast<int>(fwrite(b.buffer, 1, n, file));
}
b.expand(b.size*2);
}
}
#endif // XP_MAC_MPW
static const printCharBufferSize = 64;
// Print ch count times.
void JS::printChar(Formatter &f, char ch, int count)
{
char str[printCharBufferSize];
while (count > 0) {
int c = count;
if (c > printCharBufferSize)
c = printCharBufferSize;
count -= c;
STD::memset(str, ch, static_cast<size_t>(count));
printString(f, str, str+c);
}
}
void JS::showString(ostream &out, const String &str)
// Print ch count times.
void JS::printChar(Formatter &f, char16 ch, int count)
{
showString(out, str.begin(), str.end());
char16 str[printCharBufferSize];
while (count > 0) {
int c = count;
if (c > printCharBufferSize)
c = printCharBufferSize;
count -= c;
char16 *strEnd = str + c;
std::fill(str, strEnd, ch);
printString(f, str, strEnd);
}
}
// Print i using the given formatting string, padding on the left with pad characters
// to use at least nDigits characters.
void 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 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
#elif defined _WIN32
static const char unprintableFormat[] = "\xAB%.4X\xBB"; // Use angle quotes
#else
static const char unprintableFormat[] = "<%.4X>";
#endif
static const uint16 defaultFilterRanges[] = {
0x00, 0x09, // Filter all control characters except \t and \n
0x0B, 0x20,
0x7F, 0x100, // Filter all non-ASCII characters
0, 0
};
JS::BitSet<256> JS::AsciiFileFormatter::defaultFilter(defaultFilterRanges);
// Construct an AsciiFileFormatter using the given file and filter.
// If the filter is nil, use the default filter.
JS::AsciiFileFormatter::AsciiFileFormatter(FILE *file, BitSet<256> *filter):
file(file), filter(filter ? *filter : defaultFilter)
{
filterEmpty = AsciiFileFormatter::filter.none();
}
// Write ch, escaping non-ASCII characters.
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 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 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 JS::AsciiFileFormatter::printStr8(const char *strBegin, const char *strEnd)
{
if (filterEmpty)
printChars(file, strBegin, strEnd);
else {
ASSERT(strEnd >= strBegin);
const char *p = strBegin;
while (strBegin != strEnd) {
char ch = *strBegin;
if (filterChar(ch)) {
if (p != strBegin) {
printChars(file, p, strBegin);
p = strBegin;
}
fprintf(file, unprintableFormat, static_cast<uchar>(ch));
}
++strBegin;
}
if (p != strBegin)
printChars(file, p, strBegin);
}
}
// Write the string between strBegin and strEnd, escaping non-ASCII characters.
void JS::AsciiFileFormatter::printStr16(const char16 *strBegin, const char16 *strEnd)
{
char buffer[512];
ASSERT(strEnd >= strBegin);
char *q = buffer;
while (strBegin != strEnd) {
char16 ch = *strBegin++;
if (filterChar(ch)) {
if (q != buffer) {
printChars(file, buffer, q);
q = buffer;
}
fprintf(file, unprintableFormat, char16Value(ch));
} else {
*q++ = static_cast<char>(ch);
if (q == buffer + sizeof buffer) {
printChars(file, buffer, buffer + sizeof buffer);
q = buffer;
}
}
}
if (q != buffer)
printChars(file, buffer, q);
}
// Write the String s, escaping non-ASCII characters.
void JS::AsciiFileFormatter::printString16(const String &s)
{
const char16 *begin = s.data();
printStr16(begin, begin + s.size());
}
// Write the printf format using the supplied args, escaping non-ASCII characters.
void JS::AsciiFileFormatter::printVFormat8(const char *format, va_list args)
{
Buffer<char, 1024> b;
while (true) {
int n = vsnprintf(b.buffer, b.size, format, args);
if (n >= 0 && n < b.size) {
printStr8(b.buffer, b.buffer + n);
return;
}
b.expand(b.size*2);
}
}
JS::AsciiFileFormatter JS::stdOut(stdout);
JS::AsciiFileFormatter JS::stdErr(stderr);
//
// Input
//
// 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 JS::LineReader::readLine(string &str)
{
int ch;
bool oldCRWasLast = crWasLast;
crWasLast = false;
str.resize(0);
while ((ch = getc(in)) != EOF) {
if (ch == '\n') {
if (!str.size() && oldCRWasLast)
continue;
str += '\n';
break;
}
if (ch == '\r') {
crWasLast = true;
str += '\n';
break;
}
str += static_cast<char>(ch);
}
return str.size();
}
@ -1750,7 +1993,8 @@ void JS::showString(ostream &out, const String &str)
static const char *const kindStrings[] = {
"Syntax error" // SyntaxError
"Syntax error", // syntaxError
"Stack overflow" // stackOverflow
};
// Return a null-terminated string describing the exception's kind.
@ -1763,7 +2007,8 @@ const char *JS::Exception::kindString() const
// Return the full error message.
JS::String JS::Exception::fullMessage() const
{
String m(sourceFile);
String m(widenCString("In "));
m += sourceFile;
if (lineNum) {
char b[32];
sprintf(b, ", line %d:\n", lineNum);
@ -1779,6 +2024,7 @@ JS::String JS::Exception::fullMessage() const
m += kindString();
m += ": ";
m += message;
m += '\n';
return m;
}

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

@ -22,8 +22,6 @@
// JS2 shell.
//
#include <algorithm>
#include "world.h"
#include "interpreter.h"
@ -31,80 +29,7 @@ namespace JS = JavaScript;
using namespace JavaScript;
#ifdef XP_MAC
#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 *str, int length)
{
char *limit = str + length;
while (str != limit) {
if (*str == '\n')
*str = '\r';
str++;
}
}
int fputc(int c, FILE *file)
{
char buffer = c;
if (buffer == '\n')
buffer = '\r';
return fwrite(&buffer, 1, 1, file);
}
int fputs(const char *s, FILE *file)
{
char buffer[4096];
int n = strlen(s);
int extra = 0;
while (n > sizeof buffer) {
memcpy(buffer, s, sizeof buffer);
translateLFtoCR(buffer, sizeof buffer);
extra += fwrite(buffer, 1, sizeof buffer, file);
n -= sizeof buffer;
s += sizeof buffer;
}
memcpy(buffer, s, n);
translateLFtoCR(buffer, n);
return extra + fwrite(buffer, 1, n, file);
}
int fprintf(FILE* file, const char *format, ...)
{
va_list args;
char smallBuffer[4096];
int n;
int bufferSize = sizeof smallBuffer;
char *buffer = smallBuffer;
int result;
va_start(args, format);
n = vsnprintf(buffer, bufferSize, format, args);
va_end(args);
while (n < 0) {
if (buffer != smallBuffer)
free(buffer);
bufferSize <<= 1;
buffer = malloc(bufferSize);
if (!buffer) {
ASSERT(false);
return 0;
}
va_start(args, format);
n = vsnprintf(buffer, bufferSize, format, args);
va_end(args);
}
translateLFtoCR(buffer, n);
result = fwrite(buffer, 1, n, file);
if (buffer != smallBuffer)
free(buffer);
return result;
}
#else /* XP_MAC_MPW */
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
#include <SIOUX.h>
#include <MacTypes.h>
@ -118,65 +43,69 @@ static void initConsole(StringPtr consoleName, const char* startupMessage, int &
// Set up a buffer for stderr (otherwise it's a pig).
setvbuf(stderr, new char[BUFSIZ], _IOLBF, BUFSIZ);
std::cout << startupMessage;
stdOut << startupMessage;
argc = 1;
argv = mac_argv;
}
#endif /* XP_MAC_MPW */
#endif /* XP_MAC */
#endif
// Interactively read a line from the input stream in and put it into s.
static bool promptLine(istream &in, string &s, const char *prompt)
// Return false if reached the end of input before reading anything.
static bool promptLine(LineReader &inReader, string &s, const char *prompt)
{
std::cout << prompt;
#ifdef XP_MAC_MPW
/* Print a CR after the prompt because MPW grabs the entire line when entering an interactive command */
std::cout << std::endl;
#endif
#ifndef _WIN32
return std::getline(in, s) != 0;
#else
char buffer[256];
bool result = fgets(buffer, sizeof(buffer), stdin) != 0;
s = buffer;
return result;
#endif
if (prompt) {
stdOut << prompt;
#ifdef XP_MAC_MPW
// Print a CR after the prompt because MPW grabs the entire line when entering an interactive command.
stdOut << '\n';
#endif
}
return inReader.readLine(s) != 0;
}
static void readEvalPrint(istream &in, World &world)
const bool showTokens = true;
static void readEvalPrint(FILE *in, World &world)
{
String buffer;
string line;
String sourceLocation = widenCString("console");
LineReader inReader(in);
while (promptLine(in, line, buffer.empty() ? "js> " : "")) {
if (!buffer.empty())
buffer += uni::lf;
while (promptLine(inReader, line, buffer.empty() ? "js> " : 0)) {
appendChars(buffer, line.data(), line.size());
if (!buffer.empty()) {
try {
Lexer l(world, buffer, sourceLocation);
try {
Arena a;
Parser p(world, a, buffer, sourceLocation);
if (showTokens) {
Lexer &l = p.lexer;
while (true) {
const Token &t = l.get(true);
if (t.hasKind(Token::end))
break;
String out;
out += ' ';
t.print(out, true);
showString(std::cout, out);
stdOut << ' ';
t.print(stdOut, true);
}
} catch (Exception &e) {
std::cout << std::endl;
showString(std::cout, e.fullMessage());
} else {
ExprNode *parseTree = p.parsePostfixExpression();
}
std::cout << std::endl;
clear(buffer);
stdOut << '\n';
} catch (Exception &e) {
// If we got a syntax error on the end of input, then wait for a continuation
// of input rather than printing the error message.
if (!(e.hasKind(Exception::syntaxError) && e.lineNum && e.pos == buffer.size() &&
e.sourceFile == sourceLocation)) {
stdOut << '\n' << e.fullMessage();
clear(buffer);
}
}
}
std::cout << std::endl;
stdOut << '\n';
#if 0
do {
bufp = buffer;
@ -276,7 +205,7 @@ static int ProcessInputFile(JSContext *cx, JSObject *obj, char *filename)
static int
usage(void)
{
std::cerr << "usage: js [-s] [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n";
stdErr << "usage: js [-s] [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n";
return 2;
}
@ -474,7 +403,7 @@ int main(int argc, char **argv)
testInterpreter(5);
testICG(world);
#endif
readEvalPrint(std::cin, world);
readEvalPrint(stdin, world);
return 0;
//return ProcessArgs(argv + 1, argc - 1);