microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.1.3

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc/src/location.rs

256lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use std::sync::Arc;
5
6use qsc_data_structures::{
7 line_column::{Encoding, Range},
8 span::Span,
9};
10use qsc_frontend::compile::PackageStore;
11use qsc_hir::hir::PackageId;
12
13pub const QSHARP_LIBRARY_URI_SCHEME: &str = "qsharp-library-source";
14
15/// Describes a location in source code in terms of a source name and [`Range`].
16#[derive(Debug, PartialEq, Clone)]
17pub struct Location {
18 pub source: Arc<str>,
19 pub range: Range,
20}
21
22impl Location {
23 /// Creates a [`Location`] from a package ID and a SourceMap-relative span.
24 ///
25 /// To differentiate user sources from library sources, this function takes
26 /// a `user_package_id` parameter which denotes the user package.
27 /// All other packages in the package store are assumed to be library packages.
28 /// Source names from library packages are prepended with a unique URI scheme.
29 #[must_use]
30 pub fn from(
31 span: Span,
32 package_id: PackageId,
33 package_store: &PackageStore,
34 user_package_id: PackageId,
35 position_encoding: Encoding,
36 ) -> Self {
37 let source = package_store
38 .get(package_id)
39 .expect("package id must exist in store")
40 .sources
41 .find_by_offset(span.lo)
42 .expect("source should exist for offset");
43
44 let source_name = if package_id == user_package_id {
45 source.name.clone()
46 } else {
47 // Currently the only supported external packages are our library packages,
48 // URI's to which need to include our custom library scheme.
49 format!("{}:{}", QSHARP_LIBRARY_URI_SCHEME, source.name).into()
50 };
51
52 Location {
53 source: source_name,
54 range: Range::from_span(position_encoding, &source.contents, &(span - source.offset)),
55 }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use crate::compile;
62 use expect_test::expect;
63 use qsc_data_structures::{line_column::Encoding, span::Span};
64 use qsc_frontend::compile::{PackageStore, RuntimeCapabilityFlags, SourceMap};
65 use qsc_hir::hir::PackageId;
66 use qsc_passes::PackageType;
67
68 use super::Location;
69
70 #[test]
71 fn from_std_span() {
72 let (store, std_package_id, user_package_id) = compile_package();
73
74 let location = Location::from(
75 Span { lo: 0, hi: 1 },
76 std_package_id,
77 &store,
78 user_package_id,
79 Encoding::Utf8,
80 );
81
82 expect![[r#"
83 Location {
84 source: "qsharp-library-source:arrays.qs",
85 range: Range {
86 start: Position {
87 line: 0,
88 column: 0,
89 },
90 end: Position {
91 line: 0,
92 column: 1,
93 },
94 },
95 }
96 "#]]
97 .assert_debug_eq(&location);
98 }
99
100 #[test]
101 fn from_core_span() {
102 let (store, _, user_package_id) = compile_package();
103
104 let location = Location::from(
105 Span { lo: 0, hi: 1 },
106 PackageId::CORE,
107 &store,
108 user_package_id,
109 Encoding::Utf8,
110 );
111
112 expect![[r#"
113 Location {
114 source: "qsharp-library-source:core/core.qs",
115 range: Range {
116 start: Position {
117 line: 0,
118 column: 0,
119 },
120 end: Position {
121 line: 0,
122 column: 1,
123 },
124 },
125 }
126 "#]]
127 .assert_debug_eq(&location);
128 }
129
130 #[test]
131 fn from_user_span() {
132 let (store, _, user_package_id) = compile_package();
133
134 let bar_start_offset = store
135 .get(user_package_id)
136 .expect("expected to find user package")
137 .sources
138 .find_by_name("bar.qs")
139 .expect("expected to find source")
140 .offset;
141
142 let location = Location::from(
143 Span {
144 lo: bar_start_offset,
145 hi: bar_start_offset + 1,
146 },
147 user_package_id,
148 &store,
149 user_package_id,
150 Encoding::Utf8,
151 );
152
153 expect![[r#"
154 Location {
155 source: "bar.qs",
156 range: Range {
157 start: Position {
158 line: 0,
159 column: 0,
160 },
161 end: Position {
162 line: 0,
163 column: 1,
164 },
165 },
166 }
167 "#]]
168 .assert_debug_eq(&location);
169 }
170
171 #[test]
172 fn from_out_of_bounds_lo() {
173 let (store, _, user_package_id) = compile_package();
174
175 let location = Location::from(
176 Span { lo: 1000, hi: 2000 },
177 user_package_id,
178 &store,
179 user_package_id,
180 Encoding::Utf8,
181 );
182
183 // Per [`Range`] spec, out of bounds positions map to EOF
184 expect![[r#"
185 Location {
186 source: "bar.qs",
187 range: Range {
188 start: Position {
189 line: 0,
190 column: 17,
191 },
192 end: Position {
193 line: 0,
194 column: 17,
195 },
196 },
197 }
198 "#]]
199 .assert_debug_eq(&location);
200 }
201
202 #[test]
203 fn from_out_of_bounds_hi() {
204 let (store, _, user_package_id) = compile_package();
205
206 let location = Location::from(
207 Span { lo: 0, hi: 2000 },
208 user_package_id,
209 &store,
210 user_package_id,
211 Encoding::Utf8,
212 );
213
214 // Per [`Range`] spec, out of bounds positions map to EOF
215 expect![[r#"
216 Location {
217 source: "foo.qs",
218 range: Range {
219 start: Position {
220 line: 0,
221 column: 0,
222 },
223 end: Position {
224 line: 0,
225 column: 17,
226 },
227 },
228 }
229 "#]]
230 .assert_debug_eq(&location);
231 }
232
233 fn compile_package() -> (PackageStore, PackageId, PackageId) {
234 let mut store = PackageStore::new(compile::core());
235 let mut dependencies = Vec::new();
236
237 let (package_type, capabilities) = (PackageType::Lib, RuntimeCapabilityFlags::all());
238
239 let std = compile::std(&store, capabilities);
240 let std_package_id = store.insert(std);
241
242 dependencies.push(std_package_id);
243 let sources = SourceMap::new(
244 [
245 ("foo.qs".into(), "namespace Foo { }".into()),
246 ("bar.qs".into(), "namespace Bar { }".into()),
247 ],
248 None,
249 );
250 let (unit, _) =
251 compile::compile(&store, &dependencies, sources, package_type, capabilities);
252 let user_package_id = store.insert(unit);
253
254 (store, std_package_id, user_package_id)
255 }
256}
257