210 lines
6.7 KiB
C++
210 lines
6.7 KiB
C++
/* -*- 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.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
|
|
#include "reader.h"
|
|
|
|
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.
|
|
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 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 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);
|
|
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
|
|
// range, return 0 and two nulls. The line starts should have been recorded by
|
|
// calling beginLine(). If the nth line is the last one recorded, then getLine
|
|
// 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 JS::Reader::getLine(uint32 lineNum, const char16 *&lineBegin, const char16 *&lineEnd) const
|
|
{
|
|
lineBegin = 0;
|
|
lineEnd = 0;
|
|
if (lineNum < initialLineNum)
|
|
return 0;
|
|
lineNum -= initialLineNum;
|
|
if (lineNum >= linePositions.size())
|
|
return 0;
|
|
lineBegin = linePositions[lineNum];
|
|
|
|
const char16 *e;
|
|
++lineNum;
|
|
if (lineNum < linePositions.size())
|
|
e = linePositions[lineNum] - 1;
|
|
else {
|
|
e = lineBegin;
|
|
const char16 *end = Reader::end;
|
|
while (e != end && !isLineBreak(*e))
|
|
++e;
|
|
}
|
|
lineEnd = e;
|
|
return static_cast<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
|
|
// recorded String does not get allocated until endRecord() is called or a
|
|
// discrepancy appears between get() and recordChar().
|
|
void JS::Reader::beginRecording(String &recordString)
|
|
{
|
|
Reader::recordString = &recordString;
|
|
recordBase = p;
|
|
recordPos = p;
|
|
}
|
|
|
|
|
|
// Append ch to the recordString.
|
|
void JS::Reader::recordChar(char16 ch)
|
|
{
|
|
ASSERT(recordString);
|
|
if (recordPos) {
|
|
if (recordPos != end && *recordPos == ch) {
|
|
recordPos++;
|
|
return;
|
|
} else {
|
|
recordString->assign(recordBase, recordPos);
|
|
recordPos = 0;
|
|
}
|
|
}
|
|
*recordString += ch;
|
|
}
|
|
|
|
|
|
// Finish recording characters into the recordString that was last passed to
|
|
// beginRecording(). Return that recordString.
|
|
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 JS::Reader::error(Exception::Kind kind, const String &message, uint32 pos)
|
|
{
|
|
uint32 lineNum = posToLineNum(pos);
|
|
const char16 *lineBegin;
|
|
const char16 *lineEnd;
|
|
uint32 linePos = getLine(lineNum, lineBegin, lineEnd);
|
|
ASSERT(lineBegin && lineEnd && linePos <= pos);
|
|
|
|
throw Exception(kind, message, sourceLocation, lineNum, pos - linePos, pos, lineBegin, lineEnd);
|
|
}
|
|
|
|
|
|
// Read a line from the input file, including the trailing line break character.
|
|
// Return the total number of characters read, which is str's length.
|
|
// Translate <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();
|
|
}
|
|
|
|
|
|
// 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;
|
|
}
|