Mozilla/mozilla/js2/src/reader.cpp
gerv%gerv.net 76529f3fd6 Bug 236613: change to MPL/LGPL/GPL tri-license.
git-svn-id: svn://10.0.0.236/trunk@185990 18797224-902f-48f8-a5cc-f745e15eee43
2005-12-13 13:25:40 +00:00

228 lines
7.3 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla 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/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or 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 the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <algorithm>
#include <vector>
#include "systemtypes.h"
#include "js2value.h"
#include "strings.h"
#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);
}
// Fully process the source in order to fill in the line start table.
void JS::Reader::fillLineStartsTable()
{
char16 ch;
do {
ch = get();
if (isLineBreak(ch))
beginLine();
} while (!getEof(ch));
}
// 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(size_t 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.
size_t 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 toSize_t(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, size_t pos)
{
uint32 lineNum = posToLineNum(pos);
const char16 *lineBegin;
const char16 *lineEnd;
size_t 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;
}