summaryrefslogtreecommitdiffstats
path: root/third_party/wasm2c/src/lexer-source-line-finder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/wasm2c/src/lexer-source-line-finder.cc')
-rw-r--r--third_party/wasm2c/src/lexer-source-line-finder.cc152
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