/src/hermes/lib/SourceMap/SourceMap.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) Meta Platforms, Inc. and affiliates. |
3 | | * |
4 | | * This source code is licensed under the MIT license found in the |
5 | | * LICENSE file in the root directory of this source tree. |
6 | | */ |
7 | | |
8 | | #include "hermes/SourceMap/SourceMap.h" |
9 | | |
10 | | namespace hermes { |
11 | | |
12 | | /// Query source map text location for \p line and \p column. |
13 | | /// In both the input and output of this function, line and column numbers |
14 | | /// are 1-based. |
15 | | llvh::Optional<SourceMapTextLocationFIndex> |
16 | 0 | SourceMap::getLocationForAddressFIndex(uint32_t line, uint32_t column) const { |
17 | 0 | auto seg = this->getSegmentForAddress(line, column); |
18 | | // Unmapped location |
19 | 0 | if (!seg.hasValue() || !seg->representedLocation.hasValue()) { |
20 | 0 | return llvh::None; |
21 | 0 | } |
22 | | // parseSegment() should have validated this. |
23 | 0 | assert( |
24 | 0 | (size_t)seg->representedLocation->sourceIndex < sources_.size() && |
25 | 0 | "SourceIndex is out-of-range."); |
26 | 0 | return SourceMapTextLocationFIndex{ |
27 | 0 | (uint32_t)seg->representedLocation->sourceIndex, |
28 | 0 | (uint32_t)seg->representedLocation->lineIndex + 1, |
29 | 0 | (uint32_t)seg->representedLocation->columnIndex + 1}; |
30 | 0 | } |
31 | | |
32 | | llvh::Optional<SourceMapTextLocation> SourceMap::getLocationForAddress( |
33 | | uint32_t line, |
34 | 0 | uint32_t column) const { |
35 | 0 | auto loc = getLocationForAddressFIndex(line, column); |
36 | 0 | if (!loc) |
37 | 0 | return llvh::None; |
38 | | |
39 | 0 | return SourceMapTextLocation{ |
40 | 0 | getSourceFullPath(loc->fileIndex), loc->line, loc->column}; |
41 | 0 | } |
42 | | |
43 | | llvh::Optional<SourceMap::Segment> SourceMap::getSegmentForAddress( |
44 | | uint32_t line, |
45 | 0 | uint32_t column) const { |
46 | 0 | if (line == 0 || line > lines_.size()) { |
47 | 0 | return llvh::None; |
48 | 0 | } |
49 | | |
50 | | // line is 1-based. |
51 | 0 | uint32_t lineIndex = line - 1; |
52 | 0 | auto &segments = lines_[lineIndex]; |
53 | 0 | if (segments.empty()) { |
54 | 0 | return llvh::None; |
55 | 0 | } |
56 | 0 | assert(column >= 1 && "the column argument to this function is 1-based"); |
57 | 0 | uint32_t columnIndex = column - 1; |
58 | | // Algorithm: we wanted to locate the segment covering |
59 | | // the needle(`column`) -- segment.generatedColumn <= column. |
60 | | // We achieve it by binary searching the first sentinel |
61 | | // segment strictly greater than needle(`column`) and then move backward |
62 | | // one slot. |
63 | 0 | auto segIter = std::upper_bound( |
64 | 0 | segments.begin(), |
65 | 0 | segments.end(), |
66 | 0 | columnIndex, |
67 | 0 | [](uint32_t column, const Segment &seg) { |
68 | 0 | return column < (uint32_t)seg.generatedColumn; |
69 | 0 | }); |
70 | | // The found sentinel segment is the first one. No covering segment. |
71 | 0 | if (segIter == segments.begin()) { |
72 | 0 | return llvh::None; |
73 | 0 | } |
74 | | // Move back one slot. |
75 | 0 | const Segment &target = |
76 | 0 | segIter == segments.end() ? segments.back() : *(--segIter); |
77 | 0 | return target; |
78 | 0 | } |
79 | | |
80 | | } // namespace hermes |