blob: b74d20eee30e72e7a757d6e5f595e1527053c650 [file] [log] [blame]
Dan Sinclair6e581892020-03-02 15:47:43 -05001
2// Copyright 2020 The Tint Authors.
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#ifndef SRC_SOURCE_H_
17#define SRC_SOURCE_H_
18
Antonio Maiorano6ce58be2021-03-09 21:51:50 +000019#include <iostream>
Ben Clayton5bee67f2020-10-30 20:44:53 +000020#include <string>
Antonio Maiorano4b16a162021-04-27 17:32:37 +000021#include <tuple>
Ben Clayton5bee67f2020-10-30 20:44:53 +000022#include <vector>
23
Dan Sinclair6e581892020-03-02 15:47:43 -050024namespace tint {
25
Ben Clayton5bee67f2020-10-30 20:44:53 +000026/// Source describes a range of characters within a source file.
27class Source {
28 public:
Ben Clayton1d982362021-02-18 21:40:19 +000029 /// FileContent describes the content of a source file.
30 class FileContent {
31 public:
32 /// Constructs the FileContent with the given file content.
33 /// @param data the file contents
34 explicit FileContent(const std::string& data);
35
36 /// Destructor
37 ~FileContent();
38
39 /// un-split file content
40 const std::string data;
41 /// #data split by lines
42 const std::vector<std::string> lines;
43 };
44
Ben Clayton5bee67f2020-10-30 20:44:53 +000045 /// File describes a source file, including path and content.
46 class File {
47 public:
48 /// Constructs the File with the given file path and content.
Ben Clayton1d982362021-02-18 21:40:19 +000049 /// @param p the path for this file
50 /// @param c the file contents
51 inline File(const std::string& p, const std::string& c)
52 : path(p), content(c) {}
53
Ben Clayton5bee67f2020-10-30 20:44:53 +000054 ~File();
55
dan sinclair3d0e2732020-11-02 16:03:38 +000056 /// file path (optional)
57 const std::string path;
58 /// file content
Ben Clayton1d982362021-02-18 21:40:19 +000059 const FileContent content;
Ben Clayton5bee67f2020-10-30 20:44:53 +000060 };
61
62 /// Location holds a 1-based line and column index.
Ben Clayton5bee67f2020-10-30 20:44:53 +000063 class Location {
64 public:
Ben Clayton2d89d982020-11-02 18:02:18 +000065 /// the 1-based line number. 0 represents no line information.
Ben Clayton5bee67f2020-10-30 20:44:53 +000066 size_t line = 0;
Ben Clayton2d89d982020-11-02 18:02:18 +000067 /// the 1-based column number. 0 represents no column information.
Ben Clayton5bee67f2020-10-30 20:44:53 +000068 size_t column = 0;
Antonio Maiorano4b16a162021-04-27 17:32:37 +000069
70 /// Returns true of `this` location is lexicographically less than `rhs`
71 /// @param rhs location to compare against
72 /// @returns true if `this` < `rhs`
73 inline bool operator<(const Source::Location& rhs) {
74 return std::tie(line, column) < std::tie(rhs.line, rhs.column);
75 }
76
77 /// Returns true of `this` location is equal to `rhs`
78 /// @param rhs location to compare against
79 /// @returns true if `this` == `rhs`
80 inline bool operator==(const Location& rhs) const {
81 return line == rhs.line && column == rhs.column;
82 }
83
84 /// Returns true of `this` location is not equal to `rhs`
85 /// @param rhs location to compare against
86 /// @returns true if `this` != `rhs`
87 inline bool operator!=(const Location& rhs) const {
88 return !(*this == rhs);
89 }
Ben Clayton5bee67f2020-10-30 20:44:53 +000090 };
91
92 /// Range holds a Location interval described by [begin, end).
93 class Range {
94 public:
95 /// Constructs a zero initialized Range.
96 inline Range() = default;
97
Ben Claytonf8971ae2020-12-02 15:31:08 +000098 /// Constructs a zero-length Range starting at `loc`
99 /// @param loc the start and end location for the range
Antonio Maiorano4b16a162021-04-27 17:32:37 +0000100 inline constexpr explicit Range(const Location& loc)
101 : begin(loc), end(loc) {}
Ben Clayton5bee67f2020-10-30 20:44:53 +0000102
Ben Claytonf8971ae2020-12-02 15:31:08 +0000103 /// Constructs the Range beginning at `b` and ending at `e`
104 /// @param b the range start location
105 /// @param e the range end location
Antonio Maiorano4b16a162021-04-27 17:32:37 +0000106 inline constexpr Range(const Location& b, const Location& e)
107 : begin(b), end(e) {}
Ben Clayton5bee67f2020-10-30 20:44:53 +0000108
Ben Clayton6d612ad2021-02-24 14:15:02 +0000109 /// Return a column-shifted Range
110 /// @param n the number of characters to shift by
111 /// @returns a Range with a #begin and #end column shifted by `n`
112 inline Range operator+(size_t n) const {
113 return Range{{begin.line, begin.column + n}, {end.line, end.column + n}};
114 }
115
Antonio Maiorano4b16a162021-04-27 17:32:37 +0000116 /// Returns true of `this` range is not equal to `rhs`
117 /// @param rhs range to compare against
118 /// @returns true if `this` != `rhs`
119 inline bool operator==(const Range& rhs) const {
120 return begin == rhs.begin && end == rhs.end;
121 }
122
123 /// Returns true of `this` range is equal to `rhs`
124 /// @param rhs range to compare against
125 /// @returns true if `this` == `rhs`
126 inline bool operator!=(const Range& rhs) const { return !(*this == rhs); }
127
dan sinclair3d0e2732020-11-02 16:03:38 +0000128 /// The location of the first character in the range.
129 Location begin;
130 /// The location of one-past the last character in the range.
131 Location end;
Ben Clayton5bee67f2020-10-30 20:44:53 +0000132 };
133
134 /// Constructs the Source with an zero initialized Range and null File.
Ben Clayton1d982362021-02-18 21:40:19 +0000135 inline Source() : range() {}
Ben Clayton5bee67f2020-10-30 20:44:53 +0000136
Ben Claytonf8971ae2020-12-02 15:31:08 +0000137 /// Constructs the Source with the Range `rng` and a null File
Ben Clayton2d89d982020-11-02 18:02:18 +0000138 /// @param rng the source range
Ben Clayton5bee67f2020-10-30 20:44:53 +0000139 inline explicit Source(const Range& rng) : range(rng) {}
140
Ben Claytonf8971ae2020-12-02 15:31:08 +0000141 /// Constructs the Source with the Range `loc` and a null File
Ben Clayton2d89d982020-11-02 18:02:18 +0000142 /// @param loc the start and end location for the source range
Ben Clayton5bee67f2020-10-30 20:44:53 +0000143 inline explicit Source(const Location& loc) : range(Range(loc)) {}
144
Ben Clayton1d982362021-02-18 21:40:19 +0000145 /// Constructs the Source with the Range `rng` and File `file`
Ben Clayton2d89d982020-11-02 18:02:18 +0000146 /// @param rng the source range
Ben Clayton1d982362021-02-18 21:40:19 +0000147 /// @param file the source file
148 inline Source(const Range& rng, File const* file)
149 : range(rng), file_path(file->path), file_content(&file->content) {}
Ben Clayton5bee67f2020-10-30 20:44:53 +0000150
Ben Clayton1d982362021-02-18 21:40:19 +0000151 /// Constructs the Source with the Range `rng`, file path `path` and content
152 /// `content`
153 /// @param rng the source range
154 /// @param path the source file path
155 /// @param content the source file content
156 inline Source(const Range& rng,
157 const std::string& path,
Ben Clayton33a8cdd2021-02-24 13:31:22 +0000158 const FileContent* content = nullptr)
Ben Clayton1d982362021-02-18 21:40:19 +0000159 : range(rng), file_path(path), file_content(content) {}
160
Ben Clayton33a8cdd2021-02-24 13:31:22 +0000161 /// @returns a Source that points to the begin range of this Source.
162 inline Source Begin() const {
163 return Source(Range{range.begin}, file_path, file_content);
164 }
165
166 /// @returns a Source that points to the end range of this Source.
167 inline Source End() const {
168 return Source(Range{range.end}, file_path, file_content);
169 }
170
Ben Clayton6d612ad2021-02-24 14:15:02 +0000171 /// Return a column-shifted Source
172 /// @param n the number of characters to shift by
173 /// @returns a Source with the range's columns shifted by `n`
174 inline Source operator+(size_t n) const {
175 return Source(range + n, file_path, file_content);
176 }
177
Antonio Maiorano4b16a162021-04-27 17:32:37 +0000178 /// Returns true of `this` Source is lexicographically less than `rhs`
179 /// @param rhs source to compare against
180 /// @returns true if `this` < `rhs`
181 inline bool operator<(const Source& rhs) {
182 if (file_path != rhs.file_path) {
183 return false;
184 }
185 if (file_content != rhs.file_content) {
186 return false;
187 }
188 return range.begin < rhs.range.begin;
189 }
190
191 /// Helper function that returns the range union of two source locations. The
192 /// `start` and `end` locations are assumed to refer to the same source file.
193 /// @param start the start source of the range
194 /// @param end the end source of the range
195 /// @returns the combined source
196 inline static Source Combine(const Source& start, const Source& end) {
197 return Source(Source::Range(start.range.begin, end.range.end),
198 start.file_path, start.file_content);
199 }
200
Ben Clayton1d982362021-02-18 21:40:19 +0000201 /// range is the span of text this source refers to in #file_path
Ben Clayton5bee67f2020-10-30 20:44:53 +0000202 Range range;
Ben Clayton1d982362021-02-18 21:40:19 +0000203 /// file is the optional file path this source refers to
204 std::string file_path;
205 /// file is the optional source content this source refers to
206 const FileContent* file_content = nullptr;
Dan Sinclair6e581892020-03-02 15:47:43 -0500207};
208
Antonio Maiorano4b16a162021-04-27 17:32:37 +0000209/// Writes the Source::Location to the std::ostream.
210/// @param out the std::ostream to write to
211/// @param loc the location to write
212/// @returns out so calls can be chained
213inline std::ostream& operator<<(std::ostream& out,
214 const Source::Location& loc) {
215 out << loc.line << ":" << loc.column;
216 return out;
217}
218
219/// Writes the Source::Range to the std::ostream.
220/// @param out the std::ostream to write to
221/// @param range the range to write
222/// @returns out so calls can be chained
223inline std::ostream& operator<<(std::ostream& out, const Source::Range& range) {
224 out << "[" << range.begin << ", " << range.end << "]";
225 return out;
226}
227
Ben Clayton6fcefe42021-04-19 19:16:12 +0000228/// Writes the Source to the std::ostream.
229/// @param out the std::ostream to write to
230/// @param source the source to write
231/// @returns out so calls can be chained
232std::ostream& operator<<(std::ostream& out, const Source& source);
233
Ben Clayton1d982362021-02-18 21:40:19 +0000234/// Writes the Source::FileContent to the std::ostream.
235/// @param out the std::ostream to write to
236/// @param content the file content to write
237/// @returns out so calls can be chained
238inline std::ostream& operator<<(std::ostream& out,
239 const Source::FileContent& content) {
240 out << content.data;
241 return out;
242}
243
Dan Sinclair6e581892020-03-02 15:47:43 -0500244} // namespace tint
245
246#endif // SRC_SOURCE_H_