compiler/
lib/
examples/
std/
arch/
char/
collections/
graph/
lang/
alloc/
ast/
gen/
il/
module/
parser/
tests.rad
138.8 KiB
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.9 KiB
gen.rad
513 B
il.rad
20.4 KiB
lower.rad
321.7 KiB
module.rad
17.3 KiB
package.rad
1.3 KiB
parser.rad
92.2 KiB
resolver.rad
511.1 KiB
scanner.rad
17.9 KiB
sexpr.rad
6.7 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
graph.rad
4.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
299 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CELL_PERMISSIONS
6.8 KiB
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
5.4 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
808 B
lib/std/lang/parser/tests.rad
raw
| 1 | //! Parser tests. |
| 2 | |
| 3 | use std::mem; |
| 4 | use std::fmt; |
| 5 | use std::testing; |
| 6 | use std::lang::ast; |
| 7 | use std::lang::alloc; |
| 8 | use std::lang::sexpr; |
| 9 | use std::lang::ast::printer; |
| 10 | use std::lang::scanner; |
| 11 | use std::lang::strings; |
| 12 | |
| 13 | /// Allocated nodes publish immutable pointers with stable metadata and edges. |
| 14 | @test unsafe fn testAstNodePublication() throws (testing::TestError) { |
| 15 | static STORAGE: [u8; 4096] = [0; 4096]; |
| 16 | let mut arena = ast::nodeArena(&mut STORAGE[..]); |
| 17 | let allocate: unsafe fn(&mut ast::NodeArena, ast::Span, ast::NodeValue) -> *ast::Node = ast::allocNode; |
| 18 | let synthesize: unsafe fn(&mut ast::NodeArena, ast::NodeValue) -> *ast::Node = ast::synthNode; |
| 19 | let leaf = allocate(&mut arena, ast::Span { offset: 9, length: 4 }, ast::NodeValue::Bool(true)); |
| 20 | let root = synthesize(&mut arena, ast::NodeValue::ExprStmt(leaf)); |
| 21 | assert leaf.id == 0; |
| 22 | assert leaf.span.offset == 9; |
| 23 | assert leaf.span.length == 4; |
| 24 | assert root.id == 1; |
| 25 | assert root.span.offset == 0; |
| 26 | assert root.span.length == 0; |
| 27 | let case ast::NodeValue::ExprStmt(child) = root.value else throw testing::TestError::Failed; |
| 28 | assert child == leaf; |
| 29 | assert arena.nextId == 2; |
| 30 | } |
| 31 | |
| 32 | /// Unified arena size. |
| 33 | constant ARENA_SIZE: u32 = 2097152; |
| 34 | /// Unified arena storage for all AST allocations. |
| 35 | static ARENA_STORAGE: [u8; ARENA_SIZE] = [0; ARENA_SIZE]; |
| 36 | /// String pool. |
| 37 | unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
| 38 | |
| 39 | /// Assert that a node is an identifier with the given name. |
| 40 | fn expectIdent(node: *ast::Node, name: *[u8]) |
| 41 | throws (testing::TestError) |
| 42 | { |
| 43 | let case ast::NodeValue::Ident(n) = node.value |
| 44 | if mem::eq(n, name) |
| 45 | else throw testing::TestError::Failed; |
| 46 | } |
| 47 | |
| 48 | /// Assert that a node is a type identifier with the given name. |
| 49 | fn expectTypeIdent(node: *ast::Node, name: *[u8]) |
| 50 | throws (testing::TestError) |
| 51 | { |
| 52 | let case ast::NodeValue::TypeSig(ts) = node.value |
| 53 | else throw testing::TestError::Failed; |
| 54 | let case ast::TypeSig::Nominal(ident) = ts |
| 55 | else throw testing::TestError::Failed; |
| 56 | |
| 57 | try expectIdent(ident, name); |
| 58 | } |
| 59 | |
| 60 | /// Assert that a node is a number literal with the given text. |
| 61 | fn expectNumber(node: *ast::Node, text: *[u8]) |
| 62 | throws (testing::TestError) |
| 63 | { |
| 64 | let case ast::NodeValue::Number(n) = node.value |
| 65 | if mem::eq(n.text, text) |
| 66 | else throw testing::TestError::Failed; |
| 67 | } |
| 68 | |
| 69 | /// Assert that a node is a range literal with the given optional bounds. |
| 70 | fn expectRangeNumbers(node: *ast::Node, start: ?*[u8], end: ?*[u8]) |
| 71 | throws (testing::TestError) |
| 72 | { |
| 73 | let case ast::NodeValue::Range(range) = node.value |
| 74 | else throw testing::TestError::Failed; |
| 75 | |
| 76 | if let text = start { |
| 77 | let startNode = range.start |
| 78 | else throw testing::TestError::Failed; |
| 79 | try expectNumber(startNode, text); |
| 80 | } else { |
| 81 | try testing::expect(range.start == nil); |
| 82 | } |
| 83 | if let text = end { |
| 84 | let endNode = range.end |
| 85 | else throw testing::TestError::Failed; |
| 86 | try expectNumber(endNode, text); |
| 87 | } else { |
| 88 | try testing::expect(range.end == nil); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | /// Token operations use the parser's checked pool borrow. |
| 93 | fn checkTokenOperations 'pool (p: &mut super::Parser 'pool) throws (testing::TestError) { |
| 94 | super::advance(p); |
| 95 | let name = try super::expect(p, scanner::TokenKind::Ident, "expected name") catch { |
| 96 | throw testing::TestError::Failed; |
| 97 | }; |
| 98 | try testing::expectBytesEq(name, "alpha"); |
| 99 | try testing::expect(super::consume(p, scanner::TokenKind::Comma)); |
| 100 | try testing::expect(not super::consume(p, scanner::TokenKind::Comma)); |
| 101 | try testing::expect(super::check(p, scanner::TokenKind::Ident)); |
| 102 | super::advance(p); |
| 103 | try testing::expect(super::check(p, scanner::TokenKind::Eof)); |
| 104 | } |
| 105 | |
| 106 | /// Scanner state can advance without an unsafe token operation. |
| 107 | @test unsafe fn testSafeTokenOperations() throws (testing::TestError) { |
| 108 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 109 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 110 | let mut parser = super::mkParser(scanner::SourceLoc::String, "alpha, beta", arenaRef, poolRef); |
| 111 | try checkTokenOperations(&mut parser); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | /// Parse multiple statements from a string. |
| 116 | unsafe fn parseStmtsStr(input: *[u8]) -> *ast::Node |
| 117 | throws (testing::TestError) |
| 118 | { |
| 119 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 120 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 121 | let mut parser = super::mkParser(scanner::SourceLoc::String, input, arenaRef, poolRef); |
| 122 | return try super::parseModule(&mut parser) catch { |
| 123 | throw testing::TestError::Failed; |
| 124 | }; |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | /// Parse a single type from a string. |
| 129 | unsafe fn parseTypeStr(input: *[u8]) -> *ast::Node |
| 130 | throws (super::ParseError) |
| 131 | { |
| 132 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 133 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 134 | let mut parser = super::mkParser(scanner::SourceLoc::String, input, arenaRef, poolRef); |
| 135 | super::advance(&mut parser); |
| 136 | let root = try super::parseType(&mut parser); |
| 137 | try super::expect(&mut parser, scanner::TokenKind::Eof, "expected end of type"); |
| 138 | |
| 139 | return root; |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | /// Parse a single expression from a string. |
| 144 | export unsafe fn parseExprStr(input: *[u8]) -> *ast::Node |
| 145 | throws (super::ParseError) |
| 146 | { |
| 147 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 148 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 149 | let mut parser = super::mkParser(scanner::SourceLoc::String, input, arenaRef, poolRef); |
| 150 | super::advance(&mut parser); |
| 151 | return try super::parseExpr(&mut parser); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | /// Parse a single statement from a string. |
| 156 | unsafe fn parseStmtStr(input: *[u8]) -> *ast::Node |
| 157 | throws (super::ParseError) |
| 158 | { |
| 159 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 160 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 161 | let mut parser = super::mkParser(scanner::SourceLoc::String, input, arenaRef, poolRef); |
| 162 | super::advance(&mut parser); |
| 163 | let root = try super::parseStmt(&mut parser); |
| 164 | while super::consume(&mut parser, scanner::TokenKind::Semicolon) {} |
| 165 | try super::expect(&mut parser, scanner::TokenKind::Eof, "expected end of statement"); |
| 166 | |
| 167 | return root; |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | /// Parse an expression expected to be a number literal and return its payload. |
| 172 | unsafe fn parseNumberLiteral(text: *[u8]) -> fmt::IntLiteral |
| 173 | throws (testing::TestError) |
| 174 | { |
| 175 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 176 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 177 | let mut parser = super::mkParser(scanner::SourceLoc::String, text, arenaRef, poolRef); |
| 178 | super::advance(&mut parser); |
| 179 | |
| 180 | let node = try! super::parseExpr(&mut parser); |
| 181 | |
| 182 | if not super::check(&parser, scanner::TokenKind::Eof) { |
| 183 | throw testing::TestError::Failed; |
| 184 | } |
| 185 | let case ast::NodeValue::Number(lit) = node.value |
| 186 | else throw testing::TestError::Failed; |
| 187 | |
| 188 | return lit; |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | /// Ensure that parsing the supplied literal source fails. |
| 193 | unsafe fn expectNumberLiteralFail(text: *[u8]) |
| 194 | throws (testing::TestError) |
| 195 | { |
| 196 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 197 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 198 | let mut parser = super::mkParser(scanner::SourceLoc::String, text, arenaRef, poolRef); |
| 199 | super::advance(&mut parser); |
| 200 | |
| 201 | try super::parseExpr(&mut parser) catch { |
| 202 | return; |
| 203 | }; |
| 204 | if not super::check(&parser, scanner::TokenKind::Eof) { |
| 205 | return; |
| 206 | } |
| 207 | throw testing::TestError::Failed; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | /// Assert that a node is a type signature matching the expected type. |
| 212 | fn expectType(node: *ast::Node, type: ast::TypeSig) |
| 213 | throws (testing::TestError) |
| 214 | { |
| 215 | let case ast::NodeValue::TypeSig(t) = node.value |
| 216 | if (t == type) |
| 217 | else throw testing::TestError::Failed; |
| 218 | } |
| 219 | |
| 220 | /// Assert that a node is an integer type with the expected width and sign. |
| 221 | fn expectIntType(node: *ast::Node, expectedWidth: u32, expectedSign: ast::Signedness) |
| 222 | throws (testing::TestError) |
| 223 | { |
| 224 | let case ast::NodeValue::TypeSig(sig) = node.value |
| 225 | else throw testing::TestError::Failed; |
| 226 | |
| 227 | let case ast::TypeSig::Integer { width, sign } = sig |
| 228 | else throw testing::TestError::Failed; |
| 229 | |
| 230 | try testing::expect(width == expectedWidth); |
| 231 | try testing::expect(sign == expectedSign); |
| 232 | } |
| 233 | |
| 234 | /// Extract a union variant and verify its name and index. |
| 235 | /// Returns the payload's fields slice for further checking with `expectField`. |
| 236 | fn expectVariant(varNode: *ast::Node, name: *[u8], index: u32) -> ?*[*ast::Node] |
| 237 | throws (testing::TestError) |
| 238 | { |
| 239 | let case ast::NodeValue::UnionDeclVariant(v) = varNode.value |
| 240 | else throw testing::TestError::Failed; |
| 241 | try expectIdent(v.name, name); |
| 242 | try testing::expect(v.index == index); |
| 243 | try testing::expect(v.value == nil); |
| 244 | |
| 245 | let payloadType = v.type else return nil; |
| 246 | let case ast::NodeValue::TypeSig(sig) = payloadType.value |
| 247 | else throw testing::TestError::Failed; |
| 248 | let case ast::TypeSig::Record { fields, .. } = sig |
| 249 | else throw testing::TestError::Failed; |
| 250 | |
| 251 | return fields; |
| 252 | } |
| 253 | |
| 254 | /// Check a record field has the expected name and type signature. |
| 255 | fn expectFieldSig( |
| 256 | fields: *[*ast::Node], index: u32, name: ?*[u8], sig: ast::TypeSig |
| 257 | ) throws (testing::TestError) { |
| 258 | let fieldNode = fields[index]; |
| 259 | let case ast::NodeValue::RecordField { field, type: fieldType, .. } = fieldNode.value |
| 260 | else throw testing::TestError::Failed; |
| 261 | |
| 262 | if let expectedName = name { |
| 263 | let actualName = field else throw testing::TestError::Failed; |
| 264 | try expectIdent(actualName, expectedName); |
| 265 | } else { |
| 266 | try testing::expect(field == nil); |
| 267 | } |
| 268 | try expectType(fieldType, sig); |
| 269 | } |
| 270 | |
| 271 | /// Assert that a block's first statement is an expression statement with the expected value. |
| 272 | fn expectBlockExprStmt(blk: *ast::Node, expected: ast::NodeValue) |
| 273 | throws (testing::TestError) |
| 274 | { |
| 275 | let stmt = try getBlockFirstStmt(blk); |
| 276 | let case ast::NodeValue::ExprStmt(expr) = stmt.value |
| 277 | else throw testing::TestError::Failed; |
| 278 | |
| 279 | if let case ast::NodeValue::Ident(e) = expected { |
| 280 | if let case ast::NodeValue::Ident(a) = expr.value { |
| 281 | if mem::eq(e, a) { |
| 282 | return; |
| 283 | } else { |
| 284 | throw testing::TestError::Failed; |
| 285 | } |
| 286 | } |
| 287 | } |
| 288 | panic "expectBlockExprStmt: comparing values we don't know how to compare"; |
| 289 | } |
| 290 | |
| 291 | /// Get the first statement from a block node. |
| 292 | export fn getBlockFirstStmt(blk: *ast::Node) -> *ast::Node |
| 293 | throws (testing::TestError) |
| 294 | { |
| 295 | let case ast::NodeValue::Block(block) = blk.value |
| 296 | else throw testing::TestError::Failed; |
| 297 | |
| 298 | if block.statements.len == 0 { |
| 299 | throw testing::TestError::Failed; |
| 300 | } |
| 301 | return block.statements[0]; |
| 302 | } |
| 303 | |
| 304 | /// Get the last statement from a block node. |
| 305 | export fn getBlockLastStmt(blk: *ast::Node) -> *ast::Node |
| 306 | throws (testing::TestError) |
| 307 | { |
| 308 | let case ast::NodeValue::Block(block) = blk.value |
| 309 | else throw testing::TestError::Failed; |
| 310 | |
| 311 | if block.statements.len == 0 { |
| 312 | throw testing::TestError::Failed; |
| 313 | } |
| 314 | return block.statements[block.statements.len - 1]; |
| 315 | } |
| 316 | |
| 317 | /// Test parsing boolean literals (`true` and `false`). |
| 318 | @test unsafe fn testParseBool() throws (testing::TestError) { |
| 319 | let r1 = try! parseExprStr("true"); |
| 320 | let case ast::NodeValue::Bool(v1) = r1.value if v1 |
| 321 | else throw testing::TestError::Failed; |
| 322 | |
| 323 | let r2 = try! parseExprStr("false"); |
| 324 | let case ast::NodeValue::Bool(v2) = r2.value if not v2 |
| 325 | else throw testing::TestError::Failed; |
| 326 | } |
| 327 | |
| 328 | /// Test parsing number literals. |
| 329 | @test unsafe fn testParseNumber() throws (testing::TestError) { |
| 330 | let r1 = try! parseExprStr("4519"); |
| 331 | try expectNumber(r1, "4519"); |
| 332 | } |
| 333 | |
| 334 | /// Verify that decimal literals record magnitude and base metadata. |
| 335 | @test unsafe fn testParseDecimalLiteralMetadata() throws (testing::TestError) { |
| 336 | let lit = try parseNumberLiteral("1234"); |
| 337 | try testing::expect(lit.magnitude == 1234); |
| 338 | try testing::expect(lit.radix == fmt::Radix::Decimal); |
| 339 | } |
| 340 | |
| 341 | /// Verify that hexadecimal literals record magnitude and radix metadata. |
| 342 | @test unsafe fn testParseNumberMetadata() throws (testing::TestError) { |
| 343 | let lit = try parseNumberLiteral("0xFF"); |
| 344 | try testing::expect(lit.magnitude == 0xFF); |
| 345 | try testing::expect(lit.radix == fmt::Radix::Hex); |
| 346 | } |
| 347 | |
| 348 | /// Verify that binary literals capture their radix. |
| 349 | @test unsafe fn testParseBinaryLiteralMetadata() throws (testing::TestError) { |
| 350 | let lit = try parseNumberLiteral("0b1010"); |
| 351 | try testing::expect(lit.magnitude == 0b1010); |
| 352 | try testing::expect(lit.radix == fmt::Radix::Binary); |
| 353 | } |
| 354 | |
| 355 | /// Negative literals parse as unary negation of an unsigned number. |
| 356 | @test unsafe fn testParseNegativeLiteral() throws (testing::TestError) { |
| 357 | let node = try! parseExprStr("-99"); |
| 358 | let case ast::NodeValue::UnOp(neg) = node.value |
| 359 | else throw testing::TestError::Failed; |
| 360 | try testing::expect(neg.op == ast::UnaryOp::Neg); |
| 361 | let case ast::NodeValue::Number(lit) = neg.value.value |
| 362 | else throw testing::TestError::Failed; |
| 363 | try testing::expect(lit.magnitude == 99); |
| 364 | } |
| 365 | |
| 366 | /// Unary plus is not part of the expression grammar. |
| 367 | @test unsafe fn testRejectUnaryPlus() throws (testing::TestError) { |
| 368 | try expectNumberLiteralFail("+1"); |
| 369 | try expectNumberLiteralFail("+value"); |
| 370 | try expectNumberLiteralFail("+(value)"); |
| 371 | } |
| 372 | |
| 373 | /// Range expressions parse with explicit start and end bounds. |
| 374 | @test unsafe fn testParseRangeExpr() throws (testing::TestError) { |
| 375 | let node = try! parseExprStr("0..5"); |
| 376 | try expectRangeNumbers(node, "0", "5"); |
| 377 | } |
| 378 | |
| 379 | /// Range expressions allow a missing end bound. |
| 380 | @test unsafe fn testParseRangeExprNoEnd() throws (testing::TestError) { |
| 381 | let node = try! parseExprStr("0.."); |
| 382 | try expectRangeNumbers(node, "0", nil); |
| 383 | } |
| 384 | |
| 385 | /// Range expressions allow a missing start bound. |
| 386 | @test unsafe fn testParseRangeExprNoStart() throws (testing::TestError) { |
| 387 | let node = try! parseExprStr("..5"); |
| 388 | try expectRangeNumbers(node, nil, "5"); |
| 389 | } |
| 390 | |
| 391 | /// Literals with out-of-range digits for their base are rejected. |
| 392 | @test unsafe fn testParseInvalidIntLiteral() throws (testing::TestError) { |
| 393 | // 2^64 overflows u64. |
| 394 | try expectNumberLiteralFail("18446744073709551616"); |
| 395 | try expectNumberLiteralFail("0x10000000000000000"); |
| 396 | try expectNumberLiteralFail("0x1G"); |
| 397 | try expectNumberLiteralFail("0b102"); |
| 398 | } |
| 399 | |
| 400 | /// Test parsing nil literal. |
| 401 | @test unsafe fn testParseNil() throws (testing::TestError) { |
| 402 | let r1 = try! parseExprStr("nil"); |
| 403 | let case ast::NodeValue::Nil = r1.value |
| 404 | else throw testing::TestError::Failed; |
| 405 | } |
| 406 | |
| 407 | /// Test parsing undefined literal. |
| 408 | @test unsafe fn testParseUndefined() throws (testing::TestError) { |
| 409 | let r1 = try! parseExprStr("undefined"); |
| 410 | let case ast::NodeValue::Undef = r1.value |
| 411 | else throw testing::TestError::Failed; |
| 412 | } |
| 413 | |
| 414 | /// Test parsing character literals. |
| 415 | @test unsafe fn testParseChar() throws (testing::TestError) { |
| 416 | let r1 = try! parseExprStr("'a'"); |
| 417 | let case ast::NodeValue::Char(c1) = r1.value if c1 == 'a' |
| 418 | else throw testing::TestError::Failed; |
| 419 | |
| 420 | let r2 = try! parseExprStr("'\\n'"); |
| 421 | let case ast::NodeValue::Char(c2) = r2.value if c2 == '\n' |
| 422 | else throw testing::TestError::Failed; |
| 423 | |
| 424 | let r3 = try! parseExprStr("'\\t'"); |
| 425 | let case ast::NodeValue::Char(c3) = r3.value if c3 == '\t' |
| 426 | else throw testing::TestError::Failed; |
| 427 | } |
| 428 | |
| 429 | /// Test parsing string literals. |
| 430 | @test unsafe fn testParseString() throws (testing::TestError) { |
| 431 | let r1 = try! parseExprStr("\"hello\""); |
| 432 | let case ast::NodeValue::String(s1) = r1.value if mem::eq(s1, "hello") |
| 433 | else throw testing::TestError::Failed; |
| 434 | |
| 435 | let r2 = try! parseExprStr("\"\""); |
| 436 | let case ast::NodeValue::String(s2) = r2.value if s2.len == 0 |
| 437 | else throw testing::TestError::Failed; |
| 438 | } |
| 439 | |
| 440 | /// Test string escape sequence processing. |
| 441 | @test unsafe fn testParseStringEscape() throws (testing::TestError) { |
| 442 | // Tab and newline. |
| 443 | let r1 = try! parseExprStr("\"hello\\tworld\\n\""); |
| 444 | let case ast::NodeValue::String(s1) = r1.value if s1.len == 12 |
| 445 | else throw testing::TestError::Failed; |
| 446 | if s1[5] <> '\t' { |
| 447 | throw testing::TestError::Failed; |
| 448 | } |
| 449 | if s1[11] <> '\n' { |
| 450 | throw testing::TestError::Failed; |
| 451 | } |
| 452 | |
| 453 | // Escaped quote. |
| 454 | let r2 = try! parseExprStr("\"\\\"\""); |
| 455 | let case ast::NodeValue::String(s2) = r2.value if s2.len == 1 |
| 456 | else throw testing::TestError::Failed; |
| 457 | if s2[0] <> '"' { |
| 458 | throw testing::TestError::Failed; |
| 459 | } |
| 460 | |
| 461 | // Escaped backslash. |
| 462 | let r3 = try! parseExprStr("\"\\\\\""); |
| 463 | let case ast::NodeValue::String(s3) = r3.value if s3.len == 1 |
| 464 | else throw testing::TestError::Failed; |
| 465 | if s3[0] <> '\\' { |
| 466 | throw testing::TestError::Failed; |
| 467 | } |
| 468 | |
| 469 | // Mixed escapes. |
| 470 | let r4 = try! parseExprStr("\"a\\nb\\tc\""); |
| 471 | let case ast::NodeValue::String(s4) = r4.value if s4.len == 5 |
| 472 | else throw testing::TestError::Failed; |
| 473 | if s4[0] <> 'a' { |
| 474 | throw testing::TestError::Failed; |
| 475 | } |
| 476 | if s4[1] <> '\n' { |
| 477 | throw testing::TestError::Failed; |
| 478 | } |
| 479 | if s4[2] <> 'b' { |
| 480 | throw testing::TestError::Failed; |
| 481 | } |
| 482 | if s4[3] <> '\t' { |
| 483 | throw testing::TestError::Failed; |
| 484 | } |
| 485 | if s4[4] <> 'c' { |
| 486 | throw testing::TestError::Failed; |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | /// Test parsing placeholder/underscore. |
| 491 | @test unsafe fn testParsePlaceholder() throws (testing::TestError) { |
| 492 | let r1 = try! parseExprStr("_"); |
| 493 | let case ast::NodeValue::Placeholder = r1.value |
| 494 | else throw testing::TestError::Failed; |
| 495 | } |
| 496 | |
| 497 | /// Test parsing array literals. |
| 498 | @test unsafe fn testParseArrayLiteral() throws (testing::TestError) { |
| 499 | let r1 = try! parseExprStr("[]"); |
| 500 | let case ast::NodeValue::ArrayLit(items1) = r1.value if items1.len == 0 |
| 501 | else throw testing::TestError::Failed; |
| 502 | |
| 503 | let r2 = try! parseExprStr("[1]"); |
| 504 | let case ast::NodeValue::ArrayLit(items2) = r2.value if items2.len == 1 |
| 505 | else throw testing::TestError::Failed; |
| 506 | |
| 507 | let r3 = try! parseExprStr("[1, 2, 3]"); |
| 508 | let case ast::NodeValue::ArrayLit(items3) = r3.value if items3.len == 3 |
| 509 | else throw testing::TestError::Failed; |
| 510 | } |
| 511 | |
| 512 | /// Test parsing array repeat literals. |
| 513 | @test unsafe fn testParseArrayRepeatLiteral() throws (testing::TestError) { |
| 514 | let r1 = try! parseExprStr("[42; 10]"); |
| 515 | let case ast::NodeValue::ArrayRepeatLit(a) = r1.value |
| 516 | else throw testing::TestError::Failed; |
| 517 | |
| 518 | try expectNumber(a.item, "42"); |
| 519 | try expectNumber(a.count, "10"); |
| 520 | } |
| 521 | |
| 522 | /// Test parsing a simple `if` statement without an `else` clause. |
| 523 | @test unsafe fn testParseIf() throws (testing::TestError) { |
| 524 | let r1 = try parseStmtStr("if condition { body; }") catch { |
| 525 | throw testing::TestError::Failed; |
| 526 | }; |
| 527 | let case ast::NodeValue::If(n) = r1.value |
| 528 | else throw testing::TestError::Failed; |
| 529 | |
| 530 | try expectIdent(n.condition, "condition"); |
| 531 | try expectBlockExprStmt(n.thenBranch, ast::NodeValue::Ident("body")); |
| 532 | try testing::expect(n.elseBranch == nil); |
| 533 | } |
| 534 | |
| 535 | /// Test parsing an `if-else` statement. |
| 536 | @test unsafe fn testParseIfElse() throws (testing::TestError) { |
| 537 | let r1 = try! parseStmtStr("if condition { left; } else { right; }") catch { |
| 538 | throw testing::TestError::Failed; |
| 539 | }; |
| 540 | let case ast::NodeValue::If(n) = r1.value |
| 541 | else throw testing::TestError::Failed; |
| 542 | |
| 543 | try expectIdent(n.condition, "condition"); |
| 544 | try expectBlockExprStmt(n.thenBranch, ast::NodeValue::Ident("left")); |
| 545 | |
| 546 | let elseBranch = n.elseBranch |
| 547 | else throw testing::TestError::Failed; |
| 548 | |
| 549 | try expectBlockExprStmt(elseBranch, ast::NodeValue::Ident("right")); |
| 550 | } |
| 551 | |
| 552 | /// Test parsing an `if-else if-else` chain. |
| 553 | @test unsafe fn testParseIfElseIf() throws (testing::TestError) { |
| 554 | let root = try! parseStmtStr("if x { a; } else if y { b; } else { c; }") catch { |
| 555 | throw testing::TestError::Failed; |
| 556 | }; |
| 557 | let case ast::NodeValue::If(top) = root.value |
| 558 | else throw testing::TestError::Failed; |
| 559 | |
| 560 | try expectIdent(top.condition, "x"); |
| 561 | try expectBlockExprStmt(top.thenBranch, ast::NodeValue::Ident("a")); |
| 562 | |
| 563 | let topElse = top.elseBranch |
| 564 | else throw testing::TestError::Failed; |
| 565 | let nested = try getBlockFirstStmt(topElse); |
| 566 | let case ast::NodeValue::If(inner) = nested.value |
| 567 | else throw testing::TestError::Failed; |
| 568 | |
| 569 | try expectIdent(inner.condition, "y"); |
| 570 | try expectBlockExprStmt(inner.thenBranch, ast::NodeValue::Ident("b")); |
| 571 | |
| 572 | let innerElse = inner.elseBranch |
| 573 | else throw testing::TestError::Failed; |
| 574 | try expectBlockExprStmt(innerElse, ast::NodeValue::Ident("c")); |
| 575 | } |
| 576 | |
| 577 | /// Test parsing a block with multiple statements where the last lacks a semicolon. |
| 578 | @test unsafe fn testParseBlockMultiStmt() throws (testing::TestError) { |
| 579 | let root = try! parseStmtStr("{ first; second; third }"); |
| 580 | let case ast::NodeValue::Block(body) = root.value |
| 581 | else throw testing::TestError::Failed; |
| 582 | try testing::expect(body.statements.len == 3); |
| 583 | |
| 584 | let firstStmt = body.statements[0]; |
| 585 | let case ast::NodeValue::ExprStmt(firstExpr) = firstStmt.value |
| 586 | else throw testing::TestError::Failed; |
| 587 | try expectIdent(firstExpr, "first"); |
| 588 | |
| 589 | let secondStmt = body.statements[1]; |
| 590 | let case ast::NodeValue::ExprStmt(secondExpr) = secondStmt.value |
| 591 | else throw testing::TestError::Failed; |
| 592 | try expectIdent(secondExpr, "second"); |
| 593 | |
| 594 | let thirdStmt = body.statements[2]; |
| 595 | let case ast::NodeValue::ExprStmt(thirdExpr) = thirdStmt.value |
| 596 | else throw testing::TestError::Failed; |
| 597 | try expectIdent(thirdExpr, "third"); |
| 598 | } |
| 599 | |
| 600 | /// Test parsing a block that keeps a trailing `;` delimiter. |
| 601 | @test unsafe fn testParseBlockTrailingSemicolon() throws (testing::TestError) { |
| 602 | let root = try! parseStmtStr("if cond { only; }") catch { |
| 603 | throw testing::TestError::Failed; |
| 604 | }; |
| 605 | let case ast::NodeValue::If(node) = root.value |
| 606 | else throw testing::TestError::Failed; |
| 607 | |
| 608 | let case ast::NodeValue::Block(body) = node.thenBranch.value |
| 609 | else throw testing::TestError::Failed; |
| 610 | try testing::expect(body.statements.len == 1); |
| 611 | |
| 612 | let stmt = body.statements[0]; |
| 613 | let case ast::NodeValue::ExprStmt(expr) = stmt.value |
| 614 | else throw testing::TestError::Failed; |
| 615 | try expectIdent(expr, "only"); |
| 616 | } |
| 617 | |
| 618 | /// Test that missing delimiters between block statements produce an error. |
| 619 | @test unsafe fn testParseBlockMissingDelimiter() throws (testing::TestError) { |
| 620 | let parsed: ?*ast::Node = |
| 621 | try? parseStmtStr("if cond { first second }"); |
| 622 | try testing::expect(parsed == nil); |
| 623 | } |
| 624 | |
| 625 | /// Test parsing a `let` binding without a type annotation. |
| 626 | @test unsafe fn testParseLet() throws (testing::TestError) { |
| 627 | let r1 = try! parseStmtStr("let x = y;") catch { |
| 628 | throw testing::TestError::Failed; |
| 629 | }; |
| 630 | let case ast::NodeValue::Let(n) = r1.value |
| 631 | else throw testing::TestError::Failed; |
| 632 | |
| 633 | try expectIdent(n.ident, "x"); |
| 634 | try expectIdent(n.value, "y"); |
| 635 | try testing::expect(not n.mutable); |
| 636 | try testing::expect(n.type == nil); |
| 637 | } |
| 638 | |
| 639 | /// Test parsing a `let` binding with a type annotation. |
| 640 | @test unsafe fn testParseLetTyped() throws (testing::TestError) { |
| 641 | let r1 = try! parseStmtStr("let x: i32 = y;"); |
| 642 | let case ast::NodeValue::Let(n) = r1.value |
| 643 | else throw testing::TestError::Failed; |
| 644 | |
| 645 | try expectIdent(n.ident, "x"); |
| 646 | try expectIdent(n.value, "y"); |
| 647 | try testing::expect(not n.mutable); |
| 648 | |
| 649 | let type = n.type |
| 650 | else throw testing::TestError::Failed; |
| 651 | try expectType(type, ast::TypeSig::Integer { |
| 652 | width: 4, sign: ast::Signedness::Signed |
| 653 | }); |
| 654 | } |
| 655 | |
| 656 | /// Test parsing a `let` binding with alignment modifier. |
| 657 | @test unsafe fn testParseLetAlign() throws (testing::TestError) { |
| 658 | let r1 = try! parseStmtStr("let x: i32 align(16) = 13;"); |
| 659 | let case ast::NodeValue::Let(n) = r1.value |
| 660 | else throw testing::TestError::Failed; |
| 661 | |
| 662 | try expectIdent(n.ident, "x"); |
| 663 | try expectNumber(n.value, "13"); |
| 664 | try testing::expect(not n.mutable); |
| 665 | |
| 666 | let type = n.type |
| 667 | else throw testing::TestError::Failed; |
| 668 | try expectType(type, ast::TypeSig::Integer { |
| 669 | width: 4, sign: ast::Signedness::Signed |
| 670 | }); |
| 671 | |
| 672 | let alignment = n.alignment |
| 673 | else throw testing::TestError::Failed; |
| 674 | let case ast::NodeValue::Align(a) = alignment.value |
| 675 | else throw testing::TestError::Failed; |
| 676 | try expectNumber(a, "16"); |
| 677 | } |
| 678 | |
| 679 | /// Test parsing let-else statement. |
| 680 | @test unsafe fn testParseLetElse() throws (testing::TestError) { |
| 681 | let root = try! parseStmtStr("let x = opt else { return };"); |
| 682 | let case ast::NodeValue::LetElse(letElse) = root.value |
| 683 | else throw testing::TestError::Failed; |
| 684 | |
| 685 | try expectIdent(letElse.pattern.pattern, "x"); |
| 686 | |
| 687 | let case ast::NodeValue::Block(elseBlock) = letElse.elseBranch.value |
| 688 | else throw testing::TestError::Failed; |
| 689 | try testing::expect(elseBlock.statements.len == 1); |
| 690 | } |
| 691 | |
| 692 | /// Test parsing let-else with single statement. |
| 693 | @test unsafe fn testParseLetElseSingleStmt() throws (testing::TestError) { |
| 694 | let root = try! parseStmtStr("let y = val else return;"); |
| 695 | let case ast::NodeValue::LetElse(letElse) = root.value |
| 696 | else throw testing::TestError::Failed; |
| 697 | |
| 698 | try expectIdent(letElse.pattern.pattern, "y"); |
| 699 | |
| 700 | let case ast::NodeValue::Return(_) = letElse.elseBranch.value |
| 701 | else throw testing::TestError::Failed; |
| 702 | } |
| 703 | |
| 704 | /// Test parsing let-else with expression branch. |
| 705 | @test unsafe fn testParseLetElseExpr() throws (testing::TestError) { |
| 706 | let root = try! parseStmtStr("let z = opt else y;"); |
| 707 | let case ast::NodeValue::LetElse(letElse) = root.value |
| 708 | else throw testing::TestError::Failed; |
| 709 | |
| 710 | try expectIdent(letElse.pattern.pattern, "z"); |
| 711 | try expectIdent(letElse.elseBranch, "y"); |
| 712 | } |
| 713 | |
| 714 | /// Test parsing let-case-else statement. |
| 715 | @test unsafe fn testParseLetCaseElse() throws (testing::TestError) { |
| 716 | let root = try! parseStmtStr("let case Variant(x) = opt else { return };"); |
| 717 | let case ast::NodeValue::LetElse(letElse) = root.value |
| 718 | else throw testing::TestError::Failed; |
| 719 | |
| 720 | try testing::expect(letElse.pattern.guard == nil); |
| 721 | } |
| 722 | |
| 723 | /// Test parsing let-case-else with guard. |
| 724 | @test unsafe fn testParseLetCaseElseWithGuard() throws (testing::TestError) { |
| 725 | let root = try! parseStmtStr("let case Variant(x) = opt if x > 0 else { return };"); |
| 726 | let case ast::NodeValue::LetElse(letElse) = root.value |
| 727 | else throw testing::TestError::Failed; |
| 728 | |
| 729 | try testing::expect(letElse.pattern.guard <> nil); |
| 730 | |
| 731 | let guardNode = letElse.pattern.guard else throw testing::TestError::Failed; |
| 732 | let case ast::NodeValue::BinOp(cmp) = guardNode.value |
| 733 | else throw testing::TestError::Failed; |
| 734 | try testing::expect(cmp.op == ast::BinaryOp::Gt); |
| 735 | } |
| 736 | |
| 737 | /// Test parsing a `let mut` declaration. |
| 738 | @test unsafe fn testParseMut() throws (testing::TestError) { |
| 739 | let r1 = try! parseStmtStr("let mut x = 42;"); |
| 740 | let case ast::NodeValue::Let(n) = r1.value |
| 741 | else throw testing::TestError::Failed; |
| 742 | |
| 743 | try expectIdent(n.ident, "x"); |
| 744 | try expectNumber(n.value, "42"); |
| 745 | try testing::expect(n.mutable); |
| 746 | try testing::expect(n.type == nil); |
| 747 | } |
| 748 | |
| 749 | /// Test parsing a `let mut` declaration with type annotation. |
| 750 | @test unsafe fn testParseMutTyped() throws (testing::TestError) { |
| 751 | let r1 = try! parseStmtStr("let mut x: i32 = 42;"); |
| 752 | let case ast::NodeValue::Let(n) = r1.value |
| 753 | else throw testing::TestError::Failed; |
| 754 | |
| 755 | try expectIdent(n.ident, "x"); |
| 756 | try expectNumber(n.value, "42"); |
| 757 | try testing::expect(n.mutable); |
| 758 | |
| 759 | let type = n.type |
| 760 | else throw testing::TestError::Failed; |
| 761 | try expectType(type, ast::TypeSig::Integer { |
| 762 | width: 4, sign: ast::Signedness::Signed |
| 763 | }); |
| 764 | } |
| 765 | |
| 766 | /// Test parsing a `constant` declaration. |
| 767 | @test unsafe fn testParseConst() throws (testing::TestError) { |
| 768 | let node = try! parseStmtStr("constant ANSWER: i32 = 42;"); |
| 769 | let case ast::NodeValue::ConstDecl(decl) = node.value |
| 770 | else throw testing::TestError::Failed; |
| 771 | |
| 772 | try expectIdent(decl.ident, "ANSWER"); |
| 773 | try expectType(decl.type, ast::TypeSig::Integer { |
| 774 | width: 4, sign: ast::Signedness::Signed |
| 775 | }); |
| 776 | try expectNumber(decl.value, "42"); |
| 777 | } |
| 778 | |
| 779 | /// Test parsing a `static` declaration. |
| 780 | @test unsafe fn testParseStatic() throws (testing::TestError) { |
| 781 | let node = try! parseStmtStr("static COUNTER: i32 = 0;"); |
| 782 | let case ast::NodeValue::StaticDecl(decl) = node.value |
| 783 | else throw testing::TestError::Failed; |
| 784 | |
| 785 | try expectIdent(decl.ident, "COUNTER"); |
| 786 | try expectType(decl.type, ast::TypeSig::Integer { |
| 787 | width: 4, sign: ast::Signedness::Signed |
| 788 | }); |
| 789 | try expectNumber(decl.value, "0"); |
| 790 | } |
| 791 | |
| 792 | /// Test parsing a `use` declaration. |
| 793 | @test unsafe fn testParseUse() throws (testing::TestError) { |
| 794 | let node = try! parseStmtStr("use module::item;"); |
| 795 | let case ast::NodeValue::Use(decl) = node.value |
| 796 | else throw testing::TestError::Failed; |
| 797 | |
| 798 | let case ast::NodeValue::ScopeAccess(scope) = decl.path.value |
| 799 | else throw testing::TestError::Failed; |
| 800 | |
| 801 | try expectIdent(scope.parent, "module"); |
| 802 | try expectIdent(scope.child, "item"); |
| 803 | } |
| 804 | |
| 805 | /// Test parsing a `mod` declaration. |
| 806 | @test unsafe fn testParseMod() throws (testing::TestError) { |
| 807 | let node = try! parseStmtStr("mod io;"); |
| 808 | let case ast::NodeValue::Mod(decl) = node.value |
| 809 | else throw testing::TestError::Failed; |
| 810 | |
| 811 | try expectIdent(decl.name, "io"); |
| 812 | try testing::expect(decl.attrs == nil); |
| 813 | } |
| 814 | |
| 815 | /// Test parsing a module declaration with attributes. |
| 816 | @test unsafe fn testParseModAttributes() throws (testing::TestError) { |
| 817 | let node = try! parseStmtStr("export mod io;"); |
| 818 | let case ast::NodeValue::Mod(decl) = node.value |
| 819 | else throw testing::TestError::Failed; |
| 820 | |
| 821 | try expectIdent(decl.name, "io"); |
| 822 | let attrs = decl.attrs |
| 823 | else throw testing::TestError::Failed; |
| 824 | |
| 825 | try testing::expect(attrs.list.len == 1); |
| 826 | |
| 827 | let case ast::NodeValue::Attribute(attr) = attrs.list[0].value |
| 828 | else throw testing::TestError::Failed; |
| 829 | |
| 830 | try testing::expect(attr == ast::Attribute::Export); |
| 831 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Export)); |
| 832 | } |
| 833 | |
| 834 | /// Test parsing an optional type. |
| 835 | @test unsafe fn testParseTypeOptional() throws (testing::TestError) { |
| 836 | let node = try! parseTypeStr("?i32"); |
| 837 | let case ast::NodeValue::TypeSig(optional) = node.value |
| 838 | else throw testing::TestError::Failed; |
| 839 | let case ast::TypeSig::Optional(opt) = optional |
| 840 | else throw testing::TestError::Failed; |
| 841 | |
| 842 | try expectIntType(opt, 4, ast::Signedness::Signed); |
| 843 | } |
| 844 | |
| 845 | /// Parse an `i32` pointer type and verify its class and mutability. |
| 846 | unsafe fn expectI32Pointer( |
| 847 | source: *[u8], |
| 848 | class: ast::PointerClass, |
| 849 | mutable: bool, |
| 850 | ) throws (testing::TestError) { |
| 851 | let node = try! parseTypeStr(source); |
| 852 | let case ast::NodeValue::TypeSig(sig) = node.value |
| 853 | else throw testing::TestError::Failed; |
| 854 | let case ast::TypeSig::Pointer { |
| 855 | class: actualClass, valueType, mutable: actualMutable, |
| 856 | } = sig else throw testing::TestError::Failed; |
| 857 | |
| 858 | assert actualClass == class; |
| 859 | try expectIntType(valueType, 4, ast::Signedness::Signed); |
| 860 | assert actualMutable == mutable; |
| 861 | } |
| 862 | |
| 863 | /// Test parsing a mutable owned pointer. |
| 864 | @test unsafe fn testParseTypePointer() throws (testing::TestError) { |
| 865 | try expectI32Pointer("*mut i32", ast::PointerClass::Owned, true); |
| 866 | } |
| 867 | |
| 868 | /// Test parsing an immutable owned pointer. |
| 869 | @test unsafe fn testParseTypePointerImmutable() throws (testing::TestError) { |
| 870 | try expectI32Pointer("*i32", ast::PointerClass::Owned, false); |
| 871 | } |
| 872 | |
| 873 | /// Test parsing immutable and mutable references. |
| 874 | @test unsafe fn testParseTypeRef() throws (testing::TestError) { |
| 875 | try expectI32Pointer("&i32", ast::PointerClass::Ref, false); |
| 876 | try expectI32Pointer("&mut i32", ast::PointerClass::Ref, true); |
| 877 | } |
| 878 | |
| 879 | /// Test parsing immutable and mutable unsafe pointers. |
| 880 | @test unsafe fn testParseTypeUnsafePointer() throws (testing::TestError) { |
| 881 | try expectI32Pointer("*unsafe i32", ast::PointerClass::Unsafe, false); |
| 882 | try expectI32Pointer("*unsafe mut i32", ast::PointerClass::Unsafe, true); |
| 883 | } |
| 884 | |
| 885 | /// Test parsing a slice type. |
| 886 | @test unsafe fn testParseTypeSlice() throws (testing::TestError) { |
| 887 | let node = try! parseTypeStr("*[u8]"); |
| 888 | let case ast::NodeValue::TypeSig(sig) = node.value |
| 889 | else throw testing::TestError::Failed; |
| 890 | let case ast::TypeSig::Slice { class, itemType, mutable } = sig |
| 891 | else throw testing::TestError::Failed; |
| 892 | |
| 893 | assert class == ast::PointerClass::Owned; |
| 894 | try expectIntType(itemType, 1, ast::Signedness::Unsigned); |
| 895 | assert not mutable; |
| 896 | } |
| 897 | |
| 898 | /// Test parsing a mutable slice type. |
| 899 | @test unsafe fn testParseTypeSliceMutable() throws (testing::TestError) { |
| 900 | let node = try! parseTypeStr("*mut [u8]"); |
| 901 | let case ast::NodeValue::TypeSig(sig) = node.value |
| 902 | else throw testing::TestError::Failed; |
| 903 | let case ast::TypeSig::Slice { class, itemType, mutable } = sig |
| 904 | else throw testing::TestError::Failed; |
| 905 | |
| 906 | assert class == ast::PointerClass::Owned; |
| 907 | try expectIntType(itemType, 1, ast::Signedness::Unsigned); |
| 908 | assert mutable; |
| 909 | } |
| 910 | |
| 911 | /// Test parsing reference and unsafe slice classes. |
| 912 | @test unsafe fn testParseTypeSliceClasses() throws (testing::TestError) { |
| 913 | let refNode = try! parseTypeStr("&[u8]"); |
| 914 | let case ast::NodeValue::TypeSig(ast::TypeSig::Slice { |
| 915 | class: refClass, .. |
| 916 | }) = refNode.value else throw testing::TestError::Failed; |
| 917 | assert refClass == ast::PointerClass::Ref; |
| 918 | |
| 919 | let unsafeNode = try! parseTypeStr("*unsafe [u8]"); |
| 920 | let case ast::NodeValue::TypeSig(ast::TypeSig::Slice { |
| 921 | class: unsafeClass, .. |
| 922 | }) = unsafeNode.value else throw testing::TestError::Failed; |
| 923 | assert unsafeClass == ast::PointerClass::Unsafe; |
| 924 | } |
| 925 | |
| 926 | /// Test parsing trait object pointer classes. |
| 927 | @test unsafe fn testParseTypeTraitObjectClasses() throws (testing::TestError) { |
| 928 | let ownedNode = try! parseTypeStr("*opaque Read"); |
| 929 | let case ast::NodeValue::TypeSig(ast::TypeSig::TraitObject { |
| 930 | class: ownedClass, .. |
| 931 | }) = ownedNode.value else throw testing::TestError::Failed; |
| 932 | assert ownedClass == ast::PointerClass::Owned; |
| 933 | |
| 934 | let refNode = try! parseTypeStr("&opaque Read"); |
| 935 | let case ast::NodeValue::TypeSig(ast::TypeSig::TraitObject { |
| 936 | class: refClass, .. |
| 937 | }) = refNode.value else throw testing::TestError::Failed; |
| 938 | assert refClass == ast::PointerClass::Ref; |
| 939 | |
| 940 | let unsafeNode = try! parseTypeStr("*unsafe opaque Read"); |
| 941 | let case ast::NodeValue::TypeSig(ast::TypeSig::TraitObject { |
| 942 | class: unsafeClass, .. |
| 943 | }) = unsafeNode.value else throw testing::TestError::Failed; |
| 944 | assert unsafeClass == ast::PointerClass::Unsafe; |
| 945 | } |
| 946 | |
| 947 | /// Test parsing an array type. |
| 948 | @test unsafe fn testParseTypeArray() throws (testing::TestError) { |
| 949 | let node = try! parseTypeStr("[i32; 4]"); |
| 950 | let case ast::NodeValue::TypeSig(sig) = node.value |
| 951 | else throw testing::TestError::Failed; |
| 952 | let case ast::TypeSig::Array { itemType, length } = sig |
| 953 | else throw testing::TestError::Failed; |
| 954 | |
| 955 | try expectIntType(itemType, 4, ast::Signedness::Signed); |
| 956 | try expectNumber(length, "4"); |
| 957 | } |
| 958 | |
| 959 | /// Test parsing a named record declaration without derives. |
| 960 | /// Opaque record modifiers preserve exports, regions, and ownership markers. |
| 961 | @test unsafe fn testParseOpaqueRecord() throws (testing::TestError) { |
| 962 | for source, i in [ |
| 963 | "opaque record R { value: u32 }", |
| 964 | "export opaque record R: 'r + Copy { value: &'r u32 }", |
| 965 | "opaque record R: Copy(u32);", |
| 966 | ] { |
| 967 | let node = try! parseStmtStr(source); |
| 968 | let case ast::NodeValue::RecordDecl(decl) = node.value else throw testing::TestError::Failed; |
| 969 | let attrs = decl.attrs else throw testing::TestError::Failed; |
| 970 | assert ast::attributesContains(&attrs, ast::Attribute::Opaque); |
| 971 | assert ast::attributesContains(&attrs, ast::Attribute::Export) == (i == 1); |
| 972 | assert decl.labeled == (i <> 2); |
| 973 | assert decl.fields.len == 1; |
| 974 | assert decl.regions.len == (1 if i == 1 else 0); |
| 975 | assert decl.derives.len == (0 if i == 0 else 1); |
| 976 | static PRINT_STORAGE: [u8; 4096] = [0; 4096]; |
| 977 | let mut printArena = alloc::new(&mut PRINT_STORAGE[..]); |
| 978 | let printed = printer::toExpr(&mut printArena, node); |
| 979 | let case sexpr::Expr::Block { name, .. } = printed else throw testing::TestError::Failed; |
| 980 | assert name == "opaque-record"; |
| 981 | } |
| 982 | for source in [ |
| 983 | "opaque fn f() {}", |
| 984 | "opaque union R { Value }", |
| 985 | "opaque opaque record R {}", |
| 986 | "opaque export record R {}", |
| 987 | ] { |
| 988 | let parsed = try? parseStmtStr(source); |
| 989 | assert parsed == nil; |
| 990 | } |
| 991 | } |
| 992 | |
| 993 | @test unsafe fn testParseRecordDecl() throws (testing::TestError) { |
| 994 | let node = try! parseStmtStr("record R { x: bool, y: i32 }"); |
| 995 | let case ast::NodeValue::RecordDecl(decl) = node.value |
| 996 | else throw testing::TestError::Failed; |
| 997 | |
| 998 | try expectIdent(decl.name, "R"); |
| 999 | try testing::expect(decl.derives.len == 0); |
| 1000 | try testing::expect(decl.fields.len == 2); |
| 1001 | |
| 1002 | try expectFieldSig(decl.fields, 0, "x", ast::TypeSig::Bool); |
| 1003 | try expectFieldSig(decl.fields, 1, "y", ast::TypeSig::Integer { |
| 1004 | width: 4, |
| 1005 | sign: ast::Signedness::Signed, |
| 1006 | }); |
| 1007 | } |
| 1008 | |
| 1009 | /// Test parsing a record declaration with derives. |
| 1010 | @test unsafe fn testParseRecordDeclDerives() throws (testing::TestError) { |
| 1011 | let node = try! parseStmtStr("record R: Eq + Debug { field: i32 }"); |
| 1012 | let case ast::NodeValue::RecordDecl(decl) = node.value |
| 1013 | else throw testing::TestError::Failed; |
| 1014 | |
| 1015 | try expectIdent(decl.name, "R"); |
| 1016 | try testing::expect(decl.derives.len == 2); |
| 1017 | try expectIdent(decl.derives[0], "Eq"); |
| 1018 | try expectIdent(decl.derives[1], "Debug"); |
| 1019 | } |
| 1020 | |
| 1021 | /// Test parsing a record declaration with field initializers. |
| 1022 | @test unsafe fn testParseRecordDeclFieldDefaults() throws (testing::TestError) { |
| 1023 | let node = try! parseStmtStr("record Config { size: opaque = 42, flag: bool = true }"); |
| 1024 | let case ast::NodeValue::RecordDecl(decl) = node.value |
| 1025 | else throw testing::TestError::Failed; |
| 1026 | |
| 1027 | try expectIdent(decl.name, "Config"); |
| 1028 | try testing::expect(decl.derives.len == 0); |
| 1029 | try testing::expect(decl.fields.len == 2); |
| 1030 | |
| 1031 | try expectFieldSig(decl.fields, 0, "size", ast::TypeSig::Opaque); |
| 1032 | try expectFieldSig(decl.fields, 1, "flag", ast::TypeSig::Bool); |
| 1033 | |
| 1034 | // Check default values. |
| 1035 | let case ast::NodeValue::RecordField { value: val0, .. } = decl.fields[0].value |
| 1036 | else throw testing::TestError::Failed; |
| 1037 | let v0 = val0 else throw testing::TestError::Failed; |
| 1038 | try expectNumber(v0, "42"); |
| 1039 | |
| 1040 | let case ast::NodeValue::RecordField { value: val1, .. } = decl.fields[1].value |
| 1041 | else throw testing::TestError::Failed; |
| 1042 | let v1 = val1 else throw testing::TestError::Failed; |
| 1043 | let case ast::NodeValue::Bool(flagValue) = v1.value |
| 1044 | else throw testing::TestError::Failed; |
| 1045 | try testing::expect(flagValue); |
| 1046 | } |
| 1047 | |
| 1048 | /// Test parsing an unlabeled record declaration. |
| 1049 | @test unsafe fn testParseTupleRecordDecl() throws (testing::TestError) { |
| 1050 | let node = try! parseStmtStr("record Pair(bool, i32);"); |
| 1051 | let case ast::NodeValue::RecordDecl(decl) = node.value |
| 1052 | else throw testing::TestError::Failed; |
| 1053 | |
| 1054 | try expectIdent(decl.name, "Pair"); |
| 1055 | try testing::expect(not decl.labeled); |
| 1056 | try testing::expect(decl.derives.len == 0); |
| 1057 | try testing::expect(decl.fields.len == 2); |
| 1058 | |
| 1059 | try expectFieldSig(decl.fields, 0, nil, ast::TypeSig::Bool); |
| 1060 | try expectFieldSig(decl.fields, 1, nil, ast::TypeSig::Integer { |
| 1061 | width: 4, |
| 1062 | sign: ast::Signedness::Signed, |
| 1063 | }); |
| 1064 | } |
| 1065 | |
| 1066 | /// Test parsing a single-field unlabeled record. |
| 1067 | @test unsafe fn testParseTupleRecordSingleField() throws (testing::TestError) { |
| 1068 | let node = try! parseStmtStr("record R(bool);"); |
| 1069 | let case ast::NodeValue::RecordDecl(decl) = node.value |
| 1070 | else throw testing::TestError::Failed; |
| 1071 | |
| 1072 | try expectIdent(decl.name, "R"); |
| 1073 | try testing::expect(not decl.labeled); |
| 1074 | try testing::expect(decl.fields.len == 1); |
| 1075 | |
| 1076 | try expectFieldSig(decl.fields, 0, nil, ast::TypeSig::Bool); |
| 1077 | } |
| 1078 | |
| 1079 | /// Test parsing empty record literals. |
| 1080 | @test unsafe fn testParseEmptyRecordLiteral() throws (testing::TestError) { |
| 1081 | let r1 = try! parseExprStr("{}"); |
| 1082 | let case ast::NodeValue::RecordLit(lit) = r1.value |
| 1083 | else throw testing::TestError::Failed; |
| 1084 | |
| 1085 | try testing::expect(lit.typeName == nil); |
| 1086 | try testing::expect(lit.fields.len == 0); |
| 1087 | |
| 1088 | let r2 = try! parseExprStr("Point {}"); |
| 1089 | let case ast::NodeValue::RecordLit(lit2) = r2.value |
| 1090 | else throw testing::TestError::Failed; |
| 1091 | |
| 1092 | let typeName = lit2.typeName else throw testing::TestError::Failed; |
| 1093 | try expectIdent(typeName, "Point"); |
| 1094 | try testing::expect(lit2.fields.len == 0); |
| 1095 | } |
| 1096 | |
| 1097 | /// Test parsing a function type with parameters and return type. |
| 1098 | @test unsafe fn testParseTypeFn() throws (testing::TestError) { |
| 1099 | let node = try! parseTypeStr("fn (i32, *u8) -> bool"); |
| 1100 | let case ast::NodeValue::TypeSig(sigValue) = node.value |
| 1101 | else throw testing::TestError::Failed; |
| 1102 | let case ast::TypeSig::Fn { sig, .. } = sigValue |
| 1103 | else throw testing::TestError::Failed; |
| 1104 | |
| 1105 | try testing::expect(sig.params.len == 2); |
| 1106 | |
| 1107 | let param0 = sig.params[0]; |
| 1108 | try expectIntType(param0, 4, ast::Signedness::Signed); |
| 1109 | |
| 1110 | let param1 = sig.params[1]; |
| 1111 | let case ast::NodeValue::TypeSig(p1) = param1.value |
| 1112 | else throw testing::TestError::Failed; |
| 1113 | let case ast::TypeSig::Pointer { valueType: ptrTarget, .. } = p1 |
| 1114 | else throw testing::TestError::Failed; |
| 1115 | try expectIntType(ptrTarget, 1, ast::Signedness::Unsigned); |
| 1116 | |
| 1117 | try testing::expect(sig.returnType <> nil); |
| 1118 | } |
| 1119 | |
| 1120 | /// Test parsing a function type with a throws clause. |
| 1121 | @test unsafe fn testParseTypeFnThrows() throws (testing::TestError) { |
| 1122 | let node = try! parseTypeStr("fn (i32) -> bool throws (Error, Other)"); |
| 1123 | let case ast::NodeValue::TypeSig(sigValue) = node.value |
| 1124 | else throw testing::TestError::Failed; |
| 1125 | let case ast::TypeSig::Fn { sig, .. } = sigValue |
| 1126 | else throw testing::TestError::Failed; |
| 1127 | |
| 1128 | try testing::expect(sig.params.len == 1); |
| 1129 | try expectIntType(sig.params[0], 4, ast::Signedness::Signed); |
| 1130 | |
| 1131 | try testing::expect(sig.throwList.len == 2); |
| 1132 | try expectTypeIdent(sig.throwList[0], "Error"); |
| 1133 | try expectTypeIdent(sig.throwList[1], "Other"); |
| 1134 | |
| 1135 | let returnType = sig.returnType |
| 1136 | else throw testing::TestError::Failed; |
| 1137 | try expectType(returnType, ast::TypeSig::Bool); |
| 1138 | } |
| 1139 | |
| 1140 | /// Test parsing a function declaration without parameters. |
| 1141 | @test unsafe fn testParseFnDeclEmpty() throws (testing::TestError) { |
| 1142 | let node = try! parseStmtStr("fn main() {}"); |
| 1143 | let case ast::NodeValue::FnDecl(decl) = node.value |
| 1144 | else throw testing::TestError::Failed; |
| 1145 | |
| 1146 | try expectIdent(decl.name, "main"); |
| 1147 | try testing::expect(decl.sig.params.len == 0); |
| 1148 | try testing::expect(decl.sig.returnType == nil); |
| 1149 | try testing::expect(decl.attrs == nil); |
| 1150 | |
| 1151 | let body = decl.body else throw testing::TestError::Failed; |
| 1152 | let case ast::NodeValue::Block(_) = body.value |
| 1153 | else throw testing::TestError::Failed; |
| 1154 | } |
| 1155 | |
| 1156 | /// Test parsing a function declaration with parameters and return type. |
| 1157 | @test unsafe fn testParseFnDeclParams() throws (testing::TestError) { |
| 1158 | let node = try! parseStmtStr("fn add(x: i32, y: *u8) -> bool {}"); |
| 1159 | let case ast::NodeValue::FnDecl(decl) = node.value |
| 1160 | else throw testing::TestError::Failed; |
| 1161 | |
| 1162 | try expectIdent(decl.name, "add"); |
| 1163 | try testing::expect(decl.sig.params.len == 2); |
| 1164 | |
| 1165 | { |
| 1166 | let param0 = decl.sig.params[0]; |
| 1167 | let case ast::NodeValue::FnParam(p0) = param0.value |
| 1168 | else throw testing::TestError::Failed; |
| 1169 | try expectIdent(p0.name, "x"); |
| 1170 | try expectIntType(p0.type, 4, ast::Signedness::Signed); |
| 1171 | } |
| 1172 | { |
| 1173 | let param1 = decl.sig.params[1]; |
| 1174 | let case ast::NodeValue::FnParam(p1) = param1.value |
| 1175 | else throw testing::TestError::Failed; |
| 1176 | try expectIdent(p1.name, "y"); |
| 1177 | let case ast::NodeValue::TypeSig(sig1) = p1.type.value |
| 1178 | else throw testing::TestError::Failed; |
| 1179 | let case ast::TypeSig::Pointer { valueType, .. } = sig1 |
| 1180 | else throw testing::TestError::Failed; |
| 1181 | try expectIntType(valueType, 1, ast::Signedness::Unsigned); |
| 1182 | } |
| 1183 | { |
| 1184 | let returnType = decl.sig.returnType |
| 1185 | else throw testing::TestError::Failed; |
| 1186 | try expectType(returnType, ast::TypeSig::Bool); |
| 1187 | |
| 1188 | let body = decl.body else throw testing::TestError::Failed; |
| 1189 | let case ast::NodeValue::Block(_) = body.value |
| 1190 | else throw testing::TestError::Failed; |
| 1191 | } |
| 1192 | } |
| 1193 | |
| 1194 | /// Test parsing a function declaration with a throws clause. |
| 1195 | @test unsafe fn testParseFnDeclThrows() throws (testing::TestError) { |
| 1196 | let node = try! parseStmtStr("fn handle() throws (Error, Crash) {}"); |
| 1197 | let case ast::NodeValue::FnDecl(decl) = node.value |
| 1198 | else throw testing::TestError::Failed; |
| 1199 | |
| 1200 | try expectIdent(decl.name, "handle"); |
| 1201 | try testing::expect(decl.sig.returnType == nil); |
| 1202 | |
| 1203 | try testing::expect(decl.sig.throwList.len == 2); |
| 1204 | try expectTypeIdent(decl.sig.throwList[0], "Error"); |
| 1205 | try expectTypeIdent(decl.sig.throwList[1], "Crash"); |
| 1206 | |
| 1207 | let body = decl.body else throw testing::TestError::Failed; |
| 1208 | let case ast::NodeValue::Block(_) = body.value |
| 1209 | else throw testing::TestError::Failed; |
| 1210 | } |
| 1211 | |
| 1212 | /// Test scanning source-level `void` produces an identifier, not a type keyword. |
| 1213 | @test unsafe fn testParseTypeVoidRejected() throws (testing::TestError) { |
| 1214 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 1215 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 1216 | let mut parser = super::mkParser(scanner::SourceLoc::String, "void", arenaRef, poolRef); |
| 1217 | super::advance(&mut parser); |
| 1218 | try testing::expect(super::check(&parser, scanner::TokenKind::Ident)); |
| 1219 | } |
| 1220 | } |
| 1221 | |
| 1222 | /// Test parsing the unsafe function modifier. |
| 1223 | @test unsafe fn testParseUnsafeFnDecl() throws (testing::TestError) { |
| 1224 | let node = try! parseStmtStr("unsafe fn run() {}"); |
| 1225 | let case ast::NodeValue::FnDecl(decl) = node.value |
| 1226 | else throw testing::TestError::Failed; |
| 1227 | let attrs = decl.attrs |
| 1228 | else throw testing::TestError::Failed; |
| 1229 | |
| 1230 | try testing::expect(attrs.list.len == 1); |
| 1231 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Unsafe)); |
| 1232 | } |
| 1233 | |
| 1234 | /// Test rejecting `unsafe` on declarations where it has no semantics. |
| 1235 | @test unsafe fn testParseUnsafeUnsupportedDecl() throws (testing::TestError) { |
| 1236 | let recordDecl: ?*ast::Node = try? parseStmtStr("unsafe record R {}"); |
| 1237 | try testing::expect(recordDecl == nil); |
| 1238 | let constDecl: ?*ast::Node = try? parseStmtStr("unsafe constant X = 1;"); |
| 1239 | try testing::expect(constDecl == nil); |
| 1240 | } |
| 1241 | |
| 1242 | /// Test unsafe method declarations. |
| 1243 | @test unsafe fn testParseUnsafeMethods() throws (testing::TestError) { |
| 1244 | let instanceNode = try! parseStmtStr( |
| 1245 | "instance Read for Value { unsafe fn (value: &Value) get() {} }" |
| 1246 | ); |
| 1247 | let case ast::NodeValue::InstanceDecl { methods, .. } = instanceNode.value |
| 1248 | else throw testing::TestError::Failed; |
| 1249 | try testing::expect(methods.len == 1); |
| 1250 | let case ast::NodeValue::MethodDecl { modifiers, .. } = methods[0].value |
| 1251 | else throw testing::TestError::Failed; |
| 1252 | let attrs = modifiers.attrs; |
| 1253 | let methodAttrs = attrs else throw testing::TestError::Failed; |
| 1254 | assert ast::attributesContains(&methodAttrs, ast::Attribute::Unsafe); |
| 1255 | |
| 1256 | static printStorage: [u8; 4096] = undefined; |
| 1257 | let mut printArena = alloc::new(&mut printStorage[..]); |
| 1258 | let methodExpr = printer::toExpr(&mut printArena, methods[0]); |
| 1259 | let case sexpr::Expr::Block { items: methodItems, .. } = methodExpr |
| 1260 | else throw testing::TestError::Failed; |
| 1261 | let case sexpr::Expr::List { |
| 1262 | head: methodAttrsHead, tail: printedMethodAttrs, .. |
| 1263 | } = methodItems[0] else throw testing::TestError::Failed; |
| 1264 | assert mem::eq(methodAttrsHead, "attrs"); |
| 1265 | let case sexpr::Expr::Sym(methodAttr) = printedMethodAttrs[0] |
| 1266 | else throw testing::TestError::Failed; |
| 1267 | assert mem::eq(methodAttr, "@unsafe"); |
| 1268 | |
| 1269 | let traitNode = try! parseStmtStr( |
| 1270 | "trait Read { unsafe fn (&Read) get(); }" |
| 1271 | ); |
| 1272 | let case ast::NodeValue::TraitDecl { methods: traitMethods, .. } = traitNode.value |
| 1273 | else throw testing::TestError::Failed; |
| 1274 | let case ast::NodeValue::TraitMethodSig { |
| 1275 | modifiers: traitModifiers, .. |
| 1276 | } = traitMethods[0].value else throw testing::TestError::Failed; |
| 1277 | let traitAttrs = traitModifiers.attrs; |
| 1278 | let traitMethodAttrs = traitAttrs else throw testing::TestError::Failed; |
| 1279 | assert ast::attributesContains(&traitMethodAttrs, ast::Attribute::Unsafe); |
| 1280 | |
| 1281 | let traitMethodExpr = printer::toExpr(&mut printArena, traitMethods[0]); |
| 1282 | let case sexpr::Expr::List { tail: traitMethodItems, .. } = traitMethodExpr |
| 1283 | else throw testing::TestError::Failed; |
| 1284 | let case sexpr::Expr::List { |
| 1285 | head: traitAttrsHead, tail: printedTraitAttrs, .. |
| 1286 | } = traitMethodItems[0] else throw testing::TestError::Failed; |
| 1287 | assert mem::eq(traitAttrsHead, "attrs"); |
| 1288 | let case sexpr::Expr::Sym(traitAttr) = printedTraitAttrs[0] |
| 1289 | else throw testing::TestError::Failed; |
| 1290 | assert mem::eq(traitAttr, "@unsafe"); |
| 1291 | } |
| 1292 | |
| 1293 | /// Test region parameters on methods, trait methods, and instances. |
| 1294 | @test unsafe fn testParseRegionalMethods() throws (testing::TestError) { |
| 1295 | let instanceNode = try! parseStmtStr( |
| 1296 | "instance Read for View 'view { fn (view: &View 'view) get 'method () -> &'method u32 { panic; } }" |
| 1297 | ); |
| 1298 | let case ast::NodeValue::InstanceDecl { regions, methods, .. } = instanceNode.value |
| 1299 | else throw testing::TestError::Failed; |
| 1300 | try testing::expect(regions.len == 1 and methods.len == 1); |
| 1301 | let case ast::NodeValue::MethodDecl { modifiers, .. } = methods[0].value |
| 1302 | else throw testing::TestError::Failed; |
| 1303 | try testing::expect(modifiers.regions.len == 1); |
| 1304 | |
| 1305 | let traitNode = try! parseStmtStr( |
| 1306 | "trait Read { fn (&Read) get 'method () -> &'method u32; }" |
| 1307 | ); |
| 1308 | let case ast::NodeValue::TraitDecl { methods: traitMethods, .. } = traitNode.value |
| 1309 | else throw testing::TestError::Failed; |
| 1310 | let case ast::NodeValue::TraitMethodSig { modifiers: traitModifiers, .. } = traitMethods[0].value |
| 1311 | else throw testing::TestError::Failed; |
| 1312 | try testing::expect(traitModifiers.regions.len == 1); |
| 1313 | } |
| 1314 | |
| 1315 | /// Test parsing a function declaration with attributes. |
| 1316 | @test unsafe fn testParseFnDeclAttributes() throws (testing::TestError) { |
| 1317 | let node = try! parseStmtStr("export fn run();"); |
| 1318 | let case ast::NodeValue::FnDecl(decl) = node.value |
| 1319 | else throw testing::TestError::Failed; |
| 1320 | |
| 1321 | try expectIdent(decl.name, "run"); |
| 1322 | |
| 1323 | let attrs = decl.attrs |
| 1324 | else throw testing::TestError::Failed; |
| 1325 | |
| 1326 | try testing::expect(attrs.list.len == 2); |
| 1327 | |
| 1328 | let case ast::NodeValue::Attribute(attr0) = attrs.list[0].value |
| 1329 | else throw testing::TestError::Failed; |
| 1330 | try testing::expect(attr0 == ast::Attribute::Export); |
| 1331 | |
| 1332 | let case ast::NodeValue::Attribute(attr1) = attrs.list[1].value |
| 1333 | else throw testing::TestError::Failed; |
| 1334 | try testing::expect(attr1 == ast::Attribute::Extern); |
| 1335 | |
| 1336 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Export)); |
| 1337 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Extern)); |
| 1338 | try testing::expect(decl.body == nil); |
| 1339 | } |
| 1340 | |
| 1341 | /// Test parsing a top-level function declaration with inferred extern from `;`. |
| 1342 | @test unsafe fn testParseFnDeclInferredExtern() throws (testing::TestError) { |
| 1343 | let node = try! parseStmtStr("fn run();"); |
| 1344 | let case ast::NodeValue::FnDecl(decl) = node.value |
| 1345 | else throw testing::TestError::Failed; |
| 1346 | |
| 1347 | try expectIdent(decl.name, "run"); |
| 1348 | |
| 1349 | let attrs = decl.attrs |
| 1350 | else throw testing::TestError::Failed; |
| 1351 | |
| 1352 | try testing::expect(attrs.list.len == 1); |
| 1353 | |
| 1354 | let case ast::NodeValue::Attribute(attr0) = attrs.list[0].value |
| 1355 | else throw testing::TestError::Failed; |
| 1356 | try testing::expect(attr0 == ast::Attribute::Extern); |
| 1357 | |
| 1358 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Extern)); |
| 1359 | try testing::expect(decl.body == nil); |
| 1360 | } |
| 1361 | |
| 1362 | /// Test parsing a top-level exported function declaration with inferred extern from `;`. |
| 1363 | @test unsafe fn testParseFnDeclExportInferredExtern() throws (testing::TestError) { |
| 1364 | let node = try! parseStmtStr("export fn run();"); |
| 1365 | let case ast::NodeValue::FnDecl(decl) = node.value |
| 1366 | else throw testing::TestError::Failed; |
| 1367 | |
| 1368 | try expectIdent(decl.name, "run"); |
| 1369 | |
| 1370 | let attrs = decl.attrs |
| 1371 | else throw testing::TestError::Failed; |
| 1372 | |
| 1373 | try testing::expect(attrs.list.len == 2); |
| 1374 | |
| 1375 | let case ast::NodeValue::Attribute(attr0) = attrs.list[0].value |
| 1376 | else throw testing::TestError::Failed; |
| 1377 | try testing::expect(attr0 == ast::Attribute::Export); |
| 1378 | |
| 1379 | let case ast::NodeValue::Attribute(attr1) = attrs.list[1].value |
| 1380 | else throw testing::TestError::Failed; |
| 1381 | try testing::expect(attr1 == ast::Attribute::Extern); |
| 1382 | |
| 1383 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Export)); |
| 1384 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Extern)); |
| 1385 | try testing::expect(decl.body == nil); |
| 1386 | } |
| 1387 | |
| 1388 | /// Test parsing a scoped identifier type. |
| 1389 | @test unsafe fn testParseTypeScopedIdent() throws (testing::TestError) { |
| 1390 | let node = try! parseTypeStr("module::Type"); |
| 1391 | let case ast::NodeValue::TypeSig(ts) = node.value |
| 1392 | else throw testing::TestError::Failed; |
| 1393 | let case ast::TypeSig::Nominal(name) = ts |
| 1394 | else throw testing::TestError::Failed; |
| 1395 | let case ast::NodeValue::ScopeAccess(access) = name.value |
| 1396 | else throw testing::TestError::Failed; |
| 1397 | |
| 1398 | try expectIdent(access.parent, "module"); |
| 1399 | try expectIdent(access.child, "Type"); |
| 1400 | } |
| 1401 | |
| 1402 | /// Test parsing the `bool` type. |
| 1403 | @test unsafe fn testParseTypeBool() throws (testing::TestError) { |
| 1404 | let node = try! parseTypeStr("bool"); |
| 1405 | try expectType(node, ast::TypeSig::Bool); |
| 1406 | } |
| 1407 | |
| 1408 | /// Test parsing an unsigned integer type. |
| 1409 | @test unsafe fn testParseTypeUnsigned() throws (testing::TestError) { |
| 1410 | let node = try! parseTypeStr("u8"); |
| 1411 | try expectType(node, ast::TypeSig::Integer { |
| 1412 | width: 1, |
| 1413 | sign: ast::Signedness::Unsigned, |
| 1414 | }); |
| 1415 | } |
| 1416 | |
| 1417 | /// Test parsing a simple `if let` statement without guard or else. |
| 1418 | @test unsafe fn testParseIfLet() throws (testing::TestError) { |
| 1419 | let root = try! parseStmtStr("if let value = opt { body; }"); |
| 1420 | let case ast::NodeValue::IfLet(node) = root.value |
| 1421 | else throw testing::TestError::Failed; |
| 1422 | |
| 1423 | try expectIdent(node.pattern.pattern, "value"); |
| 1424 | try expectIdent(node.pattern.scrutinee, "opt"); |
| 1425 | |
| 1426 | try testing::expect(node.pattern.guard == nil); |
| 1427 | try expectBlockExprStmt(node.thenBranch, ast::NodeValue::Ident("body")); |
| 1428 | try testing::expect(node.elseBranch == nil); |
| 1429 | } |
| 1430 | |
| 1431 | /// Test parsing an `if let` statement with guard and else branches. |
| 1432 | @test unsafe fn testParseIfLetGuardElse() throws (testing::TestError) { |
| 1433 | let root = try! parseStmtStr( |
| 1434 | "if let value = opt; guard { body; } else { alt; }" |
| 1435 | ); |
| 1436 | let case ast::NodeValue::IfLet(node) = root.value |
| 1437 | else throw testing::TestError::Failed; |
| 1438 | |
| 1439 | try expectIdent(node.pattern.pattern, "value"); |
| 1440 | try expectIdent(node.pattern.scrutinee, "opt"); |
| 1441 | |
| 1442 | let guard = node.pattern.guard |
| 1443 | else throw testing::TestError::Failed; |
| 1444 | try expectIdent(guard, "guard"); |
| 1445 | |
| 1446 | try expectBlockExprStmt(node.thenBranch, ast::NodeValue::Ident("body")); |
| 1447 | |
| 1448 | let elseBranch = node.elseBranch |
| 1449 | else throw testing::TestError::Failed; |
| 1450 | try expectBlockExprStmt(elseBranch, ast::NodeValue::Ident("alt")); |
| 1451 | } |
| 1452 | |
| 1453 | /// Test parsing an `if let` statement with an `else if` chain. |
| 1454 | @test unsafe fn testParseIfLetElseIf() throws (testing::TestError) { |
| 1455 | let root = try! parseStmtStr( |
| 1456 | "if let value = opt { body; } else if cond { alt; }" |
| 1457 | ); |
| 1458 | let case ast::NodeValue::IfLet(node) = root.value |
| 1459 | else throw testing::TestError::Failed; |
| 1460 | |
| 1461 | try expectIdent(node.pattern.pattern, "value"); |
| 1462 | |
| 1463 | let elseBranch = node.elseBranch |
| 1464 | else throw testing::TestError::Failed; |
| 1465 | |
| 1466 | let nested = try getBlockFirstStmt(elseBranch); |
| 1467 | let case ast::NodeValue::If(inner) = nested.value |
| 1468 | else throw testing::TestError::Failed; |
| 1469 | |
| 1470 | try expectIdent(inner.condition, "cond"); |
| 1471 | try expectBlockExprStmt(inner.thenBranch, ast::NodeValue::Ident("alt")); |
| 1472 | try testing::expect(inner.elseBranch == nil); |
| 1473 | } |
| 1474 | |
| 1475 | /// Test parsing `if let mut` binding. |
| 1476 | @test unsafe fn testParseIfLetMut() throws (testing::TestError) { |
| 1477 | let root = try! parseStmtStr("if let mut value = opt { body; }"); |
| 1478 | let case ast::NodeValue::IfLet(node) = root.value |
| 1479 | else throw testing::TestError::Failed; |
| 1480 | |
| 1481 | try expectIdent(node.pattern.pattern, "value"); |
| 1482 | try expectIdent(node.pattern.scrutinee, "opt"); |
| 1483 | try testing::expect(node.pattern.mutable); |
| 1484 | try testing::expect(node.pattern.guard == nil); |
| 1485 | try expectBlockExprStmt(node.thenBranch, ast::NodeValue::Ident("body")); |
| 1486 | try testing::expect(node.elseBranch == nil); |
| 1487 | } |
| 1488 | |
| 1489 | /// Test parsing `let mut ... else` binding. |
| 1490 | @test unsafe fn testParseLetMutElse() throws (testing::TestError) { |
| 1491 | let root = try! parseStmtStr("let mut x = opt else { return };"); |
| 1492 | let case ast::NodeValue::LetElse(letElse) = root.value |
| 1493 | else throw testing::TestError::Failed; |
| 1494 | |
| 1495 | try expectIdent(letElse.pattern.pattern, "x"); |
| 1496 | try testing::expect(letElse.pattern.mutable); |
| 1497 | } |
| 1498 | |
| 1499 | /// Test that `if let` without `mut` is not mutable. |
| 1500 | @test unsafe fn testParseIfLetNotMutable() throws (testing::TestError) { |
| 1501 | let root = try! parseStmtStr("if let value = opt { body; }"); |
| 1502 | let case ast::NodeValue::IfLet(node) = root.value |
| 1503 | else throw testing::TestError::Failed; |
| 1504 | |
| 1505 | try testing::expect(not node.pattern.mutable); |
| 1506 | } |
| 1507 | |
| 1508 | /// Test that `let ... else` without `mut` is not mutable. |
| 1509 | @test unsafe fn testParseLetElseNotMutable() throws (testing::TestError) { |
| 1510 | let root = try! parseStmtStr("let x = opt else { return };"); |
| 1511 | let case ast::NodeValue::LetElse(letElse) = root.value |
| 1512 | else throw testing::TestError::Failed; |
| 1513 | |
| 1514 | try testing::expect(not letElse.pattern.mutable); |
| 1515 | } |
| 1516 | |
| 1517 | /// Test parsing a simple `if let case` statement. |
| 1518 | @test unsafe fn testParseIfCase() throws (testing::TestError) { |
| 1519 | let root = try! parseStmtStr("if let case pat = value { body; }"); |
| 1520 | let case ast::NodeValue::IfLet(node) = root.value |
| 1521 | else throw testing::TestError::Failed; |
| 1522 | |
| 1523 | try expectIdent(node.pattern.pattern, "pat"); |
| 1524 | try expectIdent(node.pattern.scrutinee, "value"); |
| 1525 | try testing::expect(node.pattern.guard == nil); |
| 1526 | try expectBlockExprStmt(node.thenBranch, ast::NodeValue::Ident("body")); |
| 1527 | try testing::expect(node.elseBranch == nil); |
| 1528 | } |
| 1529 | |
| 1530 | /// Test parsing an `if let case` statement with guard and else branches. |
| 1531 | @test unsafe fn testParseIfCaseGuardElse() throws (testing::TestError) { |
| 1532 | let root = try! parseStmtStr( |
| 1533 | "if let case pat = value; guard { body; } else { alt; }" |
| 1534 | ); |
| 1535 | let case ast::NodeValue::IfLet(node) = root.value |
| 1536 | else throw testing::TestError::Failed; |
| 1537 | |
| 1538 | try expectIdent(node.pattern.pattern, "pat"); |
| 1539 | try expectIdent(node.pattern.scrutinee, "value"); |
| 1540 | |
| 1541 | let guard = node.pattern.guard |
| 1542 | else throw testing::TestError::Failed; |
| 1543 | try expectIdent(guard, "guard"); |
| 1544 | |
| 1545 | try expectBlockExprStmt(node.thenBranch, ast::NodeValue::Ident("body")); |
| 1546 | |
| 1547 | let elseBranch = node.elseBranch |
| 1548 | else throw testing::TestError::Failed; |
| 1549 | try expectBlockExprStmt(elseBranch, ast::NodeValue::Ident("alt")); |
| 1550 | } |
| 1551 | |
| 1552 | /// Test parsing an `if let case` statement with an `else if` chain. |
| 1553 | @test unsafe fn testParseIfCaseElseIf() throws (testing::TestError) { |
| 1554 | let root = try! parseStmtStr( |
| 1555 | "if let case pat = value { body; } else if cond { alt; }" |
| 1556 | ); |
| 1557 | let case ast::NodeValue::IfLet(node) = root.value |
| 1558 | else throw testing::TestError::Failed; |
| 1559 | |
| 1560 | let elseBranch = node.elseBranch |
| 1561 | else throw testing::TestError::Failed; |
| 1562 | |
| 1563 | let nested = try getBlockFirstStmt(elseBranch); |
| 1564 | let case ast::NodeValue::If(inner) = nested.value |
| 1565 | else throw testing::TestError::Failed; |
| 1566 | |
| 1567 | try expectIdent(inner.condition, "cond"); |
| 1568 | try expectBlockExprStmt(inner.thenBranch, ast::NodeValue::Ident("alt")); |
| 1569 | try testing::expect(inner.elseBranch == nil); |
| 1570 | } |
| 1571 | |
| 1572 | /// Test parsing a simple `while` loop without an `else` branch. |
| 1573 | @test unsafe fn testParseWhile() throws (testing::TestError) { |
| 1574 | let root = try! parseStmtStr("while cond { body; }"); |
| 1575 | let case ast::NodeValue::While(loopNode) = root.value |
| 1576 | else throw testing::TestError::Failed; |
| 1577 | |
| 1578 | try expectIdent(loopNode.condition, "cond"); |
| 1579 | try expectBlockExprStmt(loopNode.body, ast::NodeValue::Ident("body")); |
| 1580 | try testing::expect(loopNode.elseBranch == nil); |
| 1581 | } |
| 1582 | |
| 1583 | /// Test parsing a `while` loop with an `else` branch. |
| 1584 | @test unsafe fn testParseWhileElse() throws (testing::TestError) { |
| 1585 | let root = try! parseStmtStr("while cond { body; } else { alt; }"); |
| 1586 | let case ast::NodeValue::While(loopNode) = root.value |
| 1587 | else throw testing::TestError::Failed; |
| 1588 | |
| 1589 | try expectIdent(loopNode.condition, "cond"); |
| 1590 | try expectBlockExprStmt(loopNode.body, ast::NodeValue::Ident("body")); |
| 1591 | |
| 1592 | let elseBranch = loopNode.elseBranch |
| 1593 | else throw testing::TestError::Failed; |
| 1594 | try expectBlockExprStmt(elseBranch, ast::NodeValue::Ident("alt")); |
| 1595 | } |
| 1596 | |
| 1597 | /// Test parsing a simple `while let case` loop. |
| 1598 | @test unsafe fn testParseWhileCase() throws (testing::TestError) { |
| 1599 | let root = try! parseStmtStr("while let case pat = value { body; }"); |
| 1600 | let case ast::NodeValue::WhileLet(node) = root.value |
| 1601 | else throw testing::TestError::Failed; |
| 1602 | |
| 1603 | try expectIdent(node.pattern.pattern, "pat"); |
| 1604 | try expectIdent(node.pattern.scrutinee, "value"); |
| 1605 | try testing::expect(node.pattern.guard == nil); |
| 1606 | try expectBlockExprStmt(node.body, ast::NodeValue::Ident("body")); |
| 1607 | try testing::expect(node.elseBranch == nil); |
| 1608 | } |
| 1609 | |
| 1610 | /// Test parsing a `while let case` loop with guard and else branches. |
| 1611 | @test unsafe fn testParseWhileCaseGuardElse() throws (testing::TestError) { |
| 1612 | let root = try! parseStmtStr( |
| 1613 | "while let case pat = value; guard { body; } else { alt; }" |
| 1614 | ); |
| 1615 | let case ast::NodeValue::WhileLet(node) = root.value |
| 1616 | else throw testing::TestError::Failed; |
| 1617 | |
| 1618 | let guard = node.pattern.guard |
| 1619 | else throw testing::TestError::Failed; |
| 1620 | try expectIdent(guard, "guard"); |
| 1621 | |
| 1622 | try expectBlockExprStmt(node.body, ast::NodeValue::Ident("body")); |
| 1623 | |
| 1624 | let elseBranch = node.elseBranch |
| 1625 | else throw testing::TestError::Failed; |
| 1626 | try expectBlockExprStmt(elseBranch, ast::NodeValue::Ident("alt")); |
| 1627 | } |
| 1628 | |
| 1629 | /// Test parsing a simple `try` expression without catch. |
| 1630 | @test unsafe fn testParseTry() throws (testing::TestError) { |
| 1631 | let root = try! parseExprStr("try value"); |
| 1632 | let case ast::NodeValue::Try(node) = root.value |
| 1633 | else throw testing::TestError::Failed; |
| 1634 | |
| 1635 | try expectIdent(node.expr, "value"); |
| 1636 | try testing::expect(node.catches.len == 0); |
| 1637 | try testing::expect(not node.shouldPanic); |
| 1638 | } |
| 1639 | |
| 1640 | /// Test that `try?` consumes a unary operand. |
| 1641 | @test unsafe fn testParseTryOptionalUnary() throws (testing::TestError) { |
| 1642 | let root = try! parseExprStr("try? -value"); |
| 1643 | let case ast::NodeValue::Try(node) = root.value |
| 1644 | else throw testing::TestError::Failed; |
| 1645 | let case ast::NodeValue::UnOp(neg) = node.expr.value |
| 1646 | else throw testing::TestError::Failed; |
| 1647 | try testing::expect(neg.op == ast::UnaryOp::Neg); |
| 1648 | try expectIdent(neg.value, "value"); |
| 1649 | try testing::expect(node.returnsOptional); |
| 1650 | } |
| 1651 | |
| 1652 | /// Test parsing a `try!` expression that panics on error. |
| 1653 | @test unsafe fn testParseTryBang() throws (testing::TestError) { |
| 1654 | let root = try! parseExprStr("try! value"); |
| 1655 | let case ast::NodeValue::Try(node) = root.value |
| 1656 | else throw testing::TestError::Failed; |
| 1657 | |
| 1658 | try expectIdent(node.expr, "value"); |
| 1659 | try testing::expect(node.catches.len == 0); |
| 1660 | try testing::expect(node.shouldPanic); |
| 1661 | } |
| 1662 | |
| 1663 | /// Test parsing a `try` expression with a `catch` block. |
| 1664 | @test unsafe fn testParseTryCatchBlock() throws (testing::TestError) { |
| 1665 | let root = try! parseExprStr("try value catch { alt; }"); |
| 1666 | let case ast::NodeValue::Try(node) = root.value |
| 1667 | else throw testing::TestError::Failed; |
| 1668 | |
| 1669 | try expectIdent(node.expr, "value"); |
| 1670 | try testing::expect(node.catches.len == 1); |
| 1671 | |
| 1672 | let case ast::NodeValue::CatchClause(clause) = node.catches[0].value |
| 1673 | else throw testing::TestError::Failed; |
| 1674 | try testing::expect(clause.binding == nil); |
| 1675 | try testing::expect(clause.typeNode == nil); |
| 1676 | try expectBlockExprStmt(clause.body, ast::NodeValue::Ident("alt")); |
| 1677 | } |
| 1678 | |
| 1679 | /// Test that `catch` without a block is rejected. |
| 1680 | @test unsafe fn testParseTryCatchExprRejected() throws (testing::TestError) { |
| 1681 | let parsed: ?*ast::Node = try? parseExprStr("try value catch alternate"); |
| 1682 | try testing::expect(parsed == nil); |
| 1683 | } |
| 1684 | |
| 1685 | /// Test parsing a `break` statement. |
| 1686 | @test unsafe fn testParseBreak() throws (testing::TestError) { |
| 1687 | let root = try! parseStmtStr("break"); |
| 1688 | let case ast::NodeValue::Break= root.value |
| 1689 | else throw testing::TestError::Failed; |
| 1690 | } |
| 1691 | |
| 1692 | /// Test parsing a `continue` statement. |
| 1693 | @test unsafe fn testParseContinue() throws (testing::TestError) { |
| 1694 | let root = try! parseStmtStr("continue"); |
| 1695 | let case ast::NodeValue::Continue= root.value |
| 1696 | else throw testing::TestError::Failed; |
| 1697 | } |
| 1698 | |
| 1699 | /// Test parsing a `return` statement without value. |
| 1700 | @test unsafe fn testParseReturnVoid() throws (testing::TestError) { |
| 1701 | let root = try! parseStmtStr("return"); |
| 1702 | let case ast::NodeValue::Return(retValue) = root.value |
| 1703 | else throw testing::TestError::Failed; |
| 1704 | |
| 1705 | try testing::expect(retValue == nil); |
| 1706 | } |
| 1707 | |
| 1708 | /// Test parsing a `return` statement with a value. |
| 1709 | @test unsafe fn testParseReturnValue() throws (testing::TestError) { |
| 1710 | let root = try! parseStmtStr("return result"); |
| 1711 | let case ast::NodeValue::Return(retValue) = root.value |
| 1712 | else throw testing::TestError::Failed; |
| 1713 | |
| 1714 | let value = retValue |
| 1715 | else throw testing::TestError::Failed; |
| 1716 | try expectIdent(value, "result"); |
| 1717 | } |
| 1718 | |
| 1719 | /// Test parsing a `throw` statement. |
| 1720 | @test unsafe fn testParseThrow() throws (testing::TestError) { |
| 1721 | let root = try! parseStmtStr("throw error"); |
| 1722 | let case ast::NodeValue::Throw(throwExpr) = root.value |
| 1723 | else throw testing::TestError::Failed; |
| 1724 | |
| 1725 | try expectIdent(throwExpr, "error"); |
| 1726 | } |
| 1727 | |
| 1728 | /// Test parsing a `panic` statement without a message. |
| 1729 | @test unsafe fn testParsePanicEmpty() throws (testing::TestError) { |
| 1730 | let root = try! parseStmtStr("panic"); |
| 1731 | let case ast::NodeValue::Panic(panicMsg) = root.value |
| 1732 | else throw testing::TestError::Failed; |
| 1733 | |
| 1734 | try testing::expect(panicMsg == nil); |
| 1735 | } |
| 1736 | |
| 1737 | /// Test parsing a `panic` statement with a message. |
| 1738 | @test unsafe fn testParsePanicMessage() throws (testing::TestError) { |
| 1739 | let root = try! parseStmtStr("panic \"something went wrong\""); |
| 1740 | let case ast::NodeValue::Panic(panicMsg) = root.value |
| 1741 | else throw testing::TestError::Failed; |
| 1742 | |
| 1743 | let message = panicMsg |
| 1744 | else throw testing::TestError::Failed; |
| 1745 | let case ast::NodeValue::String(msgStr) = message.value if mem::eq(msgStr, "something went wrong") |
| 1746 | else throw testing::TestError::Failed; |
| 1747 | } |
| 1748 | |
| 1749 | /// Test parsing a `panic` statement with braces. |
| 1750 | @test unsafe fn testParsePanicBraces() throws (testing::TestError) { |
| 1751 | let root = try! parseStmtStr("panic { \"error\" }"); |
| 1752 | let case ast::NodeValue::Panic(panicMsg) = root.value |
| 1753 | else throw testing::TestError::Failed; |
| 1754 | |
| 1755 | let message = panicMsg |
| 1756 | else throw testing::TestError::Failed; |
| 1757 | let case ast::NodeValue::String(msgStr) = message.value if mem::eq(msgStr, "error") |
| 1758 | else throw testing::TestError::Failed; |
| 1759 | } |
| 1760 | |
| 1761 | /// Test parsing a simple `match` statement with one case. |
| 1762 | @test unsafe fn testParseMatchSingle() throws (testing::TestError) { |
| 1763 | let root = try! parseStmtStr("match subject { case pattern => body }"); |
| 1764 | let case ast::NodeValue::Match(sw) = root.value |
| 1765 | else throw testing::TestError::Failed; |
| 1766 | |
| 1767 | try expectIdent(sw.subject, "subject"); |
| 1768 | try testing::expect(sw.prongs.len == 1); |
| 1769 | |
| 1770 | let caseNode = sw.prongs[0]; |
| 1771 | let case ast::NodeValue::MatchProng(prong) = caseNode.value |
| 1772 | else throw testing::TestError::Failed; |
| 1773 | |
| 1774 | let case ast::ProngArm::Case(patterns) = prong.arm |
| 1775 | else throw testing::TestError::Failed; |
| 1776 | try testing::expect(patterns.len == 1); |
| 1777 | try expectIdent(patterns[0], "pattern"); |
| 1778 | try testing::expect(prong.guard == nil); |
| 1779 | |
| 1780 | let case ast::NodeValue::ExprStmt(bodyStmt) = prong.body.value |
| 1781 | else throw testing::TestError::Failed; |
| 1782 | let case ast::NodeValue::Ident(name) = bodyStmt.value |
| 1783 | if mem::eq(name, "body") |
| 1784 | else throw testing::TestError::Failed; |
| 1785 | } |
| 1786 | |
| 1787 | /// Test parsing a `match` case with guard and multiple patterns. |
| 1788 | @test unsafe fn testParseMatchGuard() throws (testing::TestError) { |
| 1789 | let root = try! parseStmtStr( |
| 1790 | "match subject { case left, right if cond => handle }" |
| 1791 | ); |
| 1792 | let case ast::NodeValue::Match(sw) = root.value |
| 1793 | else throw testing::TestError::Failed; |
| 1794 | |
| 1795 | try testing::expect(sw.prongs.len == 1); |
| 1796 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1797 | else throw testing::TestError::Failed; |
| 1798 | |
| 1799 | let case ast::ProngArm::Case(patterns) = prong.arm |
| 1800 | else throw testing::TestError::Failed; |
| 1801 | try testing::expect(patterns.len == 2); |
| 1802 | try expectIdent(patterns[0], "left"); |
| 1803 | try expectIdent(patterns[1], "right"); |
| 1804 | |
| 1805 | let guard = prong.guard |
| 1806 | else throw testing::TestError::Failed; |
| 1807 | try expectIdent(guard, "cond"); |
| 1808 | } |
| 1809 | |
| 1810 | /// Test parsing `match` prongs whose bodies omit trailing semicolons. |
| 1811 | @test unsafe fn testParseMatchReturnNoSemicolon() throws (testing::TestError) { |
| 1812 | let root = try! parseStmtStr( |
| 1813 | "match subject { case First => return, case Second => return }" |
| 1814 | ); |
| 1815 | let case ast::NodeValue::Match(sw) = root.value |
| 1816 | else throw testing::TestError::Failed; |
| 1817 | |
| 1818 | try testing::expect(sw.prongs.len == 2); |
| 1819 | |
| 1820 | let firstCaseNode = sw.prongs[0]; |
| 1821 | let case ast::NodeValue::MatchProng(firstProng) = firstCaseNode.value |
| 1822 | else throw testing::TestError::Failed; |
| 1823 | let case ast::NodeValue::Return(firstRetVal) = firstProng.body.value |
| 1824 | else throw testing::TestError::Failed; |
| 1825 | try testing::expect(firstRetVal == nil); |
| 1826 | |
| 1827 | let secondCaseNode = sw.prongs[1]; |
| 1828 | let case ast::NodeValue::MatchProng(secondProng) = secondCaseNode.value |
| 1829 | else throw testing::TestError::Failed; |
| 1830 | let case ast::NodeValue::Return(secondRetVal) = secondProng.body.value |
| 1831 | else throw testing::TestError::Failed; |
| 1832 | try testing::expect(secondRetVal == nil); |
| 1833 | } |
| 1834 | |
| 1835 | /// Test parsing a `match` statement with multiple branches. |
| 1836 | @test unsafe fn testParseMatchMultipleCases() throws (testing::TestError) { |
| 1837 | let root = try! parseStmtStr( |
| 1838 | "match subject { case First => first, case Second => second }" |
| 1839 | ); |
| 1840 | let case ast::NodeValue::Match(sw) = root.value |
| 1841 | else throw testing::TestError::Failed; |
| 1842 | |
| 1843 | try testing::expect(sw.prongs.len == 2); |
| 1844 | { |
| 1845 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1846 | else throw testing::TestError::Failed; |
| 1847 | let case ast::ProngArm::Case(patterns) = prong.arm |
| 1848 | else throw testing::TestError::Failed; |
| 1849 | try testing::expect(patterns.len == 1); |
| 1850 | try expectIdent(patterns[0], "First"); |
| 1851 | let case ast::NodeValue::ExprStmt(stmt) = prong.body.value |
| 1852 | else throw testing::TestError::Failed; |
| 1853 | let case ast::NodeValue::Ident(val) = stmt.value |
| 1854 | if mem::eq(val, "first") |
| 1855 | else throw testing::TestError::Failed; |
| 1856 | } { |
| 1857 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[1].value |
| 1858 | else throw testing::TestError::Failed; |
| 1859 | let case ast::ProngArm::Case(pats) = prong.arm |
| 1860 | else throw testing::TestError::Failed; |
| 1861 | |
| 1862 | try testing::expect(pats.len == 1); |
| 1863 | try expectIdent(pats[0], "Second"); |
| 1864 | |
| 1865 | let case ast::NodeValue::ExprStmt(stmt) = prong.body.value |
| 1866 | else throw testing::TestError::Failed; |
| 1867 | let case ast::NodeValue::Ident(val) = stmt.value |
| 1868 | if mem::eq(val, "second") |
| 1869 | else throw testing::TestError::Failed; |
| 1870 | } |
| 1871 | } |
| 1872 | |
| 1873 | /// Test parsing a `match` case whose body is a block. |
| 1874 | @test unsafe fn testParseMatchProngBlock() throws (testing::TestError) { |
| 1875 | let root = try! parseStmtStr("match subject { case Pattern => { body; } }"); |
| 1876 | let case ast::NodeValue::Match(sw) = root.value |
| 1877 | else throw testing::TestError::Failed; |
| 1878 | |
| 1879 | try testing::expect(sw.prongs.len == 1); |
| 1880 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1881 | else throw testing::TestError::Failed; |
| 1882 | try expectBlockExprStmt(prong.body, ast::NodeValue::Ident("body")); |
| 1883 | } |
| 1884 | |
| 1885 | /// Test parsing a `match` statement with an `else` case. |
| 1886 | @test unsafe fn testParseMatchElse() throws (testing::TestError) { |
| 1887 | let root = try! parseStmtStr("match subject { else => body }"); |
| 1888 | let case ast::NodeValue::Match(sw) = root.value |
| 1889 | else throw testing::TestError::Failed; |
| 1890 | |
| 1891 | try testing::expect(sw.prongs.len == 1); |
| 1892 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1893 | else throw testing::TestError::Failed; |
| 1894 | // Else prong has no pattern. |
| 1895 | let case ast::ProngArm::Else = prong.arm |
| 1896 | else throw testing::TestError::Failed; |
| 1897 | try testing::expect(prong.guard == nil); |
| 1898 | |
| 1899 | let case ast::NodeValue::ExprStmt(bodyStmt) = prong.body.value |
| 1900 | else throw testing::TestError::Failed; |
| 1901 | let case ast::NodeValue::Ident(name) = bodyStmt.value |
| 1902 | if mem::eq(name, "body") |
| 1903 | else throw testing::TestError::Failed; |
| 1904 | } |
| 1905 | |
| 1906 | /// Test parsing a `match` statement with a binding prong. |
| 1907 | @test unsafe fn testParseMatchBinding() throws (testing::TestError) { |
| 1908 | let root = try! parseStmtStr("match subject { x => body }"); |
| 1909 | let case ast::NodeValue::Match(sw) = root.value |
| 1910 | else throw testing::TestError::Failed; |
| 1911 | |
| 1912 | try testing::expect(sw.prongs.len == 1); |
| 1913 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1914 | else throw testing::TestError::Failed; |
| 1915 | // Binding prong has single identifier pattern. |
| 1916 | let case ast::ProngArm::Binding(pat) = prong.arm |
| 1917 | else throw testing::TestError::Failed; |
| 1918 | try expectIdent(pat, "x"); |
| 1919 | try testing::expect(prong.guard == nil); |
| 1920 | |
| 1921 | let case ast::NodeValue::ExprStmt(bodyStmt) = prong.body.value |
| 1922 | else throw testing::TestError::Failed; |
| 1923 | try expectIdent(bodyStmt, "body"); |
| 1924 | } |
| 1925 | |
| 1926 | /// Test parsing a `match` statement with a guarded binding prong. |
| 1927 | @test unsafe fn testParseMatchBindingGuard() throws (testing::TestError) { |
| 1928 | let root = try! parseStmtStr("match subject { x if x > 0 => body }"); |
| 1929 | let case ast::NodeValue::Match(sw) = root.value |
| 1930 | else throw testing::TestError::Failed; |
| 1931 | |
| 1932 | try testing::expect(sw.prongs.len == 1); |
| 1933 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1934 | else throw testing::TestError::Failed; |
| 1935 | // Binding prong has single identifier pattern. |
| 1936 | let case ast::ProngArm::Binding(pat) = prong.arm |
| 1937 | else throw testing::TestError::Failed; |
| 1938 | try expectIdent(pat, "x"); |
| 1939 | |
| 1940 | let guard = prong.guard else throw testing::TestError::Failed; |
| 1941 | let case ast::NodeValue::BinOp(binop) = guard.value |
| 1942 | else throw testing::TestError::Failed; |
| 1943 | try testing::expect(binop.op == ast::BinaryOp::Gt); |
| 1944 | } |
| 1945 | |
| 1946 | /// Test parsing a `match` statement with a `_` wildcard. |
| 1947 | @test unsafe fn testParseMatchWildcard() throws (testing::TestError) { |
| 1948 | let root = try! parseStmtStr("match subject { _ => body }"); |
| 1949 | let case ast::NodeValue::Match(sw) = root.value |
| 1950 | else throw testing::TestError::Failed; |
| 1951 | |
| 1952 | try testing::expect(sw.prongs.len == 1); |
| 1953 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1954 | else throw testing::TestError::Failed; |
| 1955 | // Wildcard binding prong has single placeholder pattern. |
| 1956 | let case ast::ProngArm::Binding(pat) = prong.arm |
| 1957 | else throw testing::TestError::Failed; |
| 1958 | let case ast::NodeValue::Placeholder = pat.value |
| 1959 | else throw testing::TestError::Failed; |
| 1960 | try testing::expect(prong.guard == nil); |
| 1961 | |
| 1962 | let case ast::NodeValue::ExprStmt(bodyStmt) = prong.body.value |
| 1963 | else throw testing::TestError::Failed; |
| 1964 | try expectIdent(bodyStmt, "body"); |
| 1965 | } |
| 1966 | |
| 1967 | /// Test parsing a `match` statement with a guarded `_` wildcard. |
| 1968 | @test unsafe fn testParseMatchWildcardGuard() throws (testing::TestError) { |
| 1969 | let root = try! parseStmtStr("match subject { _ if cond => body }"); |
| 1970 | let case ast::NodeValue::Match(sw) = root.value |
| 1971 | else throw testing::TestError::Failed; |
| 1972 | |
| 1973 | try testing::expect(sw.prongs.len == 1); |
| 1974 | let case ast::NodeValue::MatchProng(prong) = sw.prongs[0].value |
| 1975 | else throw testing::TestError::Failed; |
| 1976 | // Guarded wildcard binding prong has single placeholder pattern. |
| 1977 | let case ast::ProngArm::Binding(pat) = prong.arm |
| 1978 | else throw testing::TestError::Failed; |
| 1979 | let case ast::NodeValue::Placeholder = pat.value |
| 1980 | else throw testing::TestError::Failed; |
| 1981 | |
| 1982 | let guard = prong.guard else throw testing::TestError::Failed; |
| 1983 | try expectIdent(guard, "cond"); |
| 1984 | let case ast::NodeValue::ExprStmt(bodyStmt) = prong.body.value |
| 1985 | else throw testing::TestError::Failed; |
| 1986 | try expectIdent(bodyStmt, "body"); |
| 1987 | } |
| 1988 | |
| 1989 | /// Test parsing a `while let` loop with guard and else branches. |
| 1990 | @test unsafe fn testParseWhileLet() throws (testing::TestError) { |
| 1991 | let root = try! parseStmtStr( |
| 1992 | "while let value = opt; guard { body; } else { alt; }" |
| 1993 | ); |
| 1994 | let case ast::NodeValue::WhileLet(loopNode) = root.value |
| 1995 | else throw testing::TestError::Failed; |
| 1996 | |
| 1997 | try expectIdent(loopNode.pattern.pattern, "value"); |
| 1998 | try expectIdent(loopNode.pattern.scrutinee, "opt"); |
| 1999 | |
| 2000 | let guard = loopNode.pattern.guard |
| 2001 | else throw testing::TestError::Failed; |
| 2002 | try expectIdent(guard, "guard"); |
| 2003 | |
| 2004 | try expectBlockExprStmt(loopNode.body, ast::NodeValue::Ident("body")); |
| 2005 | |
| 2006 | let elseBranch = loopNode.elseBranch |
| 2007 | else throw testing::TestError::Failed; |
| 2008 | try expectBlockExprStmt(elseBranch, ast::NodeValue::Ident("alt")); |
| 2009 | } |
| 2010 | |
| 2011 | /// Test parsing a simple `loop` statement. |
| 2012 | @test unsafe fn testParseLoop() throws (testing::TestError) { |
| 2013 | let root = try! parseStmtStr("loop { body; }"); |
| 2014 | let case ast::NodeValue::Loop(loopBody) = root.value |
| 2015 | else throw testing::TestError::Failed; |
| 2016 | |
| 2017 | try expectBlockExprStmt(loopBody, ast::NodeValue::Ident("body")); |
| 2018 | } |
| 2019 | |
| 2020 | /// Test parsing a `for` loop without index or else branches. |
| 2021 | @test unsafe fn testParseFor() throws (testing::TestError) { |
| 2022 | let root = try! parseStmtStr("for item in items { body; }"); |
| 2023 | let case ast::NodeValue::For(loopNode) = root.value |
| 2024 | else throw testing::TestError::Failed; |
| 2025 | |
| 2026 | try expectIdent(loopNode.binding, "item"); |
| 2027 | try testing::expect(loopNode.index == nil); |
| 2028 | |
| 2029 | try expectIdent(loopNode.iterable, "items"); |
| 2030 | try expectBlockExprStmt(loopNode.body, ast::NodeValue::Ident("body")); |
| 2031 | try testing::expect(loopNode.elseBranch == nil); |
| 2032 | } |
| 2033 | |
| 2034 | /// Test parsing a `for` loop over a range expression. |
| 2035 | @test unsafe fn testParseForRangeIterable() throws (testing::TestError) { |
| 2036 | let root = try! parseStmtStr("for item in 0..5 {}"); |
| 2037 | let case ast::NodeValue::For(loopNode) = root.value |
| 2038 | else throw testing::TestError::Failed; |
| 2039 | |
| 2040 | try expectIdent(loopNode.binding, "item"); |
| 2041 | try testing::expect(loopNode.index == nil); |
| 2042 | try expectRangeNumbers(loopNode.iterable, "0", "5"); |
| 2043 | |
| 2044 | let case ast::NodeValue::Block(body) = loopNode.body.value |
| 2045 | else throw testing::TestError::Failed; |
| 2046 | try testing::expect(body.statements.len == 0); |
| 2047 | try testing::expect(loopNode.elseBranch == nil); |
| 2048 | } |
| 2049 | |
| 2050 | /// Test parsing a `for` loop with index and else branches. |
| 2051 | @test unsafe fn testParseForIndexElse() throws (testing::TestError) { |
| 2052 | let root = try! parseStmtStr( |
| 2053 | "for value, idx in items { body; } else { alt; }" |
| 2054 | ); |
| 2055 | let case ast::NodeValue::For(loopNode) = root.value |
| 2056 | else throw testing::TestError::Failed; |
| 2057 | |
| 2058 | try expectIdent(loopNode.binding, "value"); |
| 2059 | |
| 2060 | let index = loopNode.index |
| 2061 | else throw testing::TestError::Failed; |
| 2062 | try expectIdent(index, "idx"); |
| 2063 | |
| 2064 | try expectIdent(loopNode.iterable, "items"); |
| 2065 | try expectBlockExprStmt(loopNode.body, ast::NodeValue::Ident("body")); |
| 2066 | |
| 2067 | let elseBranch = loopNode.elseBranch |
| 2068 | else throw testing::TestError::Failed; |
| 2069 | try expectBlockExprStmt(elseBranch, ast::NodeValue::Ident("alt")); |
| 2070 | } |
| 2071 | |
| 2072 | /// Test parsing field access expression. |
| 2073 | @test unsafe fn testParseFieldAccess() throws (testing::TestError) { |
| 2074 | let root = try! parseExprStr("obj.field"); |
| 2075 | let case ast::NodeValue::FieldAccess(access) = root.value |
| 2076 | else throw testing::TestError::Failed; |
| 2077 | |
| 2078 | try expectIdent(access.parent, "obj"); |
| 2079 | try expectIdent(access.child, "field"); |
| 2080 | } |
| 2081 | |
| 2082 | /// Test parsing scope access expression. |
| 2083 | @test unsafe fn testParseScopeAccess() throws (testing::TestError) { |
| 2084 | let root = try! parseExprStr("module::item"); |
| 2085 | let case ast::NodeValue::ScopeAccess(access) = root.value |
| 2086 | else throw testing::TestError::Failed; |
| 2087 | |
| 2088 | try expectIdent(access.parent, "module"); |
| 2089 | try expectIdent(access.child, "item"); |
| 2090 | } |
| 2091 | |
| 2092 | /// Test parsing array subscript expression. |
| 2093 | @test unsafe fn testParseArraySubscript() throws (testing::TestError) { |
| 2094 | let root = try! parseExprStr("array[index]"); |
| 2095 | let case ast::NodeValue::Subscript { container, index } = root.value |
| 2096 | else throw testing::TestError::Failed; |
| 2097 | |
| 2098 | try expectIdent(container, "array"); |
| 2099 | try expectIdent(index, "index"); |
| 2100 | } |
| 2101 | |
| 2102 | /// Test parsing array slicing expressions. |
| 2103 | @test unsafe fn testParseArraySlicing() throws (testing::TestError) { |
| 2104 | // Test `array[start..end]`. |
| 2105 | { |
| 2106 | let expr = try! parseExprStr("array[1..10]"); |
| 2107 | let case ast::NodeValue::Subscript { container: subContainer, index: subIndex } = expr.value |
| 2108 | else throw testing::TestError::Failed; |
| 2109 | try expectIdent(subContainer, "array"); |
| 2110 | |
| 2111 | let case ast::NodeValue::Range(range) = subIndex.value |
| 2112 | else throw testing::TestError::Failed; |
| 2113 | let start = range.start |
| 2114 | else throw testing::TestError::Failed; |
| 2115 | let end = range.end |
| 2116 | else throw testing::TestError::Failed; |
| 2117 | try expectNumber(start, "1"); |
| 2118 | try expectNumber(end, "10"); |
| 2119 | } |
| 2120 | // Test `array[start..]`. |
| 2121 | { |
| 2122 | let expr = try! parseExprStr("array[5..]"); |
| 2123 | let case ast::NodeValue::Subscript { container: subContainer, index: subIndex } = expr.value |
| 2124 | else throw testing::TestError::Failed; |
| 2125 | try expectIdent(subContainer, "array"); |
| 2126 | |
| 2127 | let case ast::NodeValue::Range(range) = subIndex.value |
| 2128 | else throw testing::TestError::Failed; |
| 2129 | let start = range.start |
| 2130 | else throw testing::TestError::Failed; |
| 2131 | try expectNumber(start, "5"); |
| 2132 | try testing::expect(range.end == nil); |
| 2133 | } |
| 2134 | // Test `array[..end]`. |
| 2135 | { |
| 2136 | let expr = try! parseExprStr("array[..10]"); |
| 2137 | let case ast::NodeValue::Subscript { container: subContainer, index: subIndex } = expr.value |
| 2138 | else throw testing::TestError::Failed; |
| 2139 | try expectIdent(subContainer, "array"); |
| 2140 | |
| 2141 | let case ast::NodeValue::Range(range) = subIndex.value |
| 2142 | else throw testing::TestError::Failed; |
| 2143 | try testing::expect(range.start == nil); |
| 2144 | let end = range.end |
| 2145 | else throw testing::TestError::Failed; |
| 2146 | try expectNumber(end, "10"); |
| 2147 | } |
| 2148 | // Test `array[..]`. |
| 2149 | { |
| 2150 | let expr = try! parseExprStr("array[..]"); |
| 2151 | let case ast::NodeValue::Subscript { container: subContainer, index: subIndex } = expr.value |
| 2152 | else throw testing::TestError::Failed; |
| 2153 | try expectIdent(subContainer, "array"); |
| 2154 | |
| 2155 | let case ast::NodeValue::Range(range) = subIndex.value |
| 2156 | else throw testing::TestError::Failed; |
| 2157 | try testing::expect(range.start == nil); |
| 2158 | try testing::expect(range.end == nil); |
| 2159 | } |
| 2160 | } |
| 2161 | |
| 2162 | /// Test parsing function call expression. |
| 2163 | @test unsafe fn testParseFunctionCall() throws (testing::TestError) { |
| 2164 | let root = try! parseExprStr("func(x, y)"); |
| 2165 | let case ast::NodeValue::Call(call) = root.value |
| 2166 | else throw testing::TestError::Failed; |
| 2167 | |
| 2168 | try expectIdent(call.callee, "func"); |
| 2169 | try testing::expect(call.args.len == 2); |
| 2170 | try expectIdent(call.args[0], "x"); |
| 2171 | try expectIdent(call.args[1], "y"); |
| 2172 | } |
| 2173 | |
| 2174 | /// Test parsing chained postfix operators. |
| 2175 | @test unsafe fn testParseChainedPostfix() throws (testing::TestError) { |
| 2176 | let root = try! parseExprStr("obj.method(arg)[0]"); |
| 2177 | let case ast::NodeValue::Subscript { container: subContainer, index: subIndex } = root.value |
| 2178 | else throw testing::TestError::Failed; |
| 2179 | |
| 2180 | let case ast::NodeValue::Call(call) = subContainer.value |
| 2181 | else throw testing::TestError::Failed; |
| 2182 | |
| 2183 | let case ast::NodeValue::FieldAccess(fieldAccess) = call.callee.value |
| 2184 | else throw testing::TestError::Failed; |
| 2185 | |
| 2186 | try expectIdent(fieldAccess.parent, "obj"); |
| 2187 | try expectIdent(fieldAccess.child, "method"); |
| 2188 | try testing::expect(call.args.len == 1); |
| 2189 | try expectIdent(call.args[0], "arg"); |
| 2190 | } |
| 2191 | |
| 2192 | /// Test parsing a literal cast using `as`. |
| 2193 | @test unsafe fn testParseAsCastLiteral() throws (testing::TestError) { |
| 2194 | let root = try! parseExprStr("1 as i32"); |
| 2195 | let case ast::NodeValue::As(asExpr) = root.value |
| 2196 | else throw testing::TestError::Failed; |
| 2197 | |
| 2198 | let case ast::NodeValue::Number(_) = asExpr.value.value |
| 2199 | else throw testing::TestError::Failed; |
| 2200 | |
| 2201 | try expectIntType(asExpr.type, 4, ast::Signedness::Signed); |
| 2202 | } |
| 2203 | |
| 2204 | /// Test parsing a cast following chained postfix expressions. |
| 2205 | @test unsafe fn testParseAsCastWithPostfix() throws (testing::TestError) { |
| 2206 | let root = try! parseExprStr("value.method(arg) as u32"); |
| 2207 | let case ast::NodeValue::As(asExpr) = root.value |
| 2208 | else throw testing::TestError::Failed; |
| 2209 | |
| 2210 | let case ast::NodeValue::Call(call) = asExpr.value.value |
| 2211 | else throw testing::TestError::Failed; |
| 2212 | |
| 2213 | let case ast::NodeValue::FieldAccess(access) = call.callee.value |
| 2214 | else throw testing::TestError::Failed; |
| 2215 | |
| 2216 | try expectIdent(access.parent, "value"); |
| 2217 | try expectIdent(access.child, "method"); |
| 2218 | try testing::expect(call.args.len == 1); |
| 2219 | try expectIdent(call.args[0], "arg"); |
| 2220 | try expectIntType(asExpr.type, 4, ast::Signedness::Unsigned); |
| 2221 | } |
| 2222 | |
| 2223 | /// Test parsing @sizeOf builtin. |
| 2224 | @test unsafe fn testParseBuiltinSizeOf() throws (testing::TestError) { |
| 2225 | let expr = try! parseExprStr("@sizeOf(i32)"); |
| 2226 | let case ast::NodeValue::BuiltinCall { kind: builtinKind, args: builtinArgs } = expr.value |
| 2227 | else throw testing::TestError::Failed; |
| 2228 | |
| 2229 | try testing::expect(builtinKind == ast::Builtin::SizeOf); |
| 2230 | try testing::expect(builtinArgs.len == 1); |
| 2231 | try expectType(builtinArgs[0], ast::TypeSig::Integer { |
| 2232 | width: 4, |
| 2233 | sign: ast::Signedness::Signed, |
| 2234 | }); |
| 2235 | } |
| 2236 | |
| 2237 | /// Test parsing @alignOf builtin. |
| 2238 | @test unsafe fn testParseBuiltinAlignOf() throws (testing::TestError) { |
| 2239 | let expr = try! parseExprStr("@alignOf(i32)"); |
| 2240 | let case ast::NodeValue::BuiltinCall { kind: builtinKind, args: builtinArgs } = expr.value |
| 2241 | else throw testing::TestError::Failed; |
| 2242 | |
| 2243 | try testing::expect(builtinKind == ast::Builtin::AlignOf); |
| 2244 | try testing::expect(builtinArgs.len == 1); |
| 2245 | try expectType(builtinArgs[0], ast::TypeSig::Integer { |
| 2246 | width: 4, |
| 2247 | sign: ast::Signedness::Signed, |
| 2248 | }); |
| 2249 | } |
| 2250 | |
| 2251 | /// Test parsing @sliceOf with varying argument counts. |
| 2252 | @test unsafe fn testParseBuiltinSliceOf() throws (testing::TestError) { |
| 2253 | // Two arguments. |
| 2254 | { |
| 2255 | let expr = try! parseExprStr("@sliceOf(ptr, len)"); |
| 2256 | let case ast::NodeValue::BuiltinCall { kind: builtinKind, args: builtinArgs } = expr.value |
| 2257 | else throw testing::TestError::Failed; |
| 2258 | try testing::expect(builtinKind == ast::Builtin::SliceOf); |
| 2259 | try testing::expect(builtinArgs.len == 2); |
| 2260 | } |
| 2261 | // One argument. |
| 2262 | { |
| 2263 | let expr = try! parseExprStr("@sliceOf(ptr)"); |
| 2264 | let case ast::NodeValue::BuiltinCall { kind: builtinKind, args: builtinArgs } = expr.value |
| 2265 | else throw testing::TestError::Failed; |
| 2266 | try testing::expect(builtinKind == ast::Builtin::SliceOf); |
| 2267 | try testing::expect(builtinArgs.len == 1); |
| 2268 | } |
| 2269 | // Three arguments. |
| 2270 | { |
| 2271 | let expr = try! parseExprStr("@sliceOf(ptr, len, extra)"); |
| 2272 | let case ast::NodeValue::BuiltinCall { kind: builtinKind, args: builtinArgs } = expr.value |
| 2273 | else throw testing::TestError::Failed; |
| 2274 | try testing::expect(builtinKind == ast::Builtin::SliceOf); |
| 2275 | try testing::expect(builtinArgs.len == 3); |
| 2276 | } |
| 2277 | } |
| 2278 | |
| 2279 | /// Test parsing prefix unary operators. |
| 2280 | @test unsafe fn testParseUnaryOperators() throws (testing::TestError) { |
| 2281 | { |
| 2282 | let notExpr = try! parseExprStr("not flag"); |
| 2283 | let case ast::NodeValue::UnOp(notNode) = notExpr.value |
| 2284 | else throw testing::TestError::Failed; |
| 2285 | try testing::expect(notNode.op == ast::UnaryOp::Not); |
| 2286 | try expectIdent(notNode.value, "flag"); |
| 2287 | } |
| 2288 | { |
| 2289 | let negExpr = try! parseExprStr("-value"); |
| 2290 | let case ast::NodeValue::UnOp(negNode) = negExpr.value |
| 2291 | else throw testing::TestError::Failed; |
| 2292 | try testing::expect(negNode.op == ast::UnaryOp::Neg); |
| 2293 | try expectIdent(negNode.value, "value"); |
| 2294 | } |
| 2295 | { |
| 2296 | let bitNotExpr = try! parseExprStr("~mask"); |
| 2297 | let case ast::NodeValue::UnOp(bitNotNode) = bitNotExpr.value |
| 2298 | else throw testing::TestError::Failed; |
| 2299 | try testing::expect(bitNotNode.op == ast::UnaryOp::BitNot); |
| 2300 | try expectIdent(bitNotNode.value, "mask"); |
| 2301 | } |
| 2302 | } |
| 2303 | |
| 2304 | /// Test parsing dereference expressions. |
| 2305 | @test unsafe fn testParseDereference() throws (testing::TestError) { |
| 2306 | { |
| 2307 | let derefExpr = try! parseExprStr("*ptr"); |
| 2308 | let case ast::NodeValue::Deref(target) = derefExpr.value |
| 2309 | else throw testing::TestError::Failed; |
| 2310 | try expectIdent(target, "ptr"); |
| 2311 | } |
| 2312 | { |
| 2313 | let derefField = try! parseExprStr("*ptr.field"); |
| 2314 | let case ast::NodeValue::Deref(target) = derefField.value |
| 2315 | else throw testing::TestError::Failed; |
| 2316 | let case ast::NodeValue::FieldAccess(access) = target.value |
| 2317 | else throw testing::TestError::Failed; |
| 2318 | try expectIdent(access.parent, "ptr"); |
| 2319 | try expectIdent(access.child, "field"); |
| 2320 | } |
| 2321 | } |
| 2322 | |
| 2323 | /// Test parsing reference (address-of) expressions. |
| 2324 | @test unsafe fn testParseRefs() throws (testing::TestError) { |
| 2325 | { |
| 2326 | let expr = try! parseExprStr("&cell obj.field"); |
| 2327 | let case ast::NodeValue::AddressOf(address) = expr.value |
| 2328 | else throw testing::TestError::Failed; |
| 2329 | try testing::expect( |
| 2330 | address.kind == ast::AddressKind::Cell and address.permission == nil |
| 2331 | ); |
| 2332 | let case ast::NodeValue::FieldAccess(access) = address.target.value |
| 2333 | else throw testing::TestError::Failed; |
| 2334 | try expectIdent(access.parent, "obj"); |
| 2335 | try expectIdent(access.child, "field"); |
| 2336 | } |
| 2337 | { |
| 2338 | let expr = try! parseExprStr("&cell 'permission obj.field"); |
| 2339 | let case ast::NodeValue::AddressOf(address) = expr.value |
| 2340 | else throw testing::TestError::Failed; |
| 2341 | let permission = address.permission else throw testing::TestError::Failed; |
| 2342 | let case ast::NodeValue::Region { name, parent: nil } = permission.value |
| 2343 | else throw testing::TestError::Failed; |
| 2344 | try testing::expect( |
| 2345 | address.kind == ast::AddressKind::Cell and mem::eq(name, "'permission") |
| 2346 | ); |
| 2347 | let case ast::NodeValue::FieldAccess(access) = address.target.value |
| 2348 | else throw testing::TestError::Failed; |
| 2349 | try expectIdent(access.parent, "obj"); |
| 2350 | try expectIdent(access.child, "field"); |
| 2351 | } |
| 2352 | { |
| 2353 | let refExpr = try! parseExprStr("&foo"); |
| 2354 | let case ast::NodeValue::AddressOf(refNode) = refExpr.value |
| 2355 | else throw testing::TestError::Failed; |
| 2356 | try testing::expect( |
| 2357 | refNode.kind == ast::AddressKind::Shared and refNode.permission == nil |
| 2358 | ); |
| 2359 | try expectIdent(refNode.target, "foo"); |
| 2360 | } |
| 2361 | { |
| 2362 | let mutRefExpr = try! parseExprStr("&mut bar"); |
| 2363 | let case ast::NodeValue::AddressOf(mutRefNode) = mutRefExpr.value |
| 2364 | else throw testing::TestError::Failed; |
| 2365 | try testing::expect( |
| 2366 | mutRefNode.kind == ast::AddressKind::Mutable and mutRefNode.permission == nil |
| 2367 | ); |
| 2368 | try expectIdent(mutRefNode.target, "bar"); |
| 2369 | } |
| 2370 | { |
| 2371 | let refFieldExpr = try! parseExprStr("&obj.field"); |
| 2372 | let case ast::NodeValue::AddressOf(refFieldNode) = refFieldExpr.value |
| 2373 | else throw testing::TestError::Failed; |
| 2374 | try testing::expect( |
| 2375 | refFieldNode.kind == ast::AddressKind::Shared and refFieldNode.permission == nil |
| 2376 | ); |
| 2377 | let case ast::NodeValue::FieldAccess(access) = refFieldNode.target.value |
| 2378 | else throw testing::TestError::Failed; |
| 2379 | try expectIdent(access.parent, "obj"); |
| 2380 | try expectIdent(access.child, "field"); |
| 2381 | } |
| 2382 | { |
| 2383 | let mutRefFieldExpr = try! parseExprStr("&mut obj.field"); |
| 2384 | let case ast::NodeValue::AddressOf(mutRefFieldNode) = mutRefFieldExpr.value |
| 2385 | else throw testing::TestError::Failed; |
| 2386 | try testing::expect( |
| 2387 | mutRefFieldNode.kind == ast::AddressKind::Mutable |
| 2388 | and mutRefFieldNode.permission == nil |
| 2389 | ); |
| 2390 | let case ast::NodeValue::FieldAccess(access) = mutRefFieldNode.target.value |
| 2391 | else throw testing::TestError::Failed; |
| 2392 | try expectIdent(access.parent, "obj"); |
| 2393 | try expectIdent(access.child, "field"); |
| 2394 | } |
| 2395 | for source in ["&'permission obj.field", "&mut 'permission obj.field"] { |
| 2396 | let parsed = try? parseExprStr(source); |
| 2397 | try testing::expect(parsed == nil); |
| 2398 | } |
| 2399 | } |
| 2400 | |
| 2401 | /// Test unary operator precedence relative to binary and postfix expressions. |
| 2402 | @test unsafe fn testParseUnaryPrecedence() throws (testing::TestError) { |
| 2403 | { |
| 2404 | let expr = try! parseExprStr("not a and b"); |
| 2405 | let case ast::NodeValue::BinOp(bin) = expr.value |
| 2406 | else throw testing::TestError::Failed; |
| 2407 | try testing::expect(bin.op == ast::BinaryOp::And); |
| 2408 | let case ast::NodeValue::UnOp(leftUnary) = bin.left.value |
| 2409 | else throw testing::TestError::Failed; |
| 2410 | try testing::expect(leftUnary.op == ast::UnaryOp::Not); |
| 2411 | try expectIdent(leftUnary.value, "a"); |
| 2412 | try expectIdent(bin.right, "b"); |
| 2413 | } |
| 2414 | { |
| 2415 | let mulExpr = try! parseExprStr("-x * y"); |
| 2416 | let case ast::NodeValue::BinOp(mul) = mulExpr.value |
| 2417 | else throw testing::TestError::Failed; |
| 2418 | try testing::expect(mul.op == ast::BinaryOp::Mul); |
| 2419 | let case ast::NodeValue::UnOp(leftNeg) = mul.left.value |
| 2420 | else throw testing::TestError::Failed; |
| 2421 | try testing::expect(leftNeg.op == ast::UnaryOp::Neg); |
| 2422 | try expectIdent(leftNeg.value, "x"); |
| 2423 | try expectIdent(mul.right, "y"); |
| 2424 | } |
| 2425 | { |
| 2426 | let callExpr = try! parseExprStr("not func()"); |
| 2427 | let case ast::NodeValue::UnOp(callNot) = callExpr.value |
| 2428 | else throw testing::TestError::Failed; |
| 2429 | try testing::expect(callNot.op == ast::UnaryOp::Not); |
| 2430 | let case ast::NodeValue::Call(call) = callNot.value.value |
| 2431 | else throw testing::TestError::Failed; |
| 2432 | try expectIdent(call.callee, "func"); |
| 2433 | } |
| 2434 | } |
| 2435 | |
| 2436 | /// Test parsing assignment expressions. |
| 2437 | @test unsafe fn testParseAssignment() throws (testing::TestError) { |
| 2438 | { |
| 2439 | let assign = try! parseStmtStr("set x = 1;"); |
| 2440 | let case ast::NodeValue::Assign(node) = assign.value |
| 2441 | else throw testing::TestError::Failed; |
| 2442 | try expectIdent(node.left, "x"); |
| 2443 | let case ast::NodeValue::Number(_) = node.right.value |
| 2444 | else throw testing::TestError::Failed; |
| 2445 | } |
| 2446 | { |
| 2447 | let assign = try! parseStmtStr("set obj.field = value;"); |
| 2448 | let case ast::NodeValue::Assign(node) = assign.value |
| 2449 | else throw testing::TestError::Failed; |
| 2450 | let case ast::NodeValue::FieldAccess(access) = node.left.value |
| 2451 | else throw testing::TestError::Failed; |
| 2452 | try expectIdent(access.parent, "obj"); |
| 2453 | try expectIdent(access.child, "field"); |
| 2454 | try expectIdent(node.right, "value"); |
| 2455 | } |
| 2456 | { |
| 2457 | let assign = try! parseStmtStr("set *ptr = rhs;"); |
| 2458 | let case ast::NodeValue::Assign(node) = assign.value |
| 2459 | else throw testing::TestError::Failed; |
| 2460 | let case ast::NodeValue::Deref(target) = node.left.value |
| 2461 | else throw testing::TestError::Failed; |
| 2462 | try expectIdent(target, "ptr"); |
| 2463 | try expectIdent(node.right, "rhs"); |
| 2464 | } |
| 2465 | { |
| 2466 | let assign = try! parseStmtStr("set x = 1 + 2;"); |
| 2467 | let case ast::NodeValue::Assign(node) = assign.value |
| 2468 | else throw testing::TestError::Failed; |
| 2469 | let case ast::NodeValue::BinOp(bin) = node.right.value |
| 2470 | else throw testing::TestError::Failed; |
| 2471 | try testing::expect(bin.op == ast::BinaryOp::Add); |
| 2472 | } |
| 2473 | { |
| 2474 | let assign = try! parseStmtStr("set module::VAR = 1;"); |
| 2475 | let case ast::NodeValue::Assign(node) = assign.value |
| 2476 | else throw testing::TestError::Failed; |
| 2477 | let case ast::NodeValue::ScopeAccess(access) = node.left.value |
| 2478 | else throw testing::TestError::Failed; |
| 2479 | try expectIdent(access.parent, "module"); |
| 2480 | try expectIdent(access.child, "VAR"); |
| 2481 | } |
| 2482 | } |
| 2483 | |
| 2484 | /// Test that assignment syntax requires the `set` statement. |
| 2485 | @test unsafe fn testAssignmentRequiresSetKeyword() throws (testing::TestError) { |
| 2486 | let assign: ?*ast::Node = try? parseStmtStr("x = 1;"); |
| 2487 | try testing::expect(assign == nil); |
| 2488 | |
| 2489 | let compoundAssign: ?*ast::Node = try? parseStmtStr("x += 1;"); |
| 2490 | try testing::expect(compoundAssign == nil); |
| 2491 | } |
| 2492 | |
| 2493 | /// Test that `set` requires an assignable target. |
| 2494 | @test unsafe fn testSetRequiresAssignableTarget() throws (testing::TestError) { |
| 2495 | let binTarget: ?*ast::Node = try? parseStmtStr("set x + y = 1;"); |
| 2496 | try testing::expect(binTarget == nil); |
| 2497 | |
| 2498 | let condTarget: ?*ast::Node = try? parseStmtStr("set x if ok else y = 1;"); |
| 2499 | try testing::expect(condTarget == nil); |
| 2500 | } |
| 2501 | |
| 2502 | /// Test parsing basic arithmetic binary operators (+, -, *, /, %). |
| 2503 | @test unsafe fn testParseBinOpArithmetic() throws (testing::TestError) { |
| 2504 | let add = try! parseExprStr("a + b"); |
| 2505 | let case ast::NodeValue::BinOp(op1) = add.value |
| 2506 | else throw testing::TestError::Failed; |
| 2507 | try testing::expect(op1.op == ast::BinaryOp::Add); |
| 2508 | try expectIdent(op1.left, "a"); |
| 2509 | try expectIdent(op1.right, "b"); |
| 2510 | |
| 2511 | let sub = try! parseExprStr("x - y"); |
| 2512 | let case ast::NodeValue::BinOp(op2) = sub.value |
| 2513 | else throw testing::TestError::Failed; |
| 2514 | try testing::expect(op2.op == ast::BinaryOp::Sub); |
| 2515 | |
| 2516 | let mul = try! parseExprStr("a * b"); |
| 2517 | let case ast::NodeValue::BinOp(op3) = mul.value |
| 2518 | else throw testing::TestError::Failed; |
| 2519 | try testing::expect(op3.op == ast::BinaryOp::Mul); |
| 2520 | |
| 2521 | let div = try! parseExprStr("x / y"); |
| 2522 | let case ast::NodeValue::BinOp(op4) = div.value |
| 2523 | else throw testing::TestError::Failed; |
| 2524 | try testing::expect(op4.op == ast::BinaryOp::Div); |
| 2525 | |
| 2526 | let modOp = try! parseExprStr("a % b"); |
| 2527 | let case ast::NodeValue::BinOp(op5) = modOp.value |
| 2528 | else throw testing::TestError::Failed; |
| 2529 | try testing::expect(op5.op == ast::BinaryOp::Mod); |
| 2530 | } |
| 2531 | |
| 2532 | /// Test parsing comparison binary operators (==, <>). |
| 2533 | @test unsafe fn testParseBinOpEq() throws (testing::TestError) { |
| 2534 | let eq = try! parseExprStr("a == b"); |
| 2535 | let case ast::NodeValue::BinOp(op1) = eq.value |
| 2536 | else throw testing::TestError::Failed; |
| 2537 | try testing::expect(op1.op == ast::BinaryOp::Eq); |
| 2538 | |
| 2539 | let ne = try! parseExprStr("x <> y"); |
| 2540 | let case ast::NodeValue::BinOp(op2) = ne.value |
| 2541 | else throw testing::TestError::Failed; |
| 2542 | try testing::expect(op2.op == ast::BinaryOp::Ne); |
| 2543 | } |
| 2544 | |
| 2545 | /// Test parsing comparison binary operators. |
| 2546 | @test unsafe fn testParseBinOpGtLt() throws (testing::TestError) { |
| 2547 | let lt = try! parseExprStr("a < b"); |
| 2548 | let case ast::NodeValue::BinOp(op1) = lt.value |
| 2549 | else throw testing::TestError::Failed; |
| 2550 | try testing::expect(op1.op == ast::BinaryOp::Lt); |
| 2551 | |
| 2552 | let gt = try! parseExprStr("x > y"); |
| 2553 | let case ast::NodeValue::BinOp(op2) = gt.value |
| 2554 | else throw testing::TestError::Failed; |
| 2555 | try testing::expect(op2.op == ast::BinaryOp::Gt); |
| 2556 | |
| 2557 | let lte = try! parseExprStr("a <= b"); |
| 2558 | let case ast::NodeValue::BinOp(op3) = lte.value |
| 2559 | else throw testing::TestError::Failed; |
| 2560 | try testing::expect(op3.op == ast::BinaryOp::Lte); |
| 2561 | |
| 2562 | let gte = try! parseExprStr("x >= y"); |
| 2563 | let case ast::NodeValue::BinOp(op4) = gte.value |
| 2564 | else throw testing::TestError::Failed; |
| 2565 | try testing::expect(op4.op == ast::BinaryOp::Gte); |
| 2566 | } |
| 2567 | |
| 2568 | /// Test parsing bitwise binary operators (&, |, ^, <<, >>). |
| 2569 | @test unsafe fn testParseBinOpBitwise() throws (testing::TestError) { |
| 2570 | let bitAnd = try! parseExprStr("a & b"); |
| 2571 | let case ast::NodeValue::BinOp(op1) = bitAnd.value |
| 2572 | else throw testing::TestError::Failed; |
| 2573 | try testing::expect(op1.op == ast::BinaryOp::BitAnd); |
| 2574 | |
| 2575 | let bitOr = try! parseExprStr("x | y"); |
| 2576 | let case ast::NodeValue::BinOp(op2) = bitOr.value |
| 2577 | else throw testing::TestError::Failed; |
| 2578 | try testing::expect(op2.op == ast::BinaryOp::BitOr); |
| 2579 | |
| 2580 | let bitXor = try! parseExprStr("a ^ b"); |
| 2581 | let case ast::NodeValue::BinOp(op3) = bitXor.value |
| 2582 | else throw testing::TestError::Failed; |
| 2583 | try testing::expect(op3.op == ast::BinaryOp::BitXor); |
| 2584 | |
| 2585 | let shl = try! parseExprStr("x << y"); |
| 2586 | let case ast::NodeValue::BinOp(op4) = shl.value |
| 2587 | else throw testing::TestError::Failed; |
| 2588 | try testing::expect(op4.op == ast::BinaryOp::Shl); |
| 2589 | |
| 2590 | let shr = try! parseExprStr("a >> b"); |
| 2591 | let case ast::NodeValue::BinOp(op5) = shr.value |
| 2592 | else throw testing::TestError::Failed; |
| 2593 | try testing::expect(op5.op == ast::BinaryOp::Shr); |
| 2594 | } |
| 2595 | |
| 2596 | /// Test parsing logical binary operators (and, or). |
| 2597 | @test unsafe fn testParseBinOpLogical() throws (testing::TestError) { |
| 2598 | let andOp = try! parseExprStr("a and b"); |
| 2599 | let case ast::NodeValue::BinOp(op1) = andOp.value |
| 2600 | else throw testing::TestError::Failed; |
| 2601 | try testing::expect(op1.op == ast::BinaryOp::And); |
| 2602 | try expectIdent(op1.left, "a"); |
| 2603 | try expectIdent(op1.right, "b"); |
| 2604 | |
| 2605 | let orOp = try! parseExprStr("x or y"); |
| 2606 | let case ast::NodeValue::BinOp(op2) = orOp.value |
| 2607 | else throw testing::TestError::Failed; |
| 2608 | try testing::expect(op2.op == ast::BinaryOp::Or); |
| 2609 | try expectIdent(op2.left, "x"); |
| 2610 | try expectIdent(op2.right, "y"); |
| 2611 | } |
| 2612 | |
| 2613 | /// Test operator precedence: multiplication before addition. |
| 2614 | @test unsafe fn testParseBinOpPrecedenceMulAdd() throws (testing::TestError) { |
| 2615 | let root = try! parseExprStr("a + b * c"); |
| 2616 | let case ast::NodeValue::BinOp(add) = root.value |
| 2617 | else throw testing::TestError::Failed; |
| 2618 | |
| 2619 | try testing::expect(add.op == ast::BinaryOp::Add); |
| 2620 | try expectIdent(add.left, "a"); |
| 2621 | |
| 2622 | let case ast::NodeValue::BinOp(mul) = add.right.value |
| 2623 | else throw testing::TestError::Failed; |
| 2624 | |
| 2625 | try testing::expect(mul.op == ast::BinaryOp::Mul); |
| 2626 | try expectIdent(mul.left, "b"); |
| 2627 | try expectIdent(mul.right, "c"); |
| 2628 | } |
| 2629 | |
| 2630 | /// Test operator precedence: shifts before bitwise operations. |
| 2631 | @test unsafe fn testParseBinOpPrecedenceShiftBitwise() throws (testing::TestError) { |
| 2632 | let root = try! parseExprStr("a & b << c"); |
| 2633 | let case ast::NodeValue::BinOp(bitAnd) = root.value |
| 2634 | else throw testing::TestError::Failed; |
| 2635 | |
| 2636 | try testing::expect(bitAnd.op == ast::BinaryOp::BitAnd); |
| 2637 | try expectIdent(bitAnd.left, "a"); |
| 2638 | |
| 2639 | let case ast::NodeValue::BinOp(shl) = bitAnd.right.value |
| 2640 | else throw testing::TestError::Failed; |
| 2641 | |
| 2642 | try testing::expect(shl.op == ast::BinaryOp::Shl); |
| 2643 | try expectIdent(shl.left, "b"); |
| 2644 | try expectIdent(shl.right, "c"); |
| 2645 | } |
| 2646 | |
| 2647 | /// Test operator precedence: comparison before logical AND. |
| 2648 | @test unsafe fn testParseBinOpPrecedenceCompareLogical() throws (testing::TestError) { |
| 2649 | let root = try! parseExprStr("a < b and c > d"); |
| 2650 | let case ast::NodeValue::BinOp(andOp) = root.value |
| 2651 | else throw testing::TestError::Failed; |
| 2652 | |
| 2653 | try testing::expect(andOp.op == ast::BinaryOp::And); |
| 2654 | |
| 2655 | let case ast::NodeValue::BinOp(lt) = andOp.left.value |
| 2656 | else throw testing::TestError::Failed; |
| 2657 | try testing::expect(lt.op == ast::BinaryOp::Lt); |
| 2658 | try expectIdent(lt.left, "a"); |
| 2659 | try expectIdent(lt.right, "b"); |
| 2660 | |
| 2661 | let case ast::NodeValue::BinOp(gt) = andOp.right.value |
| 2662 | else throw testing::TestError::Failed; |
| 2663 | try testing::expect(gt.op == ast::BinaryOp::Gt); |
| 2664 | try expectIdent(gt.left, "c"); |
| 2665 | try expectIdent(gt.right, "d"); |
| 2666 | } |
| 2667 | |
| 2668 | /// Test left associativity of addition. |
| 2669 | @test unsafe fn testParseBinOpAssociativityAdd() throws (testing::TestError) { |
| 2670 | let root = try! parseExprStr("a + b + c"); |
| 2671 | let case ast::NodeValue::BinOp(add2) = root.value |
| 2672 | else throw testing::TestError::Failed; |
| 2673 | |
| 2674 | try testing::expect(add2.op == ast::BinaryOp::Add); |
| 2675 | try expectIdent(add2.right, "c"); |
| 2676 | |
| 2677 | let case ast::NodeValue::BinOp(add1) = add2.left.value |
| 2678 | else throw testing::TestError::Failed; |
| 2679 | try testing::expect(add1.op == ast::BinaryOp::Add); |
| 2680 | try expectIdent(add1.left, "a"); |
| 2681 | try expectIdent(add1.right, "b"); |
| 2682 | } |
| 2683 | |
| 2684 | /// Test complex expression with multiple operators and precedence. |
| 2685 | @test unsafe fn testParseBinOpComplex() throws (testing::TestError) { |
| 2686 | let root = try! parseExprStr("a + b * c - d / e"); |
| 2687 | let case ast::NodeValue::BinOp(sub) = root.value |
| 2688 | else throw testing::TestError::Failed; |
| 2689 | |
| 2690 | try testing::expect(sub.op == ast::BinaryOp::Sub); |
| 2691 | |
| 2692 | let case ast::NodeValue::BinOp(add) = sub.left.value |
| 2693 | else throw testing::TestError::Failed; |
| 2694 | try testing::expect(add.op == ast::BinaryOp::Add); |
| 2695 | try expectIdent(add.left, "a"); |
| 2696 | |
| 2697 | let case ast::NodeValue::BinOp(mul) = add.right.value |
| 2698 | else throw testing::TestError::Failed; |
| 2699 | try testing::expect(mul.op == ast::BinaryOp::Mul); |
| 2700 | |
| 2701 | let case ast::NodeValue::BinOp(div) = sub.right.value |
| 2702 | else throw testing::TestError::Failed; |
| 2703 | try testing::expect(div.op == ast::BinaryOp::Div); |
| 2704 | } |
| 2705 | |
| 2706 | /// Test binary operators with parentheses override precedence. |
| 2707 | @test unsafe fn testParseBinOpParentheses() throws (testing::TestError) { |
| 2708 | let root = try! parseExprStr("(a + b) * c"); |
| 2709 | let case ast::NodeValue::BinOp(mul) = root.value |
| 2710 | else throw testing::TestError::Failed; |
| 2711 | |
| 2712 | try testing::expect(mul.op == ast::BinaryOp::Mul); |
| 2713 | try expectIdent(mul.right, "c"); |
| 2714 | |
| 2715 | let case ast::NodeValue::BinOp(add) = mul.left.value |
| 2716 | else throw testing::TestError::Failed; |
| 2717 | try testing::expect(add.op == ast::BinaryOp::Add); |
| 2718 | try expectIdent(add.left, "a"); |
| 2719 | try expectIdent(add.right, "b"); |
| 2720 | } |
| 2721 | |
| 2722 | /// Test parsing a simple union without payloads. |
| 2723 | @test unsafe fn testParseEnumSimple() throws (testing::TestError) { |
| 2724 | let node = try! parseStmtStr("union Color { Red, Green, Blue }"); |
| 2725 | let case ast::NodeValue::UnionDecl(decl) = node.value |
| 2726 | else throw testing::TestError::Failed; |
| 2727 | |
| 2728 | try expectIdent(decl.name, "Color"); |
| 2729 | try testing::expect(decl.derives.len == 0); |
| 2730 | |
| 2731 | let variants = decl.variants; |
| 2732 | try testing::expect(variants.len == 3); |
| 2733 | |
| 2734 | let v0 = variants[0]; |
| 2735 | let case ast::NodeValue::UnionDeclVariant(var0) = v0.value |
| 2736 | else throw testing::TestError::Failed; |
| 2737 | try expectIdent(var0.name, "Red"); |
| 2738 | try testing::expect(var0.index == 0); |
| 2739 | try testing::expect(var0.type == nil); |
| 2740 | try testing::expect(var0.value == nil); |
| 2741 | |
| 2742 | let v1 = variants[1]; |
| 2743 | let case ast::NodeValue::UnionDeclVariant(var1) = v1.value |
| 2744 | else throw testing::TestError::Failed; |
| 2745 | try expectIdent(var1.name, "Green"); |
| 2746 | try testing::expect(var1.index == 1); |
| 2747 | try testing::expect(var1.type == nil); |
| 2748 | try testing::expect(var1.value == nil); |
| 2749 | |
| 2750 | let v2 = variants[2]; |
| 2751 | let case ast::NodeValue::UnionDeclVariant(var2) = v2.value |
| 2752 | else throw testing::TestError::Failed; |
| 2753 | try expectIdent(var2.name, "Blue"); |
| 2754 | try testing::expect(var2.index == 2); |
| 2755 | try testing::expect(var2.type == nil); |
| 2756 | try testing::expect(var2.value == nil); |
| 2757 | } |
| 2758 | |
| 2759 | /// Test parsing a union with trailing comma. |
| 2760 | @test unsafe fn testParseEnumTrailingComma() throws (testing::TestError) { |
| 2761 | let node = try! parseStmtStr("union Letter { A, B, C, }"); |
| 2762 | let case ast::NodeValue::UnionDecl(decl) = node.value |
| 2763 | else throw testing::TestError::Failed; |
| 2764 | |
| 2765 | try expectIdent(decl.name, "Letter"); |
| 2766 | try testing::expect(decl.variants.len == 3); |
| 2767 | } |
| 2768 | |
| 2769 | /// Test parsing a union with explicit values. |
| 2770 | @test unsafe fn testParseEnumExplicitValues() throws (testing::TestError) { |
| 2771 | let node = try! parseStmtStr("union Status { Ok = 0, Error = 1, Pending = 5 }"); |
| 2772 | let case ast::NodeValue::UnionDecl(decl) = node.value |
| 2773 | else throw testing::TestError::Failed; |
| 2774 | |
| 2775 | try expectIdent(decl.name, "Status"); |
| 2776 | |
| 2777 | let variants = decl.variants; |
| 2778 | try testing::expect(variants.len == 3); |
| 2779 | |
| 2780 | let v0 = variants[0]; |
| 2781 | let case ast::NodeValue::UnionDeclVariant(var0) = v0.value |
| 2782 | else throw testing::TestError::Failed; |
| 2783 | try expectIdent(var0.name, "Ok"); |
| 2784 | try testing::expect(var0.index == 0); |
| 2785 | try testing::expect(var0.type == nil); |
| 2786 | try testing::expect(var0.value <> nil); |
| 2787 | |
| 2788 | let v1 = variants[1]; |
| 2789 | let case ast::NodeValue::UnionDeclVariant(var1) = v1.value |
| 2790 | else throw testing::TestError::Failed; |
| 2791 | try expectIdent(var1.name, "Error"); |
| 2792 | try testing::expect(var1.index == 1); |
| 2793 | try testing::expect(var1.value <> nil); |
| 2794 | |
| 2795 | let v2 = variants[2]; |
| 2796 | let case ast::NodeValue::UnionDeclVariant(var2) = v2.value |
| 2797 | else throw testing::TestError::Failed; |
| 2798 | try expectIdent(var2.name, "Pending"); |
| 2799 | try testing::expect(var2.index == 2); |
| 2800 | try testing::expect(var2.value <> nil); |
| 2801 | } |
| 2802 | |
| 2803 | /// Test parsing a union with payload and tag-only variants. |
| 2804 | @test unsafe fn testParseEnumWithPayloads() throws (testing::TestError) { |
| 2805 | let node = try! parseStmtStr("union Result { Ok(bool), Error }"); |
| 2806 | let case ast::NodeValue::UnionDecl(decl) = node.value |
| 2807 | else throw testing::TestError::Failed; |
| 2808 | |
| 2809 | try expectIdent(decl.name, "Result"); |
| 2810 | try testing::expect(decl.variants.len == 2); |
| 2811 | |
| 2812 | let okFields = try expectVariant(decl.variants[0], "Ok", 0) |
| 2813 | else throw testing::TestError::Failed; |
| 2814 | try testing::expect(okFields.len == 1); |
| 2815 | try expectFieldSig(okFields, 0, nil, ast::TypeSig::Bool); |
| 2816 | |
| 2817 | let errFields = try expectVariant(decl.variants[1], "Error", 1); |
| 2818 | try testing::expect(errFields == nil); |
| 2819 | } |
| 2820 | |
| 2821 | /// Test parsing a union with derives. |
| 2822 | @test unsafe fn testParseEnumWithDerives() throws (testing::TestError) { |
| 2823 | let node = try! parseStmtStr("union Option: Debug + Eq { None, Some(i32) }"); |
| 2824 | let case ast::NodeValue::UnionDecl(decl) = node.value |
| 2825 | else throw testing::TestError::Failed; |
| 2826 | |
| 2827 | try expectIdent(decl.name, "Option"); |
| 2828 | try testing::expect(decl.derives.len == 2); |
| 2829 | try expectIdent(decl.derives[0], "Debug"); |
| 2830 | try expectIdent(decl.derives[1], "Eq"); |
| 2831 | |
| 2832 | let variants = decl.variants; |
| 2833 | try testing::expect(variants.len == 2); |
| 2834 | |
| 2835 | let v0 = variants[0]; |
| 2836 | let case ast::NodeValue::UnionDeclVariant(var0) = v0.value |
| 2837 | else throw testing::TestError::Failed; |
| 2838 | try expectIdent(var0.name, "None"); |
| 2839 | try testing::expect(var0.type == nil); |
| 2840 | |
| 2841 | let v1 = variants[1]; |
| 2842 | let case ast::NodeValue::UnionDeclVariant(var1) = v1.value |
| 2843 | else throw testing::TestError::Failed; |
| 2844 | try expectIdent(var1.name, "Some"); |
| 2845 | try testing::expect(var1.type <> nil); |
| 2846 | } |
| 2847 | |
| 2848 | /// Test parsing named record literals with named fields. |
| 2849 | @test unsafe fn testParseNamedRecordLiteralNamed() throws (testing::TestError) { |
| 2850 | let r1 = try! parseExprStr("Point { x: 5, y: 10 }"); |
| 2851 | let case ast::NodeValue::RecordLit(lit) = r1.value |
| 2852 | else throw testing::TestError::Failed; |
| 2853 | |
| 2854 | let typeName = lit.typeName else throw testing::TestError::Failed; |
| 2855 | try expectIdent(typeName, "Point"); |
| 2856 | try testing::expect(lit.fields.len == 2); |
| 2857 | |
| 2858 | let field0 = lit.fields[0]; |
| 2859 | let case ast::NodeValue::RecordLitField(arg0) = field0.value |
| 2860 | else throw testing::TestError::Failed; |
| 2861 | let label0 = arg0.label else throw testing::TestError::Failed; |
| 2862 | try expectIdent(label0, "x"); |
| 2863 | try expectNumber(arg0.value, "5"); |
| 2864 | } |
| 2865 | |
| 2866 | /// Test parsing anonymous record literals with named fields. |
| 2867 | @test unsafe fn testParseAnonymousRecordLiteralNamed() throws (testing::TestError) { |
| 2868 | let r1 = try! parseExprStr("{ x: 10, y: 20 }"); |
| 2869 | let case ast::NodeValue::RecordLit(lit) = r1.value |
| 2870 | else throw testing::TestError::Failed; |
| 2871 | |
| 2872 | try testing::expect(lit.typeName == nil); |
| 2873 | try testing::expect(lit.fields.len == 2); |
| 2874 | |
| 2875 | let field0 = lit.fields[0]; |
| 2876 | let case ast::NodeValue::RecordLitField(arg0) = field0.value |
| 2877 | else throw testing::TestError::Failed; |
| 2878 | let label0 = arg0.label else throw testing::TestError::Failed; |
| 2879 | try expectIdent(label0, "x"); |
| 2880 | try expectNumber(arg0.value, "10"); |
| 2881 | |
| 2882 | let field1 = lit.fields[1]; |
| 2883 | let case ast::NodeValue::RecordLitField(arg1) = field1.value |
| 2884 | else throw testing::TestError::Failed; |
| 2885 | let label1 = arg1.label else throw testing::TestError::Failed; |
| 2886 | try expectIdent(label1, "y"); |
| 2887 | try expectNumber(arg1.value, "20"); |
| 2888 | } |
| 2889 | |
| 2890 | /// Test parsing record literals with shorthand field syntax. |
| 2891 | /// `{ x, y }` is equivalent to `{ x: x, y: y }`. |
| 2892 | @test unsafe fn testParseRecordLiteralShorthand() throws (testing::TestError) { |
| 2893 | let r1 = try! parseExprStr("Point { x, y }"); |
| 2894 | let case ast::NodeValue::RecordLit(lit) = r1.value |
| 2895 | else throw testing::TestError::Failed; |
| 2896 | |
| 2897 | let typeName = lit.typeName else throw testing::TestError::Failed; |
| 2898 | try expectIdent(typeName, "Point"); |
| 2899 | try testing::expect(lit.fields.len == 2); |
| 2900 | |
| 2901 | // First field: shorthand `x`. |
| 2902 | let field0 = lit.fields[0]; |
| 2903 | let case ast::NodeValue::RecordLitField(arg0) = field0.value |
| 2904 | else throw testing::TestError::Failed; |
| 2905 | let label0 = arg0.label else throw testing::TestError::Failed; |
| 2906 | try expectIdent(label0, "x"); |
| 2907 | try expectIdent(arg0.value, "x"); |
| 2908 | // Label and value should point to the same node. |
| 2909 | try testing::expect(label0 == arg0.value); |
| 2910 | |
| 2911 | // Second field: shorthand `y`. |
| 2912 | let field1 = lit.fields[1]; |
| 2913 | let case ast::NodeValue::RecordLitField(arg1) = field1.value |
| 2914 | else throw testing::TestError::Failed; |
| 2915 | let label1 = arg1.label else throw testing::TestError::Failed; |
| 2916 | try expectIdent(label1, "y"); |
| 2917 | try expectIdent(arg1.value, "y"); |
| 2918 | try testing::expect(label1 == arg1.value); |
| 2919 | } |
| 2920 | |
| 2921 | /// Test parsing record literals with mixed shorthand and explicit fields. |
| 2922 | @test unsafe fn testParseRecordLiteralMixedShorthand() throws (testing::TestError) { |
| 2923 | let r1 = try! parseExprStr("Point { x, y: 10 }"); |
| 2924 | let case ast::NodeValue::RecordLit(lit) = r1.value |
| 2925 | else throw testing::TestError::Failed; |
| 2926 | |
| 2927 | try testing::expect(lit.fields.len == 2); |
| 2928 | |
| 2929 | // First field: shorthand `x`. |
| 2930 | let field0 = lit.fields[0]; |
| 2931 | let case ast::NodeValue::RecordLitField(arg0) = field0.value |
| 2932 | else throw testing::TestError::Failed; |
| 2933 | let label0 = arg0.label else throw testing::TestError::Failed; |
| 2934 | try expectIdent(label0, "x"); |
| 2935 | try expectIdent(arg0.value, "x"); |
| 2936 | |
| 2937 | // Second field: explicit `y: 10`. |
| 2938 | let field1 = lit.fields[1]; |
| 2939 | let case ast::NodeValue::RecordLitField(arg1) = field1.value |
| 2940 | else throw testing::TestError::Failed; |
| 2941 | let label1 = arg1.label else throw testing::TestError::Failed; |
| 2942 | try expectIdent(label1, "y"); |
| 2943 | try expectNumber(arg1.value, "10"); |
| 2944 | } |
| 2945 | |
| 2946 | /// Test that positional brace initializers are rejected: `{ 1, 2 }`. |
| 2947 | @test unsafe fn testParsePositionalBraceInitializerAnonymous() throws (testing::TestError) { |
| 2948 | let parsed: ?*ast::Node = try? parseExprStr("{ 1, 2 }"); |
| 2949 | try testing::expect(parsed == nil); |
| 2950 | } |
| 2951 | |
| 2952 | /// Test that positional brace initializers are rejected: `Point { 1, 2 }`. |
| 2953 | @test unsafe fn testParsePositionalBraceInitializerNamed() throws (testing::TestError) { |
| 2954 | let parsed: ?*ast::Node = try? parseExprStr("Point { 1, 2 }"); |
| 2955 | try testing::expect(parsed == nil); |
| 2956 | } |
| 2957 | |
| 2958 | /// Test that mixed labeled/positional brace initializers are rejected: `Pt { x: 1, 2 }`. |
| 2959 | @test unsafe fn testParseMixedBraceInitializer() throws (testing::TestError) { |
| 2960 | let parsed: ?*ast::Node = try? parseExprStr("Pt { x: 1, 2 }"); |
| 2961 | try testing::expect(parsed == nil); |
| 2962 | } |
| 2963 | |
| 2964 | /// Unsafe statements have a block body. |
| 2965 | @test unsafe fn testParseUnsafeBlock() throws (testing::TestError) { |
| 2966 | let parsed = try? parseStmtsStr("fn run() { unsafe { return; } }"); |
| 2967 | let root = parsed else throw testing::TestError::Failed; |
| 2968 | let case ast::NodeValue::Block(module) = root.value |
| 2969 | else throw testing::TestError::Failed; |
| 2970 | let case ast::NodeValue::FnDecl(decl) = module.statements[0].value |
| 2971 | else throw testing::TestError::Failed; |
| 2972 | let fnBody = decl.body else throw testing::TestError::Failed; |
| 2973 | let case ast::NodeValue::Block(body) = fnBody.value |
| 2974 | else throw testing::TestError::Failed; |
| 2975 | let case ast::NodeValue::Block(inner) = body.statements[0].value |
| 2976 | else throw testing::TestError::Failed; |
| 2977 | try testing::expect(not body.isUnsafe); |
| 2978 | try testing::expect(inner.isUnsafe); |
| 2979 | } |
| 2980 | |
| 2981 | /// Unsafe blocks do not accept declaration attributes. |
| 2982 | @test unsafe fn testUnsafeBlockAttributesRejected() throws (testing::TestError) { |
| 2983 | let parsed = try? parseStmtsStr("fn run() { export unsafe {} }"); |
| 2984 | try testing::expect(parsed == nil); |
| 2985 | } |
| 2986 | |
| 2987 | /// Unsafe static declarations carry an explicit access requirement. |
| 2988 | @test unsafe fn testParseUnsafeStatic() throws (testing::TestError) { |
| 2989 | let parsed = try? parseStmtsStr("export unsafe static DATA: [u8; 4] = undefined;"); |
| 2990 | try testing::expect(parsed <> nil); |
| 2991 | } |
| 2992 | |
| 2993 | @test unsafe fn testParseModule() throws (testing::TestError) { |
| 2994 | let r = try! parseStmtsStr("fn f() {} fn g() {}"); |
| 2995 | |
| 2996 | let case ast::NodeValue::Block(module) = r.value |
| 2997 | else throw testing::TestError::Failed; |
| 2998 | try testing::expect(module.statements.len == 2); |
| 2999 | |
| 3000 | let first = module.statements[0]; |
| 3001 | let case ast::NodeValue::FnDecl(fDecl) = first.value |
| 3002 | else throw testing::TestError::Failed; |
| 3003 | try expectIdent(fDecl.name, "f"); |
| 3004 | |
| 3005 | let second = module.statements[1]; |
| 3006 | let case ast::NodeValue::FnDecl(gDecl) = second.value |
| 3007 | else throw testing::TestError::Failed; |
| 3008 | try expectIdent(gDecl.name, "g"); |
| 3009 | } |
| 3010 | |
| 3011 | /// Test parsing a simple conditional expression. |
| 3012 | @test unsafe fn testParseCondExpr() throws (testing::TestError) { |
| 3013 | let r = try! parseExprStr("a if cond else b") catch { |
| 3014 | throw testing::TestError::Failed; |
| 3015 | }; |
| 3016 | let case ast::NodeValue::CondExpr(cond) = r.value |
| 3017 | else throw testing::TestError::Failed; |
| 3018 | |
| 3019 | try expectIdent(cond.thenExpr, "a"); |
| 3020 | try expectIdent(cond.condition, "cond"); |
| 3021 | try expectIdent(cond.elseExpr, "b"); |
| 3022 | } |
| 3023 | |
| 3024 | /// Test parsing a conditional expression with `as` casts. |
| 3025 | @test unsafe fn testParseCondExprWithAsCast() throws (testing::TestError) { |
| 3026 | let r = try! parseExprStr("x as i32 if cond else y as i32") catch { |
| 3027 | throw testing::TestError::Failed; |
| 3028 | }; |
| 3029 | let case ast::NodeValue::CondExpr(cond) = r.value |
| 3030 | else throw testing::TestError::Failed; |
| 3031 | |
| 3032 | // Check thenExpr is an `as` cast. |
| 3033 | let case ast::NodeValue::As(thenAs) = cond.thenExpr.value |
| 3034 | else throw testing::TestError::Failed; |
| 3035 | try expectIdent(thenAs.value, "x"); |
| 3036 | try expectIntType(thenAs.type, 4, ast::Signedness::Signed); |
| 3037 | |
| 3038 | // Check condition. |
| 3039 | try expectIdent(cond.condition, "cond"); |
| 3040 | |
| 3041 | // Check elseExpr is an `as` cast. |
| 3042 | let case ast::NodeValue::As(elseAs) = cond.elseExpr.value |
| 3043 | else throw testing::TestError::Failed; |
| 3044 | try expectIdent(elseAs.value, "y"); |
| 3045 | try expectIntType(elseAs.type, 4, ast::Signedness::Signed); |
| 3046 | } |
| 3047 | |
| 3048 | /// Test parsing a nested conditional expression (right-associative). |
| 3049 | @test unsafe fn testParseCondExprNested() throws (testing::TestError) { |
| 3050 | let r = try! parseExprStr("a if x else b if y else c") catch { |
| 3051 | throw testing::TestError::Failed; |
| 3052 | }; |
| 3053 | let case ast::NodeValue::CondExpr(outer) = r.value |
| 3054 | else throw testing::TestError::Failed; |
| 3055 | |
| 3056 | try expectIdent(outer.thenExpr, "a"); |
| 3057 | try expectIdent(outer.condition, "x"); |
| 3058 | |
| 3059 | // The else branch should be another conditional expression. |
| 3060 | let case ast::NodeValue::CondExpr(inner) = outer.elseExpr.value |
| 3061 | else throw testing::TestError::Failed; |
| 3062 | |
| 3063 | try expectIdent(inner.thenExpr, "b"); |
| 3064 | try expectIdent(inner.condition, "y"); |
| 3065 | try expectIdent(inner.elseExpr, "c"); |
| 3066 | } |
| 3067 | |
| 3068 | /// Test that trailing commas are allowed in all comma-separated lists. |
| 3069 | @test unsafe fn testTrailingCommas() throws (testing::TestError) { |
| 3070 | // Function call arguments. |
| 3071 | let call = try! parseExprStr("f(1, 2, 3,)"); |
| 3072 | let case ast::NodeValue::Call(c) = call.value else throw testing::TestError::Failed; |
| 3073 | try testing::expect(c.args.len == 3); |
| 3074 | |
| 3075 | // Function parameters. |
| 3076 | let fnNode = try! parseStmtStr("fn add(x: i32, y: i32,) {}"); |
| 3077 | let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value else throw testing::TestError::Failed; |
| 3078 | try testing::expect(fnDecl.sig.params.len == 2); |
| 3079 | |
| 3080 | // Record declarations. |
| 3081 | let recNode = try! parseStmtStr("record R { x: i32, y: bool, }"); |
| 3082 | let case ast::NodeValue::RecordDecl(recDecl) = recNode.value else throw testing::TestError::Failed; |
| 3083 | try testing::expect(recDecl.fields.len == 2); |
| 3084 | |
| 3085 | // Tuple record declarations. |
| 3086 | let tupNode = try! parseStmtStr("record R(i32, bool,);"); |
| 3087 | let case ast::NodeValue::RecordDecl(tupDecl) = tupNode.value else throw testing::TestError::Failed; |
| 3088 | try testing::expect(tupDecl.fields.len == 2); |
| 3089 | |
| 3090 | // Record literals. |
| 3091 | let litNode = try! parseExprStr("Point { x: 1, y: 2, }"); |
| 3092 | let case ast::NodeValue::RecordLit(lit) = litNode.value else throw testing::TestError::Failed; |
| 3093 | try testing::expect(lit.fields.len == 2); |
| 3094 | |
| 3095 | // Union declarations. |
| 3096 | let unionNode = try! parseStmtStr("union Color { Red, Green, Blue, }"); |
| 3097 | let case ast::NodeValue::UnionDecl(unionDecl) = unionNode.value else throw testing::TestError::Failed; |
| 3098 | try testing::expect(unionDecl.variants.len == 3); |
| 3099 | |
| 3100 | // Array literals. |
| 3101 | let arrNode = try! parseExprStr("[1, 2, 3,]"); |
| 3102 | let case ast::NodeValue::ArrayLit(items) = arrNode.value else throw testing::TestError::Failed; |
| 3103 | try testing::expect(items.len == 3); |
| 3104 | |
| 3105 | // Function type parameters. |
| 3106 | let fnType = try! parseTypeStr("fn (i32, bool,)"); |
| 3107 | let case ast::NodeValue::TypeSig(sigValue) = fnType.value else throw testing::TestError::Failed; |
| 3108 | let case ast::TypeSig::Fn { sig, .. } = sigValue else throw testing::TestError::Failed; |
| 3109 | try testing::expect(sig.params.len == 2); |
| 3110 | try testing::expect(sig.returnType == nil); |
| 3111 | |
| 3112 | // Throws lists. |
| 3113 | let throwsNode = try! parseStmtStr("fn handle() throws (Error, Other,) {}"); |
| 3114 | let case ast::NodeValue::FnDecl(throwsDecl) = throwsNode.value else throw testing::TestError::Failed; |
| 3115 | try testing::expect(throwsDecl.sig.throwList.len == 2); |
| 3116 | } |
| 3117 | |
| 3118 | /// Function declarations and function types accept never return annotations. |
| 3119 | @test unsafe fn testParseNeverReturn() throws (testing::TestError) { |
| 3120 | let declNode = try! parseStmtStr("fn stop() -> ! { panic; }"); |
| 3121 | let case ast::NodeValue::FnDecl(decl) = declNode.value else throw testing::TestError::Failed; |
| 3122 | let ret = decl.sig.returnType else throw testing::TestError::Failed; |
| 3123 | assert ret.value == ast::NodeValue::TypeSig(ast::TypeSig::Never); |
| 3124 | let fnNode = try! parseTypeStr("unsafe fn(u64) -> ! throws (Error)"); |
| 3125 | let case ast::NodeValue::TypeSig(ast::TypeSig::Fn { sig, isUnsafe }) = fnNode.value |
| 3126 | else throw testing::TestError::Failed; |
| 3127 | let fnRet = sig.returnType else throw testing::TestError::Failed; |
| 3128 | assert isUnsafe and sig.params.len == 1 and sig.throwList.len == 1; |
| 3129 | assert fnRet.value == ast::NodeValue::TypeSig(ast::TypeSig::Never); |
| 3130 | } |
| 3131 | |
| 3132 | /// Unsafe function types preserve their call requirement and signature. |
| 3133 | @test unsafe fn testParseUnsafeFunctionType() throws (testing::TestError) { |
| 3134 | let node = try! parseTypeStr("unsafe fn(&u32) -> u32 throws (Error)"); |
| 3135 | let case ast::NodeValue::TypeSig(ast::TypeSig::Fn { sig, isUnsafe }) = node.value |
| 3136 | else throw testing::TestError::Failed; |
| 3137 | assert isUnsafe; |
| 3138 | assert sig.params.len == 1; |
| 3139 | assert sig.returnType <> nil; |
| 3140 | assert sig.throwList.len == 1; |
| 3141 | } |
| 3142 | |
| 3143 | /// Region arguments on an inner type remain distinct from a reference region. |
| 3144 | @test unsafe fn testRegionReferenceTypes() throws (testing::TestError) { |
| 3145 | let root = try! parseTypeStr("&'short mut Node 'arena"); |
| 3146 | let case ast::NodeValue::TypeSig(ast::TypeSig::RegionRef { region, type }) = root.value |
| 3147 | else throw testing::TestError::Failed; |
| 3148 | let case ast::NodeValue::Region { name, parent: nil } = region.value |
| 3149 | else throw testing::TestError::Failed; |
| 3150 | try testing::expect(mem::eq(name, "'short")); |
| 3151 | let case ast::NodeValue::TypeSig(ast::TypeSig::Pointer { class, valueType, mutable }) = type.value |
| 3152 | else throw testing::TestError::Failed; |
| 3153 | try testing::expect(class == ast::PointerClass::Ref and mutable); |
| 3154 | let case ast::NodeValue::TypeSig(ast::TypeSig::Applied { name: nominal, regions }) = valueType.value |
| 3155 | else throw testing::TestError::Failed; |
| 3156 | try expectIdent(nominal, "Node"); |
| 3157 | try testing::expect(regions.len == 1); |
| 3158 | let case ast::NodeValue::Region { name: argument, .. } = regions[0].value |
| 3159 | else throw testing::TestError::Failed; |
| 3160 | try testing::expect(mem::eq(argument, "'arena")); |
| 3161 | let slice = try! parseTypeStr("&'r [View 'a 'b]"); |
| 3162 | let case ast::NodeValue::TypeSig(ast::TypeSig::RegionRef { type: sliceType, .. }) = slice.value |
| 3163 | else throw testing::TestError::Failed; |
| 3164 | let case ast::NodeValue::TypeSig(ast::TypeSig::Slice { .. }) = sliceType.value |
| 3165 | else throw testing::TestError::Failed; |
| 3166 | } |
| 3167 | |
| 3168 | /// Declaration lists accept regions, parent relations, and ownership derives. |
| 3169 | @test unsafe fn testRegionDeclarations() throws (testing::TestError) { |
| 3170 | let parsedRecord = try! parseStmtStr("record View: 'a + 'b + Copy where 'a: 'b { item: &'b u8 }"); |
| 3171 | let case ast::NodeValue::RecordDecl(decl) = parsedRecord.value |
| 3172 | else throw testing::TestError::Failed; |
| 3173 | try testing::expect(decl.regions.len == 2 and decl.derives.len == 1); |
| 3174 | let case ast::NodeValue::Region { parent: parent, .. } = decl.regions[1].value |
| 3175 | else throw testing::TestError::Failed; |
| 3176 | try testing::expect(parent <> nil); |
| 3177 | let func = try! parseStmtStr( |
| 3178 | "fn read 'long 'short (input: &'short u8) -> &'short u8 throws (ReadError) where 'long: 'short { return input; }" |
| 3179 | ); |
| 3180 | let case ast::NodeValue::FnDecl(f) = func.value else throw testing::TestError::Failed; |
| 3181 | try testing::expect(f.regions.len == 2 and f.sig.throwList.len == 1); |
| 3182 | let case ast::NodeValue::Region { name: shortName, parent: shortParent } = f.regions[1].value |
| 3183 | else throw testing::TestError::Failed; |
| 3184 | try testing::expect(mem::eq(shortName, "'short") and shortParent <> nil); |
| 3185 | let parentNode = shortParent else throw testing::TestError::Failed; |
| 3186 | let case ast::NodeValue::Region { name: parentName, parent: nil } = parentNode.value |
| 3187 | else throw testing::TestError::Failed; |
| 3188 | try testing::expect(mem::eq(parentName, "'long")); |
| 3189 | let parsedUnion = try! parseStmtStr("union Result: 'x { Value(&'x u8), Empty }"); |
| 3190 | let case ast::NodeValue::UnionDecl(u) = parsedUnion.value else throw testing::TestError::Failed; |
| 3191 | try testing::expect(u.regions.len == 1 and u.derives.len == 0); |
| 3192 | } |
| 3193 | |
| 3194 | /// Regional blocks retain their source bindings and derived session region. |
| 3195 | @test unsafe fn testRegionBlocks() throws (testing::TestError) { |
| 3196 | let root = try! parseStmtStr("let left: 'r = &mut state.left, right = &state.right in { useView(left); }"); |
| 3197 | let case ast::NodeValue::RegionBlock { bindings, isSession, .. } = root.value |
| 3198 | else throw testing::TestError::Failed; |
| 3199 | try testing::expect(not isSession and bindings.len == 2); |
| 3200 | let nested = try! parseStmtStr("let view: 'inner = &value where 'outer: 'inner in {}"); |
| 3201 | let case ast::NodeValue::RegionBlock { region: nestedRegion, .. } = nested.value |
| 3202 | else throw testing::TestError::Failed; |
| 3203 | let case ast::NodeValue::Region { name: nestedName, parent: nestedParent } = nestedRegion.value |
| 3204 | else throw testing::TestError::Failed; |
| 3205 | let parent = nestedParent else throw testing::TestError::Failed; |
| 3206 | let case ast::NodeValue::Region { name: parentName, parent: nil } = parent.value |
| 3207 | else throw testing::TestError::Failed; |
| 3208 | try testing::expect(mem::eq(nestedName, "'inner") and mem::eq(parentName, "'outer")); |
| 3209 | let arena = try! parseStmtStr("use arena as objects in { make(objects); }"); |
| 3210 | let case ast::NodeValue::RegionBlock { |
| 3211 | region: arenaRegion, bindings: arenaBindings, isSession: arenaSession, .. |
| 3212 | } = arena.value |
| 3213 | else throw testing::TestError::Failed; |
| 3214 | let case ast::NodeValue::Region { name: arenaRegionName, parent: nil } = arenaRegion.value |
| 3215 | else throw testing::TestError::Failed; |
| 3216 | let case ast::NodeValue::RegionBinding(arenaBinding) = arenaBindings[0].value |
| 3217 | else throw testing::TestError::Failed; |
| 3218 | let arenaLabel = arenaBinding.label else throw testing::TestError::Failed; |
| 3219 | let case ast::NodeValue::Ident(arenaLabelName) = arenaLabel.value |
| 3220 | else throw testing::TestError::Failed; |
| 3221 | let case ast::NodeValue::AddressOf({ |
| 3222 | target: arenaTarget, kind: ast::AddressKind::Mutable, permission: nil, |
| 3223 | }) = arenaBinding.value.value |
| 3224 | else throw testing::TestError::Failed; |
| 3225 | let case ast::NodeValue::Ident(arenaTargetName) = arenaTarget.value |
| 3226 | else throw testing::TestError::Failed; |
| 3227 | try testing::expect( |
| 3228 | arenaSession and arenaBindings.len == 1 |
| 3229 | and mem::eq(arenaRegionName, "'objects") |
| 3230 | and mem::eq(arenaLabelName, "objects") |
| 3231 | and mem::eq(arenaTargetName, "arena") |
| 3232 | ); |
| 3233 | } |
| 3234 | |
| 3235 | /// Region grammar rejects incomplete lists and invalid allocation headers. |
| 3236 | @test unsafe fn testMalformedRegionSyntax() throws (testing::TestError) { |
| 3237 | for source in [ |
| 3238 | "fn bad: Copy () {}", |
| 3239 | "record Bad: 'r + {}", |
| 3240 | "let 'r in {}", |
| 3241 | "let p: 'r = value in {}", |
| 3242 | "let 'r p = &value in {}", |
| 3243 | "let 'child < 'parent p = &value in {}", |
| 3244 | "let 'parent as p = &value in {}", |
| 3245 | "let value: 'child = &source where 'parent: 'other in {}", |
| 3246 | "use arena in {}", |
| 3247 | "use arena as in {}", |
| 3248 | "use arena as first, second in {}", |
| 3249 | "use 'r a = &mut arena in {}", |
| 3250 | "use 'r a as &mut arena in {}", |
| 3251 | ] { |
| 3252 | let parsed = try? parseStmtStr(source); |
| 3253 | try testing::expect(parsed == nil); |
| 3254 | } |
| 3255 | for source in ["&'x' u8", "&mut 'x u8", "View '", "&'r"] { |
| 3256 | let parsed = try? parseTypeStr(source); |
| 3257 | try testing::expect(parsed == nil); |
| 3258 | } |
| 3259 | } |
| 3260 | |
| 3261 | /// Ordinary identifiers remain available beside regional block syntax. |
| 3262 | @test unsafe fn testRegionContextualKeywords() throws (testing::TestError) { |
| 3263 | for source in [ |
| 3264 | "let borrow = 1;", |
| 3265 | "let session = 2;", |
| 3266 | "borrow(value);", |
| 3267 | "session(value);", |
| 3268 | "record Context { borrow: u32, session: u32 }", |
| 3269 | ] { |
| 3270 | let parsed = try? parseStmtStr(source); |
| 3271 | try testing::expect(parsed <> nil); |
| 3272 | } |
| 3273 | } |
| 3274 | |
| 3275 | /// The AST printer retains region parameters and qualified reference types. |
| 3276 | @test unsafe fn testPrintRegionSignature() throws (testing::TestError) { |
| 3277 | let root = try! parseStmtStr("fn read 'r (input: &'r u8) -> &'r u8 { return input; }"); |
| 3278 | static PRINT_STORAGE: [u8; 4096] = [0; 4096]; |
| 3279 | let mut arena = alloc::new(&mut PRINT_STORAGE[..]); |
| 3280 | let printed = printer::toExpr(&mut arena, root); |
| 3281 | let case sexpr::Expr::Block { items, .. } = printed |
| 3282 | else throw testing::TestError::Failed; |
| 3283 | try testing::expect(items.len == 4); |
| 3284 | let case sexpr::Expr::List { head, tail, .. } = items[1] |
| 3285 | else throw testing::TestError::Failed; |
| 3286 | try testing::expect(mem::eq(head, "regions") and tail.len == 1); |
| 3287 | let case sexpr::Expr::Sym(name) = tail[0] else throw testing::TestError::Failed; |
| 3288 | try testing::expect(mem::eq(name, "'r")); |
| 3289 | let case sexpr::Expr::List { head: refHead, tail: refTail, .. } = items[3] |
| 3290 | else throw testing::TestError::Failed; |
| 3291 | try testing::expect(mem::eq(refHead, "region-ref") and refTail.len == 2); |
| 3292 | } |
| 3293 | |
| 3294 | /// Explicit function region arguments precede ordinary call arguments. |
| 3295 | @test unsafe fn testFunctionRegionApplication() throws (testing::TestError) { |
| 3296 | let expr = try! parseExprStr("read 'a 'b (p)"); |
| 3297 | let case ast::NodeValue::Call(call) = expr.value else throw testing::TestError::Failed; |
| 3298 | let case ast::NodeValue::RegionApply { value, regions } = call.callee.value |
| 3299 | else throw testing::TestError::Failed; |
| 3300 | try expectIdent(value, "read"); |
| 3301 | try testing::expect(regions.len == 2 and call.args.len == 1); |
| 3302 | } |
| 3303 | |
| 3304 | /// Concrete region headers can name a parent and end without a semicolon. |
| 3305 | @test unsafe fn testRegionParentSyntax() throws (testing::TestError) { |
| 3306 | let parsed = try? parseStmtsStr("fn f 'a (p: &'a u32) { let q: 'b = &*p where 'a: 'b in {} return; }"); |
| 3307 | try testing::expect(parsed <> nil); |
| 3308 | } |
| 3309 | |
| 3310 | /// Cell qualifiers retain pointer ownership and payload syntax. |
| 3311 | @test unsafe fn testCellPointerType() throws (testing::TestError) { |
| 3312 | let root = try! parseTypeStr("*cell u32"); |
| 3313 | let case ast::NodeValue::TypeSig(ast::TypeSig::Cell { |
| 3314 | class, payload, permission, |
| 3315 | }) = root.value else throw testing::TestError::Failed; |
| 3316 | try testing::expect(class == ast::PointerClass::Owned and permission == nil); |
| 3317 | let case ast::NodeValue::TypeSig(ast::TypeSig::Integer { width: 4, .. }) = payload.value |
| 3318 | else throw testing::TestError::Failed; |
| 3319 | |
| 3320 | let ownedAssociated = try! parseTypeStr("*cell 'permission u32"); |
| 3321 | let case ast::NodeValue::TypeSig(ast::TypeSig::Cell { |
| 3322 | class: ownedClass, payload: ownedPayload, permission: ownedPermission, |
| 3323 | }) = ownedAssociated.value else throw testing::TestError::Failed; |
| 3324 | let ownedPermissionRegion = ownedPermission else throw testing::TestError::Failed; |
| 3325 | let case ast::NodeValue::Region { name: ownedPermissionName, parent: nil } = |
| 3326 | ownedPermissionRegion.value |
| 3327 | else throw testing::TestError::Failed; |
| 3328 | let case ast::NodeValue::TypeSig(ast::TypeSig::Integer { width: 4, .. }) = |
| 3329 | ownedPayload.value |
| 3330 | else throw testing::TestError::Failed; |
| 3331 | try testing::expect( |
| 3332 | ownedClass == ast::PointerClass::Owned |
| 3333 | and mem::eq(ownedPermissionName, "'permission") |
| 3334 | ); |
| 3335 | |
| 3336 | let borrowed = try! parseTypeStr("&'r cell Pair 's"); |
| 3337 | let case ast::NodeValue::TypeSig(ast::TypeSig::RegionRef { type, .. }) = borrowed.value |
| 3338 | else throw testing::TestError::Failed; |
| 3339 | let case ast::NodeValue::TypeSig(ast::TypeSig::Cell { |
| 3340 | class: refClass, payload: inner, permission: refPermission, |
| 3341 | }) = type.value else throw testing::TestError::Failed; |
| 3342 | try testing::expect(refClass == ast::PointerClass::Ref and refPermission == nil); |
| 3343 | let case ast::NodeValue::TypeSig(ast::TypeSig::Applied { regions, .. }) = inner.value |
| 3344 | else throw testing::TestError::Failed; |
| 3345 | try testing::expect(regions.len == 1); |
| 3346 | |
| 3347 | let associated = try! parseTypeStr("&'storage cell 'permission Pair 'payload"); |
| 3348 | let case ast::NodeValue::TypeSig(ast::TypeSig::RegionRef { |
| 3349 | region: storage, type: associatedType, |
| 3350 | }) = associated.value else throw testing::TestError::Failed; |
| 3351 | let case ast::NodeValue::Region { name: storageName, parent: nil } = storage.value |
| 3352 | else throw testing::TestError::Failed; |
| 3353 | let case ast::NodeValue::TypeSig(ast::TypeSig::Cell { |
| 3354 | class: associatedClass, |
| 3355 | payload: associatedPayload, |
| 3356 | permission: associatedPermission, |
| 3357 | }) = associatedType.value else throw testing::TestError::Failed; |
| 3358 | let permissionRegion = associatedPermission else throw testing::TestError::Failed; |
| 3359 | let case ast::NodeValue::Region { name: permissionName, parent: nil } = |
| 3360 | permissionRegion.value |
| 3361 | else throw testing::TestError::Failed; |
| 3362 | let case ast::NodeValue::TypeSig(ast::TypeSig::Applied { |
| 3363 | name: payloadName, regions: payloadRegions, |
| 3364 | }) = associatedPayload.value else throw testing::TestError::Failed; |
| 3365 | try expectIdent(payloadName, "Pair"); |
| 3366 | try testing::expect(payloadRegions.len == 1); |
| 3367 | let case ast::NodeValue::Region { name: payloadRegionName, parent: nil } = |
| 3368 | payloadRegions[0].value |
| 3369 | else throw testing::TestError::Failed; |
| 3370 | try testing::expect( |
| 3371 | associatedClass == ast::PointerClass::Ref |
| 3372 | and mem::eq(storageName, "'storage") |
| 3373 | and mem::eq(permissionName, "'permission") |
| 3374 | and mem::eq(payloadRegionName, "'payload") |
| 3375 | ); |
| 3376 | |
| 3377 | } |
| 3378 | |
| 3379 | /// Measure committed storage for a statement after an existing node. |
| 3380 | unsafe fn statementStorageUsed(source: *[u8]) -> u32 { |
| 3381 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 3382 | ast::allocNode(&mut arena, ast::Span { offset: 0, length: 0 }, ast::NodeValue::Bool(true)); |
| 3383 | let start = alloc::used(&arena.arena); |
| 3384 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 3385 | let mut parser = super::mkParser(scanner::SourceLoc::String, source, arenaRef, poolRef); |
| 3386 | super::advance(&mut parser); |
| 3387 | try! super::parseStmt(&mut parser); |
| 3388 | return alloc::used(&parser.arena.arena) - start; |
| 3389 | } |
| 3390 | } |
| 3391 | |
| 3392 | /// Rewinding a failed expression preserves published nodes and source tokens. |
| 3393 | @test unsafe fn testSpeculativeRestoreStorage() throws (testing::TestError) { |
| 3394 | let expectedBytes = statementStorageUsed("return"); |
| 3395 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 3396 | let retained = ast::allocNode(&mut arena, ast::Span { offset: 3, length: 1 }, ast::NodeValue::Bool(true)); |
| 3397 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 3398 | let mut parser = super::mkParser(scanner::SourceLoc::String, |
| 3399 | "return [speculativeRestoreIdentifier, 1 +", arenaRef, poolRef); |
| 3400 | super::advance(&mut parser); |
| 3401 | try super::expect(&mut parser, scanner::TokenKind::Eof, "retained diagnostic") catch { |
| 3402 | }; |
| 3403 | let mut expectedScanner = parser.scanner; |
| 3404 | let expectedCurrent = scanner::next(&mut expectedScanner, parser.pool); |
| 3405 | let expectedPrevious = parser.current; |
| 3406 | let expectedContext = parser.context; |
| 3407 | let startOffset = alloc::used(&parser.arena.arena); |
| 3408 | let startId = parser.arena.nextId; |
| 3409 | let statement = try! super::parseStmt(&mut parser); |
| 3410 | let case ast::NodeValue::Return { value } = statement.value else throw testing::TestError::Failed; |
| 3411 | try testing::expect(value == nil); |
| 3412 | try testing::expect(statement.id == startId); |
| 3413 | try testing::expect(alloc::used(&parser.arena.arena) == startOffset + expectedBytes); |
| 3414 | try testing::expect(parser.arena.nextId == startId + 1); |
| 3415 | try testing::expect(parser.scanner.cursor == expectedScanner.cursor); |
| 3416 | try testing::expect(parser.scanner.token == expectedScanner.token); |
| 3417 | try testing::expect(parser.current.kind == expectedCurrent.kind); |
| 3418 | try testing::expect(parser.current.offset == expectedCurrent.offset); |
| 3419 | try testing::expect(parser.previous.kind == expectedPrevious.kind); |
| 3420 | try testing::expect(parser.previous.offset == expectedPrevious.offset); |
| 3421 | try testing::expect(parser.context == expectedContext); |
| 3422 | try testing::expect(parser.errors.count == 1); |
| 3423 | for i in alloc::used(&parser.arena.arena)..ARENA_STORAGE.len { |
| 3424 | set ARENA_STORAGE[i] = 0xA5; |
| 3425 | } |
| 3426 | let case ast::NodeValue::Bool(true) = retained.value else throw testing::TestError::Failed; |
| 3427 | try testing::expect(retained.span.offset == 3); |
| 3428 | try testing::expect(retained.span.length == 1); |
| 3429 | try testing::expect(mem::eq(parser.errors.list[0].message, "retained diagnostic")); |
| 3430 | try testing::expect(mem::eq(parser.errors.list[0].token.source, "return")); |
| 3431 | let interned = strings::find(parser.pool, "speculativeRestoreIdentifier") else throw testing::TestError::Failed; |
| 3432 | try testing::expect(mem::eq(interned, "speculativeRestoreIdentifier")); |
| 3433 | let replacement = ast::allocNode(parser.arena, ast::Span { offset: 0, length: 0 }, ast::NodeValue::Bool(false)); |
| 3434 | try testing::expect(replacement.id == startId + 1); |
| 3435 | let case ast::NodeValue::Bool(true) = retained.value else throw testing::TestError::Failed; |
| 3436 | } |
| 3437 | } |
| 3438 | |
| 3439 | /// Optional return and panic expressions publish only their wrapper after failure. |
| 3440 | @test unsafe fn testSpeculativeStatementPublication() throws (testing::TestError) { |
| 3441 | let expectedBytes = statementStorageUsed("return"); |
| 3442 | for source in ["return (speculativeReturnIdentifier +", "panic (speculativePanicIdentifier +"] { |
| 3443 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
| 3444 | ast::allocNode(&mut arena, ast::Span { offset: 0, length: 0 }, ast::NodeValue::Bool(true)); |
| 3445 | let startOffset = alloc::used(&arena.arena); |
| 3446 | let poolRef: 'pool = &mut STRING_POOL, arenaRef = &mut arena in { |
| 3447 | let mut parser = super::mkParser(scanner::SourceLoc::String, source, arenaRef, poolRef); |
| 3448 | super::advance(&mut parser); |
| 3449 | let startId = parser.arena.nextId; |
| 3450 | let statement = try! super::parseStmt(&mut parser); |
| 3451 | try testing::expect(statement.id == startId); |
| 3452 | try testing::expect(parser.arena.nextId == startId + 1); |
| 3453 | try testing::expect(alloc::used(&parser.arena.arena) == startOffset + expectedBytes); |
| 3454 | try testing::expect(parser.errors.count == 0); |
| 3455 | try testing::expect(parser.current.kind == scanner::TokenKind::LParen); |
| 3456 | match statement.value { |
| 3457 | case ast::NodeValue::Return { value } => try testing::expect(value == nil), |
| 3458 | case ast::NodeValue::Panic { message } => try testing::expect(message == nil), |
| 3459 | else => throw testing::TestError::Failed, |
| 3460 | } |
| 3461 | } |
| 3462 | } |
| 3463 | } |