microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
compiler/qsc_parse/src/prim/tests.rs
368lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use super::{ident, opt, pat, path, seq}; |
| 5 | use crate::{ |
| 6 | keyword::Keyword, |
| 7 | lex::{ClosedBinOp, TokenKind}, |
| 8 | scan::Scanner, |
| 9 | tests::{check, check_opt, check_seq}, |
| 10 | Error, ErrorKind, |
| 11 | }; |
| 12 | use expect_test::expect; |
| 13 | use qsc_data_structures::span::Span; |
| 14 | |
| 15 | #[test] |
| 16 | fn ident_basic() { |
| 17 | check(ident, "foo", &expect![[r#"Ident _id_ [0-3] "foo""#]]); |
| 18 | } |
| 19 | |
| 20 | #[test] |
| 21 | fn ident_num_suffix() { |
| 22 | check(ident, "foo2", &expect![[r#"Ident _id_ [0-4] "foo2""#]]); |
| 23 | } |
| 24 | |
| 25 | #[test] |
| 26 | fn ident_underscore_prefix() { |
| 27 | check(ident, "_foo", &expect![[r#"Ident _id_ [0-4] "_foo""#]]); |
| 28 | } |
| 29 | |
| 30 | #[test] |
| 31 | fn ident_num_prefix() { |
| 32 | check( |
| 33 | ident, |
| 34 | "2foo", |
| 35 | &expect![[r#" |
| 36 | Error( |
| 37 | Rule( |
| 38 | "identifier", |
| 39 | Int( |
| 40 | Decimal, |
| 41 | ), |
| 42 | Span { |
| 43 | lo: 0, |
| 44 | hi: 1, |
| 45 | }, |
| 46 | ), |
| 47 | ) |
| 48 | "#]], |
| 49 | ); |
| 50 | } |
| 51 | |
| 52 | #[test] |
| 53 | fn ident_keyword() { |
| 54 | for keyword in enum_iterator::all::<Keyword>() { |
| 55 | let mut scanner = Scanner::new(keyword.as_str()); |
| 56 | let actual = ident(&mut scanner); |
| 57 | let span = Span { |
| 58 | lo: 0, |
| 59 | hi: keyword |
| 60 | .as_str() |
| 61 | .len() |
| 62 | .try_into() |
| 63 | .expect("keyword length should fit into u32"), |
| 64 | }; |
| 65 | |
| 66 | let expected = Error(match keyword { |
| 67 | Keyword::And => { |
| 68 | ErrorKind::Rule("identifier", TokenKind::ClosedBinOp(ClosedBinOp::And), span) |
| 69 | } |
| 70 | Keyword::Or => { |
| 71 | ErrorKind::Rule("identifier", TokenKind::ClosedBinOp(ClosedBinOp::Or), span) |
| 72 | } |
| 73 | _ => ErrorKind::Rule("identifier", TokenKind::Keyword(keyword), span), |
| 74 | }); |
| 75 | |
| 76 | assert_eq!(actual, Err(expected), "{keyword}"); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | #[test] |
| 81 | fn path_single() { |
| 82 | check( |
| 83 | path, |
| 84 | "Foo", |
| 85 | &expect![[r#"Path _id_ [0-3] (Ident _id_ [0-3] "Foo")"#]], |
| 86 | ); |
| 87 | } |
| 88 | |
| 89 | #[test] |
| 90 | fn path_double() { |
| 91 | check( |
| 92 | path, |
| 93 | "Foo.Bar", |
| 94 | &expect![[r#"Path _id_ [0-7] (Ident _id_ [0-3] "Foo") (Ident _id_ [4-7] "Bar")"#]], |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | #[test] |
| 99 | fn path_triple() { |
| 100 | check( |
| 101 | path, |
| 102 | "Foo.Bar.Baz", |
| 103 | &expect![[r#"Path _id_ [0-11] (Ident _id_ [0-7] "Foo.Bar") (Ident _id_ [8-11] "Baz")"#]], |
| 104 | ); |
| 105 | } |
| 106 | |
| 107 | #[test] |
| 108 | fn path_trailing_dot() { |
| 109 | check( |
| 110 | path, |
| 111 | "Foo.Bar.", |
| 112 | &expect![[r#" |
| 113 | Error( |
| 114 | Rule( |
| 115 | "identifier", |
| 116 | Eof, |
| 117 | Span { |
| 118 | lo: 8, |
| 119 | hi: 8, |
| 120 | }, |
| 121 | ), |
| 122 | ) |
| 123 | "#]], |
| 124 | ); |
| 125 | } |
| 126 | |
| 127 | #[test] |
| 128 | fn pat_bind() { |
| 129 | check( |
| 130 | pat, |
| 131 | "foo", |
| 132 | &expect![[r#" |
| 133 | Pat _id_ [0-3]: Bind: |
| 134 | Ident _id_ [0-3] "foo""#]], |
| 135 | ); |
| 136 | } |
| 137 | |
| 138 | #[test] |
| 139 | fn pat_bind_ty() { |
| 140 | check( |
| 141 | pat, |
| 142 | "foo : Int", |
| 143 | &expect![[r#" |
| 144 | Pat _id_ [0-9]: Bind: |
| 145 | Ident _id_ [0-3] "foo" |
| 146 | Type _id_ [6-9]: Path: Path _id_ [6-9] (Ident _id_ [6-9] "Int")"#]], |
| 147 | ); |
| 148 | } |
| 149 | |
| 150 | #[test] |
| 151 | fn pat_bind_discard() { |
| 152 | check(pat, "_", &expect!["Pat _id_ [0-1]: Discard"]); |
| 153 | } |
| 154 | |
| 155 | #[test] |
| 156 | fn pat_discard_ty() { |
| 157 | check( |
| 158 | pat, |
| 159 | "_ : Int", |
| 160 | &expect![[r#" |
| 161 | Pat _id_ [0-7]: Discard: |
| 162 | Type _id_ [4-7]: Path: Path _id_ [4-7] (Ident _id_ [4-7] "Int")"#]], |
| 163 | ); |
| 164 | } |
| 165 | |
| 166 | #[test] |
| 167 | fn pat_paren() { |
| 168 | check( |
| 169 | pat, |
| 170 | "(foo)", |
| 171 | &expect![[r#" |
| 172 | Pat _id_ [0-5]: Paren: |
| 173 | Pat _id_ [1-4]: Bind: |
| 174 | Ident _id_ [1-4] "foo""#]], |
| 175 | ); |
| 176 | } |
| 177 | |
| 178 | #[test] |
| 179 | fn pat_singleton_tuple() { |
| 180 | check( |
| 181 | pat, |
| 182 | "(foo,)", |
| 183 | &expect![[r#" |
| 184 | Pat _id_ [0-6]: Tuple: |
| 185 | Pat _id_ [1-4]: Bind: |
| 186 | Ident _id_ [1-4] "foo""#]], |
| 187 | ); |
| 188 | } |
| 189 | |
| 190 | #[test] |
| 191 | fn pat_tuple() { |
| 192 | check( |
| 193 | pat, |
| 194 | "(foo, bar)", |
| 195 | &expect![[r#" |
| 196 | Pat _id_ [0-10]: Tuple: |
| 197 | Pat _id_ [1-4]: Bind: |
| 198 | Ident _id_ [1-4] "foo" |
| 199 | Pat _id_ [6-9]: Bind: |
| 200 | Ident _id_ [6-9] "bar""#]], |
| 201 | ); |
| 202 | } |
| 203 | |
| 204 | #[test] |
| 205 | fn pat_tuple_ty_discard() { |
| 206 | check( |
| 207 | pat, |
| 208 | "(foo : Int, _)", |
| 209 | &expect![[r#" |
| 210 | Pat _id_ [0-14]: Tuple: |
| 211 | Pat _id_ [1-10]: Bind: |
| 212 | Ident _id_ [1-4] "foo" |
| 213 | Type _id_ [7-10]: Path: Path _id_ [7-10] (Ident _id_ [7-10] "Int") |
| 214 | Pat _id_ [12-13]: Discard"#]], |
| 215 | ); |
| 216 | } |
| 217 | |
| 218 | #[test] |
| 219 | fn pat_invalid() { |
| 220 | check( |
| 221 | pat, |
| 222 | "@", |
| 223 | &expect![[r#" |
| 224 | Error( |
| 225 | Rule( |
| 226 | "pattern", |
| 227 | At, |
| 228 | Span { |
| 229 | lo: 0, |
| 230 | hi: 1, |
| 231 | }, |
| 232 | ), |
| 233 | ) |
| 234 | "#]], |
| 235 | ); |
| 236 | } |
| 237 | |
| 238 | #[test] |
| 239 | fn pat_missing_ty() { |
| 240 | check( |
| 241 | pat, |
| 242 | "foo :", |
| 243 | &expect![[r#" |
| 244 | Error( |
| 245 | Rule( |
| 246 | "type", |
| 247 | Eof, |
| 248 | Span { |
| 249 | lo: 5, |
| 250 | hi: 5, |
| 251 | }, |
| 252 | ), |
| 253 | ) |
| 254 | "#]], |
| 255 | ); |
| 256 | } |
| 257 | |
| 258 | #[test] |
| 259 | fn opt_succeed() { |
| 260 | check_opt( |
| 261 | |s| opt(s, path), |
| 262 | "Foo.Bar", |
| 263 | &expect![[r#"Path _id_ [0-7] (Ident _id_ [0-3] "Foo") (Ident _id_ [4-7] "Bar")"#]], |
| 264 | ); |
| 265 | } |
| 266 | |
| 267 | #[test] |
| 268 | fn opt_fail_no_consume() { |
| 269 | check_opt(|s| opt(s, path), "123", &expect!["None"]); |
| 270 | } |
| 271 | |
| 272 | #[test] |
| 273 | fn opt_fail_consume() { |
| 274 | check_opt( |
| 275 | |s| opt(s, path), |
| 276 | "Foo.#", |
| 277 | &expect![[r#" |
| 278 | Error( |
| 279 | Rule( |
| 280 | "identifier", |
| 281 | Eof, |
| 282 | Span { |
| 283 | lo: 5, |
| 284 | hi: 5, |
| 285 | }, |
| 286 | ), |
| 287 | ) |
| 288 | |
| 289 | [ |
| 290 | Error( |
| 291 | Lex( |
| 292 | Unknown( |
| 293 | '#', |
| 294 | Span { |
| 295 | lo: 4, |
| 296 | hi: 5, |
| 297 | }, |
| 298 | ), |
| 299 | ), |
| 300 | ), |
| 301 | ]"#]], |
| 302 | ); |
| 303 | } |
| 304 | |
| 305 | #[test] |
| 306 | fn seq_empty() { |
| 307 | check_seq(|s| seq(s, ident), "", &expect!["(, Missing)"]); |
| 308 | } |
| 309 | |
| 310 | #[test] |
| 311 | fn seq_single() { |
| 312 | check_seq( |
| 313 | |s| seq(s, ident), |
| 314 | "foo", |
| 315 | &expect![[r#"(Ident _id_ [0-3] "foo", Missing)"#]], |
| 316 | ); |
| 317 | } |
| 318 | |
| 319 | #[test] |
| 320 | fn seq_double() { |
| 321 | check_seq( |
| 322 | |s| seq(s, ident), |
| 323 | "foo, bar", |
| 324 | &expect![[r#" |
| 325 | (Ident _id_ [0-3] "foo", |
| 326 | Ident _id_ [5-8] "bar", Missing)"#]], |
| 327 | ); |
| 328 | } |
| 329 | |
| 330 | #[test] |
| 331 | fn seq_trailing() { |
| 332 | check_seq( |
| 333 | |s| seq(s, ident), |
| 334 | "foo, bar,", |
| 335 | &expect![[r#" |
| 336 | (Ident _id_ [0-3] "foo", |
| 337 | Ident _id_ [5-8] "bar", Present)"#]], |
| 338 | ); |
| 339 | } |
| 340 | |
| 341 | #[test] |
| 342 | fn seq_fail_no_consume() { |
| 343 | check_seq( |
| 344 | |s| seq(s, ident), |
| 345 | "foo, 2", |
| 346 | &expect![[r#"(Ident _id_ [0-3] "foo", Present)"#]], |
| 347 | ); |
| 348 | } |
| 349 | |
| 350 | #[test] |
| 351 | fn seq_fail_consume() { |
| 352 | check_seq( |
| 353 | |s| seq(s, path), |
| 354 | "foo, bar.", |
| 355 | &expect![[r#" |
| 356 | Error( |
| 357 | Rule( |
| 358 | "identifier", |
| 359 | Eof, |
| 360 | Span { |
| 361 | lo: 9, |
| 362 | hi: 9, |
| 363 | }, |
| 364 | ), |
| 365 | ) |
| 366 | "#]], |
| 367 | ); |
| 368 | } |
| 369 | |