2
Copyright 2006 Hamish Rodda <rodda@kde.org>
3
Copyright 2008-2009 David Nolden <david.nolden.kdevelop@art-master.de>
5
Permission to use, copy, modify, distribute, and sell this software and its
6
documentation for any purpose is hereby granted without fee, provided that
7
the above copyright notice appear in all copies and that both that
8
copyright notice and this permission notice appear in supporting
11
The above copyright notice and this permission notice shall be included in
12
all copies or substantial portions of the Software.
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
#include "pp-stream.h"
24
///@todo Better splitting of input and output functionality
28
#include "pp-location.h"
29
#include "chartools.h"
30
#include <language/duchain/indexedstring.h>
34
const unsigned int Stream::newline(indexFromCharacter('\n'));
35
static unsigned int nullItem(0);
36
const unsigned int deepLine(indexFromCharacter('_'));
38
// bool shouldMergeTo(uint previous) {
39
// return !isCharacter(previous) || previous == deepLine || isLetter(previous);
42
// bool shouldMerge(uint follower) {
43
// return !isCharacter(follower) || follower == deepLine || isLetterOrNumber(follower);
47
: m_string(new PreprocessedContents())
49
, m_skippedToEnd(false)
50
, m_inputPositionLocked(false)
52
, m_macroExpansion(KDevelop::SimpleCursor::invalid())
55
, m_inputLineStartedAt(0)
57
, m_originalInputPosition(KDevelop::SimpleCursor::invalid())
62
Stream::Stream( PreprocessedContents * string, const Anchor& offset, LocationTable* table )
65
, m_skippedToEnd(false)
66
, m_inputPositionLocked(false)
68
, m_macroExpansion(KDevelop::SimpleCursor::invalid())
70
, m_inputLine(offset.line)
71
, m_inputLineStartedAt(-offset.column)
72
, m_locationTable(table)
73
, m_originalInputPosition(KDevelop::SimpleCursor::invalid())
76
m_inputPositionLocked = true;
77
c = m_string->constData();
78
end = m_string->constData() + m_string->size();
81
Stream::Stream( const uint * string, uint stringSize, const Anchor& offset, LocationTable* table )
82
: m_string(new PreprocessedContents(stringSize))
84
, m_skippedToEnd(false)
85
, m_inputPositionLocked(false)
87
, m_macroExpansion(KDevelop::SimpleCursor::invalid())
89
, m_inputLine(offset.line)
90
, m_inputLineStartedAt(-offset.column)
91
, m_locationTable(table)
92
, m_originalInputPosition(KDevelop::SimpleCursor::invalid())
94
memcpy(m_string->data(), string, stringSize * sizeof(uint));
96
m_inputPositionLocked = true;
97
c = m_string->constData();
98
end = m_string->constData() + m_string->size();
101
Stream::Stream( PreprocessedContents * string, LocationTable* table )
104
, m_skippedToEnd(false)
105
, m_inputPositionLocked(false)
106
, m_onwsString(false)
107
, m_macroExpansion(KDevelop::SimpleCursor::invalid())
110
, m_inputLineStartedAt(0)
111
, m_locationTable(table)
112
, m_originalInputPosition(KDevelop::SimpleCursor::invalid())
114
c = m_string->constData();
115
end = m_string->constData() + m_string->size();
124
Stream& Stream::operator--()
126
if (c == m_string->constData())
132
if(m_inputPositionLocked)
133
--m_inputLineStartedAt;
135
m_inputLineStartedAt -= (1-KDevelop::IndexedString::lengthFromIndex(*c));
141
bool Stream::atEnd() const
148
m_skippedToEnd = true;
152
bool Stream::skippedToEnd() const
154
return m_skippedToEnd;
157
const uint& Stream::peek(uint offset) const
159
if (c + offset >= end)
162
return *(c + offset);
165
int Stream::offset( ) const
170
void Stream::seek(int offset)
172
if(m_inputPositionLocked){
173
m_inputLineStartedAt = offset + (m_inputLineStartedAt - m_pos);
176
for(int a = offset; a < m_pos; ++a)
177
m_inputLineStartedAt -= (1-KDevelop::IndexedString::lengthFromIndex(m_string->at(a)));
179
for(int a = m_pos; a < offset; ++a)
180
m_inputLineStartedAt += (1-KDevelop::IndexedString::lengthFromIndex(m_string->at(a)));
184
c = m_string->constData() + offset;
188
m_pos = m_string->size();
192
Stream & Stream::operator<< ( const unsigned int& c )
194
// Keep in sync with below
198
unsigned int& previous( (*m_string)[m_pos-1] );
199
if(shouldMergeTo(previous)) {
201
//We have to merge with the previous character, so we get a correct tokenization. This should not happen too often.
202
previous = KDevelop::IndexedString(KDevelop::IndexedString(previous).byteArray() + KDevelop::IndexedString(c).byteArray()).index();
203
kDebug() << "merging" << KDevelop::IndexedString(previous).str() << "and" << KDevelop::IndexedString(c).str();
213
m_inputLineStartedAt = m_pos; ///@todo remove
221
unsigned int rpp::Stream::popLastOutput() {
222
unsigned int ret = m_string->last();
223
m_string->pop_back();
228
unsigned int rpp::Stream::peekLastOutput(uint backOffset) const {
229
if(m_pos - backOffset > 0)
230
return m_string->at(m_pos - backOffset - 1);
234
Stream& Stream::operator<< ( const Stream& input )
236
const uint c = input;
238
// Keep in sync with above
242
unsigned int& previous( (*m_string)[m_pos-1] );
243
if(shouldMergeTo(previous)) {
245
//We have to merge with the previous character, so we get a correct tokenization. This should not happen too often.
246
previous = KDevelop::IndexedString(KDevelop::IndexedString(previous).byteArray() + KDevelop::IndexedString(c).byteArray()).index();
247
kDebug() << "merging" << KDevelop::IndexedString(previous).str() << "and" << KDevelop::IndexedString(c).str();
258
Anchor inputPosition = input.inputPosition();
260
m_inputLineStartedAt = m_pos; ///@todo remove
261
if(!inputPosition.collapsed)
262
mark(Anchor(inputPosition.line + 1, 0, false, m_macroExpansion));
268
Stream& Stream::appendString( const Anchor& inputPosition, const PreprocessedContents & string )
274
/* if(m_pos > 0 && string.size()) {
275
//Eventually merge the tokens. This shouldn't happen too often
276
int size = string.size();
277
unsigned int& previous( (*m_string)[m_pos-1] );
278
for(int a = 0; a < size; ++a) {
279
if(shouldMergeTo(previous)) {
280
if(shouldMerge(string[a])) {
281
//We have to merge with the previous character, so we get a correct tokenization. This should not happen too often.
282
previous = KDevelop::IndexedString(KDevelop::IndexedString(previous).byteArray() + KDevelop::IndexedString(string[a]).byteArray()).index();
284
kDebug() << "merging" << KDevelop::IndexedString(previous).str() << "and" << KDevelop::IndexedString(string[a]).str();
292
// if(!offset) ///@todo think about his. We lose the input position, but on the other hand the merging should only happen when ## was used
298
for (int i = 0; i < string.size(); ++i) {
300
if (string.at(i) == newline) {
301
m_pos += i + 1; //Move the current offset to that position, so the marker is set correctly
302
if(!inputPosition.collapsed)
303
mark(Anchor(inputPosition.line + ++extraLines, 0, false, m_macroExpansion));
308
m_pos += string.size();
310
// TODO check correctness Probably remove
311
m_inputLineStartedAt = m_pos - (string.size() - string.lastIndexOf(newline)); ///@todo remove
316
Stream& Stream::appendString( const Anchor& inputPosition, KDevelop::IndexedString string )
323
unsigned int& previous( (*m_string)[m_pos-1] );
324
if(shouldMergeTo(previous)) {
325
if(shouldMerge(string.index())) {
326
//We have to merge with the previous character, so we get a correct tokenization. This should not happen too often.
327
previous = KDevelop::IndexedString(KDevelop::IndexedString(previous).byteArray() + string.byteArray()).index();
328
kDebug() << "merging" << KDevelop::IndexedString(previous).str() << "and" << string.str();
329
return *this; ///We lose the input-position, but on the other hand we would lose it anyway on another level
335
m_string->append(string.index());
338
if (string.index() == newline) {
339
m_pos += 1; //Move the current offset to that position, so the marker is set correctly
340
if(!inputPosition.collapsed)
341
mark(Anchor(inputPosition.line + ++extraLines, 0, false, m_macroExpansion));
347
// TODO check correctness Probably remove
348
m_inputLineStartedAt = m_pos; ///@todo remove
353
bool Stream::isNull() const
358
Anchor Stream::inputPosition() const
360
return Anchor(m_inputLine, m_pos - m_inputLineStartedAt, m_inputPositionLocked, m_macroExpansion);
363
void Stream::setInputPosition(const Anchor& position)
365
m_inputLine = position.line;
366
m_inputLineStartedAt = m_pos - position.column;
367
m_inputPositionLocked = position.collapsed;
370
void Stream::setMacroExpansion(const KDevelop::SimpleCursor& expansion)
372
m_macroExpansion = expansion;
375
KDevelop::SimpleCursor Stream::macroExpansion() const
377
return m_macroExpansion;
380
rpp::Anchor rpp::Stream::currentOutputAnchor() const {
382
return m_locationTable->positionAt(m_pos, *m_string).first;
383
return rpp::Anchor();
386
void Stream::mark(const Anchor& position)
388
Q_ASSERT(m_pos <= m_string->size());
389
if (m_locationTable) {
390
if(m_macroExpansion.isValid()) {
392
a.macroExpansion = m_macroExpansion;
393
m_locationTable->anchor(m_pos, a, m_string);
395
m_locationTable->anchor(m_pos, position, m_string);
400
void Stream::reset( )
402
c = m_string->constData();
403
m_inputLineStartedAt = m_inputLine = m_pos = 0;
404
m_inputPositionLocked = false;
407
QByteArray rpp::Stream::stringFrom(int offset) const
410
for(int a = offset; a < m_pos; ++a)
411
ret += KDevelop::IndexedString::fromIndex((*m_string)[a]).byteArray();
416
KDevelop::SimpleCursor rpp::Stream::originalInputPosition() const
418
if (m_originalInputPosition.isValid())
419
return m_originalInputPosition;
421
return inputPosition();
424
void rpp::Stream::setOriginalInputPosition(const KDevelop::SimpleCursor & position)
426
m_originalInputPosition = position;