diff options
Diffstat (limited to 'third_party/wasm2c/src/lexer-source-line-finder.cc')
-rw-r--r-- | third_party/wasm2c/src/lexer-source-line-finder.cc | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/third_party/wasm2c/src/lexer-source-line-finder.cc b/third_party/wasm2c/src/lexer-source-line-finder.cc new file mode 100644 index 0000000000..4d407e9d8e --- /dev/null +++ b/third_party/wasm2c/src/lexer-source-line-finder.cc @@ -0,0 +1,152 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wabt/lexer-source-line-finder.h" + +#include <algorithm> + +#include "wabt/lexer-source.h" + +namespace wabt { + +LexerSourceLineFinder::LexerSourceLineFinder( + std::unique_ptr<LexerSource> source) + : source_(std::move(source)), + next_line_start_(0), + last_cr_(false), + eof_(false) { + source_->Seek(0); + // Line 0 should not be used; but it makes indexing simpler. + line_ranges_.emplace_back(0, 0); +} + +Result LexerSourceLineFinder::GetSourceLine(const Location& loc, + Offset max_line_length, + SourceLine* out_source_line) { + ColumnRange column_range(loc.first_column, loc.last_column); + OffsetRange original; + CHECK_RESULT(GetLineOffsets(loc.line, &original)); + + OffsetRange clamped = + ClampSourceLineOffsets(original, column_range, max_line_length); + bool has_start_ellipsis = original.start != clamped.start; + bool has_end_ellipsis = original.end != clamped.end; + + out_source_line->column_offset = clamped.start - original.start; + + if (has_start_ellipsis) { + out_source_line->line += "..."; + clamped.start += 3; + } + if (has_end_ellipsis) { + clamped.end -= 3; + } + + std::vector<char> read_line; + CHECK_RESULT(source_->ReadRange(clamped, &read_line)); + out_source_line->line.append(read_line.begin(), read_line.end()); + + if (has_end_ellipsis) { + out_source_line->line += "..."; + } + + return Result::Ok; +} + +bool LexerSourceLineFinder::IsLineCached(int line) const { + return static_cast<size_t>(line) < line_ranges_.size(); +} + +OffsetRange LexerSourceLineFinder::GetCachedLine(int line) const { + assert(IsLineCached(line)); + return line_ranges_[line]; +} + +Result LexerSourceLineFinder::GetLineOffsets(int find_line, + OffsetRange* out_range) { + if (IsLineCached(find_line)) { + *out_range = GetCachedLine(find_line); + return Result::Ok; + } + + const size_t kBufferSize = 1 << 16; + std::vector<char> buffer(kBufferSize); + + assert(!line_ranges_.empty()); + Offset buffer_file_offset = 0; + while (!IsLineCached(find_line) && !eof_) { + CHECK_RESULT(source_->Tell(&buffer_file_offset)); + size_t read_size = source_->Fill(buffer.data(), buffer.size()); + if (read_size < buffer.size()) { + eof_ = true; + } + + for (auto iter = buffer.begin(), end = iter + read_size; iter < end; + ++iter) { + if (*iter == '\n') { + // Don't include \n or \r in the line range. + Offset line_offset = + buffer_file_offset + (iter - buffer.begin()) - last_cr_; + line_ranges_.emplace_back(next_line_start_, line_offset); + next_line_start_ = line_offset + last_cr_ + 1; + } + last_cr_ = *iter == '\r'; + } + + if (eof_) { + // Add the final line as an empty range. + Offset end = buffer_file_offset + read_size; + line_ranges_.emplace_back(next_line_start_, end); + } + } + + if (IsLineCached(find_line)) { + *out_range = GetCachedLine(find_line); + return Result::Ok; + } else { + assert(eof_); + return Result::Error; + } +} + +// static +OffsetRange LexerSourceLineFinder::ClampSourceLineOffsets( + OffsetRange offset_range, + ColumnRange column_range, + Offset max_line_length) { + Offset line_length = offset_range.size(); + if (line_length > max_line_length) { + size_t column_count = column_range.size(); + size_t center_on; + if (column_count > max_line_length) { + // The column range doesn't fit, just center on first_column. + center_on = column_range.start - 1; + } else { + // the entire range fits, display it all in the center. + center_on = (column_range.start + column_range.end) / 2 - 1; + } + if (center_on > max_line_length / 2) { + offset_range.start += center_on - max_line_length / 2; + } + offset_range.start = + std::min(offset_range.start, offset_range.end - max_line_length); + offset_range.end = offset_range.start + max_line_length; + } + + return offset_range; +} + +} // namespace wabt |