1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #pragma once
18 
19 #include <cassert>
20 #include <iosfwd>
21 #include <stdexcept>
22 
23 namespace apache {
24 namespace thrift {
25 namespace compiler {
26 
27 class t_program;
28 
29 /**
30  * class source_loc
31  *
32  * Source location information of a parsed element.
33  */
34 class source_loc final {
35  public:
36   constexpr source_loc() noexcept = default;
37   constexpr source_loc(source_loc const&) noexcept = default;
38 
39   /**
40    * Constructor for source_loc
41    *
42    * @param program - The program this location belongs to.
43    * @param line - The 1-based line number.
44    * @param column - The 1-based column number.
45    */
source_loc(const t_program & program,size_t line,size_t column)46   constexpr source_loc(
47       const t_program& program, size_t line, size_t column) noexcept
48       : program_(&program), line_(line), col_(column) {}
49 
50   // If the location is specified/known.
has_loc()51   constexpr bool has_loc() const noexcept { return program_ != nullptr; }
52 
53   // The program associated with the location.
54   //
55   // UB if `has_loc()` returns false.
program()56   constexpr const t_program& program() const {
57     assert(program_ != nullptr);
58     return *program_;
59   }
60 
61   // The 1-based line number.
62   //
63   // Returns 0 if unknown/not specified.
line()64   size_t line() const noexcept { return line_; }
65   // The 1-based column number.
66   //
67   // Returns 0 if unknown/not specified.
column()68   size_t column() const noexcept { return col_; }
69 
70   // The 0-based byte offset from the beginning of the program.
71   //
72   // Returns t_program::noffset if unknown/not specified.
73   size_t offset() const noexcept;
74 
75   constexpr explicit operator bool() const noexcept { return has_loc(); }
76   constexpr source_loc& operator=(const source_loc& loc) noexcept = default;
77 
78   // Ordered by program (nullptr first, then ordered by program.path(), then
79   // &program), then line, then column.
compare(const source_loc & rhs)80   int compare(const source_loc& rhs) const noexcept {
81     return compare(*this, rhs);
82   }
83 
84  private:
85   const t_program* program_ = nullptr;
86   size_t line_ = 0; // 1-based
87   size_t col_ = 0; // Code units (bytes), 1-based
88 
89   friend bool operator==(const source_loc& lhs, const source_loc& rhs) {
90     return lhs.program_ == rhs.program_ && lhs.line_ == rhs.line_ &&
91         lhs.col_ == rhs.col_;
92   }
93   friend bool operator!=(const source_loc& lhs, const source_loc& rhs) {
94     return !(lhs == rhs);
95   }
96 
97   static int compare(const source_loc& lhs, const source_loc& rhs) noexcept;
98 
99   friend bool operator<(const source_loc& lhs, const source_loc& rhs) noexcept {
100     return compare(lhs, rhs) < 0;
101   }
102   friend bool operator<=(
103       const source_loc& lhs, const source_loc& rhs) noexcept {
104     return compare(lhs, rhs) <= 0;
105   }
106   friend bool operator>(const source_loc& lhs, const source_loc& rhs) noexcept {
107     return compare(lhs, rhs) > 0;
108   }
109   friend bool operator>=(
110       const source_loc& lhs, const source_loc& rhs) noexcept {
111     return compare(lhs, rhs) >= 0;
112   }
113 
114   friend std::ostream& operator<<(std::ostream& os, const source_loc& rhs);
115 };
116 
117 /**
118  * class source_range
119  *
120  * Source range information of a parsed element.
121  */
122 class source_range final {
123  public:
124   constexpr source_range() noexcept = default;
125   constexpr source_range(source_range const&) noexcept = default;
126 
source_range(const t_program & program,size_t begin_line,size_t begin_column,size_t end_line,size_t end_column)127   constexpr source_range(
128       const t_program& program,
129       size_t begin_line,
130       size_t begin_column,
131       size_t end_line,
132       size_t end_column) noexcept
133       : program_(&program),
134         begin_line_(begin_line),
135         begin_col_(begin_column),
136         end_line_(end_line),
137         end_col_(end_column) {}
138 
139   // Throws std::invalid_argument if begin and end refer to different programs.
140   source_range(const source_loc& begin, const source_loc& end);
141 
begin()142   constexpr source_loc begin() const noexcept {
143     return {*program_, begin_line_, begin_col_};
144   }
end()145   constexpr source_loc end() const noexcept {
146     return {*program_, end_line_, end_col_};
147   }
program()148   constexpr const t_program& program() const {
149     assert(program_ != nullptr);
150     return *program_;
151   }
152 
153   // If the range is specified/known.
has_range()154   constexpr bool has_range() const noexcept { return program_ != nullptr; }
155 
156   constexpr explicit operator bool() const noexcept { return has_range(); }
157   constexpr source_range& operator=(const source_range& range) noexcept =
158       default;
159 
160   // Ordered by `begin` than `end`.
compare(const source_range & rhs)161   int compare(const source_range& rhs) const noexcept {
162     return compare(*this, rhs);
163   }
164 
165  private:
166   const t_program* program_ = nullptr;
167   size_t begin_line_ = 0; // 1-based
168   size_t begin_col_ = 0; // Code units (bytes), 1-based
169   size_t end_line_ = 0; // 1-based
170   size_t end_col_ = 0; // Code units (bytes), 1-based
171 
172   friend bool operator==(const source_range& lhs, const source_range& rhs) {
173     return lhs.program_ == rhs.program_ && lhs.begin_line_ == rhs.begin_line_ &&
174         lhs.begin_col_ == rhs.begin_col_ && lhs.end_line_ == rhs.end_line_ &&
175         lhs.end_col_ == rhs.end_col_;
176   }
177   friend bool operator!=(
178       const source_range& lhs, const source_range& rhs) noexcept {
179     return !(lhs == rhs);
180   }
181 
182   static int compare(const source_range& lhs, const source_range& rhs) noexcept;
183 
184   friend bool operator<(
185       const source_range& lhs, const source_range& rhs) noexcept {
186     return compare(lhs, rhs) < 0;
187   }
188   friend bool operator<=(
189       const source_range& lhs, const source_range& rhs) noexcept {
190     return compare(lhs, rhs) <= 0;
191   }
192   friend bool operator>(
193       const source_range& lhs, const source_range& rhs) noexcept {
194     return compare(lhs, rhs) > 0;
195   }
196   friend bool operator>=(
197       const source_range& lhs, const source_range& rhs) noexcept {
198     return compare(lhs, rhs) >= 0;
199   }
200 };
201 
202 } // namespace compiler
203 } // namespace thrift
204 } // namespace apache
205