InputStreamPreprocessor.h [plain text]
#ifndef InputStreamPreprocessor_h
#define InputStreamPreprocessor_h
#include "SegmentedString.h"
#include <wtf/Noncopyable.h>
#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
const LChar kEndOfFileMarker = 0;
template <typename Tokenizer>
class InputStreamPreprocessor {
WTF_MAKE_NONCOPYABLE(InputStreamPreprocessor);
public:
explicit InputStreamPreprocessor(Tokenizer& tokenizer)
: m_tokenizer(tokenizer)
{
reset();
}
ALWAYS_INLINE UChar nextInputCharacter() const { return m_nextInputCharacter; }
ALWAYS_INLINE bool peek(SegmentedString& source, bool skipNullCharacters = false)
{
if (source.isEmpty())
return false;
m_nextInputCharacter = source.currentChar();
static const UChar specialCharacterMask = '\n' | '\r' | '\0';
if (m_nextInputCharacter & ~specialCharacterMask) {
m_skipNextNewLine = false;
return true;
}
return processNextInputCharacter(source, skipNullCharacters);
}
ALWAYS_INLINE bool advance(SegmentedString& source, bool skipNullCharacters = false)
{
source.advanceAndUpdateLineNumber();
return peek(source, skipNullCharacters);
}
bool skipNextNewLine() const { return m_skipNextNewLine; }
void reset(bool skipNextNewLine = false)
{
m_nextInputCharacter = '\0';
m_skipNextNewLine = skipNextNewLine;
}
private:
bool processNextInputCharacter(SegmentedString& source, bool skipNullCharacters)
{
ProcessAgain:
ASSERT(m_nextInputCharacter == source.currentChar());
if (m_nextInputCharacter == '\n' && m_skipNextNewLine) {
m_skipNextNewLine = false;
source.advancePastNewlineAndUpdateLineNumber();
if (source.isEmpty())
return false;
m_nextInputCharacter = source.currentChar();
}
if (m_nextInputCharacter == '\r') {
m_nextInputCharacter = '\n';
m_skipNextNewLine = true;
} else {
m_skipNextNewLine = false;
if (m_nextInputCharacter == '\0' && !shouldTreatNullAsEndOfFileMarker(source)) {
if (skipNullCharacters && !m_tokenizer.neverSkipNullCharacters()) {
source.advancePastNonNewline();
if (source.isEmpty())
return false;
m_nextInputCharacter = source.currentChar();
goto ProcessAgain;
}
m_nextInputCharacter = replacementCharacter;
}
}
return true;
}
bool shouldTreatNullAsEndOfFileMarker(SegmentedString& source) const
{
return source.isClosed() && source.length() == 1;
}
Tokenizer& m_tokenizer;
UChar m_nextInputCharacter;
bool m_skipNextNewLine;
};
}
#endif // InputStreamPreprocessor_h