2 * Copyright 2017 WebAssembly Community Group participants
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "wabt/lexer-source-line-finder.h"
21 #include "wabt/lexer-source.h"
25 LexerSourceLineFinder::LexerSourceLineFinder(
26 std::unique_ptr
<LexerSource
> source
)
27 : source_(std::move(source
)),
32 // Line 0 should not be used; but it makes indexing simpler.
33 line_ranges_
.emplace_back(0, 0);
36 Result
LexerSourceLineFinder::GetSourceLine(const Location
& loc
,
37 Offset max_line_length
,
38 SourceLine
* out_source_line
) {
39 ColumnRange
column_range(loc
.first_column
, loc
.last_column
);
41 CHECK_RESULT(GetLineOffsets(loc
.line
, &original
));
44 ClampSourceLineOffsets(original
, column_range
, max_line_length
);
45 bool has_start_ellipsis
= original
.start
!= clamped
.start
;
46 bool has_end_ellipsis
= original
.end
!= clamped
.end
;
48 out_source_line
->column_offset
= clamped
.start
- original
.start
;
50 if (has_start_ellipsis
) {
51 out_source_line
->line
+= "...";
54 if (has_end_ellipsis
) {
58 std::vector
<char> read_line
;
59 CHECK_RESULT(source_
->ReadRange(clamped
, &read_line
));
60 out_source_line
->line
.append(read_line
.begin(), read_line
.end());
62 if (has_end_ellipsis
) {
63 out_source_line
->line
+= "...";
69 bool LexerSourceLineFinder::IsLineCached(int line
) const {
70 return static_cast<size_t>(line
) < line_ranges_
.size();
73 OffsetRange
LexerSourceLineFinder::GetCachedLine(int line
) const {
74 assert(IsLineCached(line
));
75 return line_ranges_
[line
];
78 Result
LexerSourceLineFinder::GetLineOffsets(int find_line
,
79 OffsetRange
* out_range
) {
80 if (IsLineCached(find_line
)) {
81 *out_range
= GetCachedLine(find_line
);
85 const size_t kBufferSize
= 1 << 16;
86 std::vector
<char> buffer(kBufferSize
);
88 assert(!line_ranges_
.empty());
89 Offset buffer_file_offset
= 0;
90 while (!IsLineCached(find_line
) && !eof_
) {
91 CHECK_RESULT(source_
->Tell(&buffer_file_offset
));
92 size_t read_size
= source_
->Fill(buffer
.data(), buffer
.size());
93 if (read_size
< buffer
.size()) {
97 for (auto iter
= buffer
.begin(), end
= iter
+ read_size
; iter
< end
;
100 // Don't include \n or \r in the line range.
102 buffer_file_offset
+ (iter
- buffer
.begin()) - last_cr_
;
103 line_ranges_
.emplace_back(next_line_start_
, line_offset
);
104 next_line_start_
= line_offset
+ last_cr_
+ 1;
106 last_cr_
= *iter
== '\r';
110 // Add the final line as an empty range.
111 Offset end
= buffer_file_offset
+ read_size
;
112 line_ranges_
.emplace_back(next_line_start_
, end
);
116 if (IsLineCached(find_line
)) {
117 *out_range
= GetCachedLine(find_line
);
121 return Result::Error
;
126 OffsetRange
LexerSourceLineFinder::ClampSourceLineOffsets(
127 OffsetRange offset_range
,
128 ColumnRange column_range
,
129 Offset max_line_length
) {
130 Offset line_length
= offset_range
.size();
131 if (line_length
> max_line_length
) {
132 size_t column_count
= column_range
.size();
134 if (column_count
> max_line_length
) {
135 // The column range doesn't fit, just center on first_column.
136 center_on
= column_range
.start
- 1;
138 // the entire range fits, display it all in the center.
139 center_on
= (column_range
.start
+ column_range
.end
) / 2 - 1;
141 if (center_on
> max_line_length
/ 2) {
142 offset_range
.start
+= center_on
- max_line_length
/ 2;
145 std::min(offset_range
.start
, offset_range
.end
- max_line_length
);
146 offset_range
.end
= offset_range
.start
+ max_line_length
;