1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "sourceLocation.h"
17
18#include <lexer/token/letters.h>
19
20#include <cstdint>
21
22namespace panda::es2panda::lexer {
23
24void OffsetEntry::AddCol(size_t offset)
25{
26    size_t diff = offset - offset_;
27    offset_ = offset;
28
29    if (ranges.empty()) {
30        ranges.emplace_back(Range {diff});
31        return;
32    }
33
34    auto &range = ranges.back();
35
36    if (diff == range.byteSize) {
37        range.cnt++;
38    } else {
39        ranges.emplace_back(Range {diff});
40    }
41}
42
43LineIndex::LineIndex(const util::StringView &source) noexcept
44{
45    auto iter = util::StringView::Iterator(source);
46    entrys_.emplace_back(0);
47
48    bool nextEntry = false;
49    while (true) {
50        if (!iter.HasNext()) {
51            if (!nextEntry) {
52                // Add the last entry if the ending character is not LEX_CHAR_LF / LEX_CHAR_PS / LEX_CHAR_LS
53                entrys_.emplace_back(iter.Index());
54            }
55            return;
56        }
57
58        switch (iter.Next()) {
59            case LEX_CHAR_CR: {
60                if (iter.HasNext() && iter.Peek() == LEX_CHAR_LF) {
61                    iter.Forward(1);
62                }
63
64                [[fallthrough]];
65            }
66            case LEX_CHAR_LF:
67            case LEX_CHAR_PS:
68            case LEX_CHAR_LS: {
69                entrys_.emplace_back(iter.Index());
70                nextEntry = true;
71                break;
72            }
73            default: {
74                entrys_.back().AddCol(iter.Index());
75                nextEntry = false;
76            }
77        }
78    }
79}
80
81SourceLocation LineIndex::GetLocation(SourcePosition pos) noexcept
82{
83    size_t line = pos.line;
84
85    size_t col = 0;
86    ASSERT(pos.line < entrys_.size());
87    const auto &entry = entrys_[pos.line];
88    size_t diff = pos.index - entry.lineStart;
89
90    for (const auto &range : entry.ranges) {
91        if (diff < (range.cnt * range.byteSize)) {
92            col += (diff / range.byteSize) ;
93            break;
94        }
95
96        diff -= range.cnt * range.byteSize;
97        col += range.cnt;
98    }
99
100    return SourceLocation(line + 1, col + 1);
101}
102
103}  // namespace panda::es2panda::lexer
104