diff options
author | eldritch horrors <pennae@lix.systems> | 2024-01-29 06:19:23 +0100 |
---|---|---|
committer | eldritch horrors <pennae@lix.systems> | 2024-03-18 16:12:46 +0100 |
commit | 4c072c7c5f5e574ace6a3c3a1e07cb5db25a4487 (patch) | |
tree | 9b40b241d9f139c5684633d95652acaf333b5aa3 /src/libutil/position.cc | |
parent | 9cf92c012d81bdd8df60a51f7cbcdb4812544c46 (diff) |
match line endings used by parser and error reports
the parser treats a plain \r as a newline, error reports do not. this
can lead to interesting divergences if anything makes use of this
feature, with error reports pointing to wrong locations in the input (or
even outside the input altogether).
(cherry picked from commit 2be6b143289e5479cc4a2667bb84e879116c2447)
Change-Id: Ieb7f7655bac8cb0cf5734c60bd41723388f2973c
Diffstat (limited to 'src/libutil/position.cc')
-rw-r--r-- | src/libutil/position.cc | 55 |
1 files changed, 31 insertions, 24 deletions
diff --git a/src/libutil/position.cc b/src/libutil/position.cc index b39a5a1d4..724e560b7 100644 --- a/src/libutil/position.cc +++ b/src/libutil/position.cc @@ -29,32 +29,17 @@ std::optional<LinesOfCode> Pos::getCodeLines() const return std::nullopt; if (auto source = getSource()) { - - std::istringstream iss(*source); - // count the newlines. - int count = 0; - std::string curLine; - int pl = line - 1; - + LinesIterator lines(*source), end; LinesOfCode loc; - do { - std::getline(iss, curLine); - ++count; - if (count < pl) - ; - else if (count == pl) { - loc.prevLineOfCode = curLine; - } else if (count == pl + 1) { - loc.errLineOfCode = curLine; - } else if (count == pl + 2) { - loc.nextLineOfCode = curLine; - break; - } - - if (!iss.good()) - break; - } while (true); + if (line > 1) + std::advance(lines, line - 2); + if (lines != end && line > 1) + loc.prevLineOfCode = *lines++; + if (lines != end) + loc.errLineOfCode = *lines++; + if (lines != end) + loc.nextLineOfCode = *lines++; return loc; } @@ -109,4 +94,26 @@ std::ostream & operator<<(std::ostream & str, const Pos & pos) return str; } +void Pos::LinesIterator::bump(bool atFirst) +{ + if (!atFirst) { + pastEnd = input.empty(); + if (!input.empty() && input[0] == '\r') + input.remove_prefix(1); + if (!input.empty() && input[0] == '\n') + input.remove_prefix(1); + } + + // nix line endings are not only \n as eg std::getline assumes, but also + // \r\n **and \r alone**. not treating them all the same causes error + // reports to not match with line numbers as the parser expects them. + auto eol = input.find_first_of("\r\n"); + + if (eol > input.size()) + eol = input.size(); + + curLine = input.substr(0, eol); + input.remove_prefix(eol); +} + } |