compiler: Borrow parser string pools without copying snapshots
929c447c0daba09a85c93ee38046cec627475bde163cb3ec374e3aa8394a2008
1 parent
411cc85d
lib/std/lang/parser.rad
+145 -127
| 84 | 84 | count: u32, |
|
| 85 | 85 | } |
|
| 86 | 86 | ||
| 87 | 87 | /// Snapshot of parser state for speculative parsing. |
|
| 88 | 88 | record SavedState: Copy { |
|
| 89 | - | /// Scanner position, tokens, diagnostics, and expression context. |
|
| 90 | - | parser: Parser, |
|
| 89 | + | /// Scanner position. |
|
| 90 | + | scanner: scanner::Scanner, |
|
| 91 | + | /// Token under examination. |
|
| 92 | + | current: scanner::Token, |
|
| 93 | + | /// Most recently consumed token. |
|
| 94 | + | previous: scanner::Token, |
|
| 95 | + | /// Diagnostics collected before speculative parsing. |
|
| 96 | + | errors: ErrorList, |
|
| 97 | + | /// Expression context before speculative parsing. |
|
| 98 | + | context: Context, |
|
| 91 | 99 | /// First byte available for tentative allocations. |
|
| 92 | 100 | arena: u32, |
|
| 93 | 101 | /// First node identifier available to the tentative parse. |
|
| 94 | 102 | nextId: u32, |
|
| 95 | 103 | } |
| 144 | 152 | return nil, |
|
| 145 | 153 | } |
|
| 146 | 154 | } |
|
| 147 | 155 | ||
| 148 | 156 | /// Parser state. |
|
| 149 | - | export record Parser: Copy { |
|
| 157 | + | export record Parser: 'pool { |
|
| 150 | 158 | /// The scanner that provides tokens. |
|
| 151 | 159 | scanner: scanner::Scanner, |
|
| 152 | - | /// Interned string pool. It must remain valid while parsing. |
|
| 153 | - | pool: *unsafe mut strings::Pool, |
|
| 160 | + | /// Interned string pool borrowed for this parse. |
|
| 161 | + | pool: &'pool mut strings::Pool, |
|
| 154 | 162 | /// The current token being examined. |
|
| 155 | 163 | current: scanner::Token, |
|
| 156 | 164 | /// The most recently consumed token. |
|
| 157 | 165 | previous: scanner::Token, |
|
| 158 | 166 | /// Collection of errors encountered during parsing. |
| 164 | 172 | /// Current parsing context (normal or conditional). |
|
| 165 | 173 | context: Context, |
|
| 166 | 174 | } |
|
| 167 | 175 | ||
| 168 | 176 | /// Create a new parser initialized with the given source kind, source and node arena. |
|
| 169 | - | /// The node arena and string pool must outlive every copy of the parser. |
|
| 170 | - | export unsafe fn mkParser(sourceLoc: scanner::SourceLoc, source: *[u8], arena: &mut ast::NodeArena, pool: *unsafe mut strings::Pool) -> Parser { |
|
| 171 | - | return Parser { |
|
| 177 | + | /// The node arena and string pool must outlive the parser. |
|
| 178 | + | export unsafe fn mkParser 'pool (sourceLoc: scanner::SourceLoc, source: *[u8], arena: &mut ast::NodeArena, pool: &'pool mut strings::Pool) -> Parser 'pool { |
|
| 179 | + | return Parser 'pool { |
|
| 172 | 180 | scanner: scanner::scanner(sourceLoc, source, pool), |
|
| 173 | 181 | pool, |
|
| 174 | 182 | current: scanner::invalid(0, ""), |
|
| 175 | 183 | previous: scanner::invalid(0, ""), |
|
| 176 | - | errors: ErrorList { list: undefined, count: 0 }, |
|
| 184 | + | errors: ErrorList { list: [Error { message: "", token: scanner::invalid(0, "") }; MAX_ERRORS], count: 0 }, |
|
| 177 | 185 | arena: (&mut *arena) as *unsafe mut ast::NodeArena, |
|
| 178 | 186 | allocator: alloc::arenaAllocator(&mut arena.arena), |
|
| 179 | 187 | context: Context::Normal, |
|
| 180 | 188 | }; |
|
| 181 | 189 | } |
|
| 182 | 190 | ||
| 183 | 191 | /// Emit a `true` or `false` literal node. |
|
| 184 | - | unsafe fn nodeBool(p: &mut Parser, value: bool) -> *ast::Node { |
|
| 192 | + | unsafe fn nodeBool 'pool (p: &mut Parser 'pool, value: bool) -> *ast::Node { |
|
| 185 | 193 | return node(p, ast::NodeValue::Bool(value)); |
|
| 186 | 194 | } |
|
| 187 | 195 | ||
| 188 | 196 | /// Parse an integer literal while mapping shared errors into parser diagnostics. |
|
| 189 | - | fn parseIntLiteral(p: &mut Parser, text: *[u8]) -> fmt::IntLiteral |
|
| 197 | + | fn parseIntLiteral 'pool (p: &mut Parser 'pool, text: *[u8]) -> fmt::IntLiteral |
|
| 190 | 198 | throws (ParseError) |
|
| 191 | 199 | { |
|
| 192 | 200 | let literal = try fmt::parseInt(text) catch err { |
|
| 193 | 201 | match err { |
|
| 194 | 202 | case fmt::ParseError::Invalid => |
| 201 | 209 | }; |
|
| 202 | 210 | return literal; |
|
| 203 | 211 | } |
|
| 204 | 212 | ||
| 205 | 213 | /// Emit an integer type node. |
|
| 206 | - | unsafe fn nodeTypeInt(p: &mut Parser, width: u8, sign: ast::Signedness) -> *ast::Node { |
|
| 214 | + | unsafe fn nodeTypeInt 'pool (p: &mut Parser 'pool, width: u8, sign: ast::Signedness) -> *ast::Node { |
|
| 207 | 215 | return node(p, ast::NodeValue::TypeSig( |
|
| 208 | 216 | ast::TypeSig::Integer { width, sign } |
|
| 209 | 217 | )); |
|
| 210 | 218 | } |
|
| 211 | 219 | ||
| 212 | 220 | /// Emit a number literal node with the provided literal metadata. |
|
| 213 | - | unsafe fn nodeNumber(p: &mut Parser, literal: fmt::IntLiteral) -> *ast::Node { |
|
| 221 | + | unsafe fn nodeNumber 'pool (p: &mut Parser 'pool, literal: fmt::IntLiteral) -> *ast::Node { |
|
| 214 | 222 | return node(p, ast::NodeValue::Number(literal)); |
|
| 215 | 223 | } |
|
| 216 | 224 | ||
| 217 | 225 | /// Emit a `super` node. |
|
| 218 | - | unsafe fn nodeSuper(p: &mut Parser) -> *ast::Node { |
|
| 226 | + | unsafe fn nodeSuper 'pool (p: &mut Parser 'pool) -> *ast::Node { |
|
| 219 | 227 | return node(p, ast::NodeValue::Super); |
|
| 220 | 228 | } |
|
| 221 | 229 | ||
| 222 | 230 | /// Emit a single attribute node. |
|
| 223 | - | unsafe fn nodeAttribute(p: &mut Parser, attr: ast::Attribute) -> *ast::Node { |
|
| 231 | + | unsafe fn nodeAttribute 'pool (p: &mut Parser 'pool, attr: ast::Attribute) -> *ast::Node { |
|
| 224 | 232 | return node(p, ast::NodeValue::Attribute(attr)); |
|
| 225 | 233 | } |
|
| 226 | 234 | ||
| 227 | 235 | /// Emit a unary operator node. |
|
| 228 | - | unsafe fn nodeUnary(p: &mut Parser, op: ast::UnaryOp, value: *ast::Node) -> *ast::Node { |
|
| 236 | + | unsafe fn nodeUnary 'pool (p: &mut Parser 'pool, op: ast::UnaryOp, value: *ast::Node) -> *ast::Node { |
|
| 229 | 237 | return node(p, ast::NodeValue::UnOp({ op, value })); |
|
| 230 | 238 | } |
|
| 231 | 239 | ||
| 232 | 240 | /// Parse one expression without inheriting a surrounding condition or pattern context. |
|
| 233 | - | unsafe fn parseNormalExpr(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 241 | + | unsafe fn parseNormalExpr 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 234 | 242 | let saved = p.context; |
|
| 235 | 243 | set p.context = Context::Normal; |
|
| 236 | 244 | let expr = try parseExpr(p); |
|
| 237 | 245 | set p.context = saved; |
|
| 238 | 246 | return expr; |
|
| 239 | 247 | } |
|
| 240 | 248 | ||
| 241 | 249 | /// Parse a parenthesized expression without applying postfix operators. |
|
| 242 | - | unsafe fn parseParenthesized(p: &mut Parser) -> *ast::Node |
|
| 250 | + | unsafe fn parseParenthesized 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 243 | 251 | throws (ParseError) |
|
| 244 | 252 | { |
|
| 245 | 253 | try expect(p, scanner::TokenKind::LParen, "expected `(`"); |
|
| 246 | 254 | ||
| 247 | 255 | let expr = try parseNormalExpr(p); |
| 250 | 258 | ||
| 251 | 259 | return expr; |
|
| 252 | 260 | } |
|
| 253 | 261 | ||
| 254 | 262 | /// Parse an array literal: `[a, b, c]` or `[item; count]`. |
|
| 255 | - | unsafe fn parseArrayLiteral(p: &mut Parser) -> *ast::Node |
|
| 263 | + | unsafe fn parseArrayLiteral 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 256 | 264 | throws (ParseError) |
|
| 257 | 265 | { |
|
| 258 | 266 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
|
| 259 | 267 | if consume(p, scanner::TokenKind::RBracket) { // Empty array: `[]`. |
|
| 260 | 268 | let empty: *mut [*ast::Node] = &mut []; |
| 282 | 290 | ||
| 283 | 291 | return node(p, ast::NodeValue::ArrayLit(items)); |
|
| 284 | 292 | } |
|
| 285 | 293 | ||
| 286 | 294 | /// Parse a function call expression. |
|
| 287 | - | unsafe fn parseCall(p: &mut Parser, callee: *ast::Node) -> *ast::Node |
|
| 295 | + | unsafe fn parseCall 'pool (p: &mut Parser 'pool, callee: *ast::Node) -> *ast::Node |
|
| 288 | 296 | throws (ParseError) |
|
| 289 | 297 | { |
|
| 290 | 298 | let args = try parseList( |
|
| 291 | 299 | p, |
|
| 292 | 300 | scanner::TokenKind::LParen, |
|
| 293 | 301 | scanner::TokenKind::RParen, |
|
| 294 | - | parseNormalExpr |
|
| 302 | + | parseNormalExpr 'pool |
|
| 295 | 303 | ); |
|
| 296 | 304 | return node(p, ast::NodeValue::Call( |
|
| 297 | 305 | ast::Call { callee, args } |
|
| 298 | 306 | )); |
|
| 299 | 307 | } |
|
| 300 | 308 | ||
| 301 | 309 | /// Parse zero or more trailing `as` casts applied to `expr`. |
|
| 302 | - | unsafe fn parseAsCast(p: &mut Parser, expr: *ast::Node) -> *ast::Node |
|
| 310 | + | unsafe fn parseAsCast 'pool (p: &mut Parser 'pool, expr: *ast::Node) -> *ast::Node |
|
| 303 | 311 | throws (ParseError) |
|
| 304 | 312 | { |
|
| 305 | 313 | let mut result = expr; |
|
| 306 | 314 | ||
| 307 | 315 | while consume(p, scanner::TokenKind::As) { |
| 317 | 325 | /// Parse an optional conditional expression suffix. |
|
| 318 | 326 | /// |
|
| 319 | 327 | /// `<thenExpr> if <condition> else <elseExpr>` |
|
| 320 | 328 | /// |
|
| 321 | 329 | /// If no `if` keyword follows, returns the input expression unchanged. |
|
| 322 | - | unsafe fn parseCondExpr(p: &mut Parser, thenExpr: *ast::Node) -> *ast::Node |
|
| 330 | + | unsafe fn parseCondExpr 'pool (p: &mut Parser 'pool, thenExpr: *ast::Node) -> *ast::Node |
|
| 323 | 331 | throws (ParseError) |
|
| 324 | 332 | { |
|
| 325 | 333 | // Only parse conditional expressions in normal context. |
|
| 326 | 334 | // In conditional context, `if` is used for guards. |
|
| 327 | 335 | if p.context <> Context::Normal { |
| 338 | 346 | ast::CondExpr { condition, thenExpr, elseExpr } |
|
| 339 | 347 | )); |
|
| 340 | 348 | } |
|
| 341 | 349 | ||
| 342 | 350 | /// Parse array subscript or slice expression after `[`. |
|
| 343 | - | unsafe fn parseSubscriptOrSlice(p: &mut Parser, container: *ast::Node) -> *ast::Node |
|
| 351 | + | unsafe fn parseSubscriptOrSlice 'pool (p: &mut Parser 'pool, container: *ast::Node) -> *ast::Node |
|
| 344 | 352 | throws (ParseError) |
|
| 345 | 353 | { |
|
| 346 | 354 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
|
| 347 | 355 | ||
| 348 | 356 | let mut index: *ast::Node = undefined; |
| 378 | 386 | ||
| 379 | 387 | return node(p, ast::NodeValue::Subscript { container, index }); |
|
| 380 | 388 | } |
|
| 381 | 389 | ||
| 382 | 390 | /// Parse postfix operators (eg. field access, function call etc.) |
|
| 383 | - | unsafe fn parsePostfix(p: &mut Parser, expr: *ast::Node) -> *ast::Node |
|
| 391 | + | unsafe fn parsePostfix 'pool (p: &mut Parser 'pool, expr: *ast::Node) -> *ast::Node |
|
| 384 | 392 | throws (ParseError) |
|
| 385 | 393 | { |
|
| 386 | 394 | let mut result = expr; |
|
| 387 | 395 | ||
| 388 | 396 | loop { |
| 428 | 436 | } |
|
| 429 | 437 | return result; |
|
| 430 | 438 | } |
|
| 431 | 439 | ||
| 432 | 440 | /// Parse a conditional expression. |
|
| 433 | - | export unsafe fn parseCond(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 441 | + | export unsafe fn parseCond 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 434 | 442 | let saved = p.context; |
|
| 435 | 443 | set p.context = Context::Condition; |
|
| 436 | 444 | let expr = try parseExpr(p); |
|
| 437 | 445 | set p.context = saved; |
|
| 438 | 446 | ||
| 439 | 447 | return expr; |
|
| 440 | 448 | } |
|
| 441 | 449 | ||
| 442 | 450 | /// Parse unary expression followed by optional `as` cast. |
|
| 443 | 451 | /// `as` has higher precedence than binary ops but lower than unary. |
|
| 444 | - | unsafe fn parseUnary(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 452 | + | unsafe fn parseUnary 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 445 | 453 | let unary = try parseUnaryExpr(p); |
|
| 446 | 454 | return try parseAsCast(p, unary); |
|
| 447 | 455 | } |
|
| 448 | 456 | ||
| 449 | 457 | /// Parse prefix unary expressions and defer to primary expressions otherwise. |
|
| 450 | - | unsafe fn parseUnaryExpr(p: &mut Parser) -> *ast::Node |
|
| 458 | + | unsafe fn parseUnaryExpr 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 451 | 459 | throws (ParseError) |
|
| 452 | 460 | { |
|
| 453 | 461 | match p.current.kind { |
|
| 454 | 462 | case scanner::TokenKind::Not => { |
|
| 455 | 463 | advance(p); |
| 482 | 490 | } |
|
| 483 | 491 | } |
|
| 484 | 492 | } |
|
| 485 | 493 | ||
| 486 | 494 | /// Parse the access qualifier after an address operator. |
|
| 487 | - | unsafe fn parseAddressKind(p: &mut Parser) -> ast::AddressKind { |
|
| 495 | + | fn parseAddressKind 'pool (p: &mut Parser 'pool) -> ast::AddressKind { |
|
| 488 | 496 | if consume(p, scanner::TokenKind::Mut) { |
|
| 489 | 497 | return ast::AddressKind::Mutable; |
|
| 490 | 498 | } |
|
| 491 | 499 | if check(p, scanner::TokenKind::Ident) and mem::eq(p.current.source, "cell") { |
|
| 492 | 500 | advance(p); |
| 523 | 531 | return false, |
|
| 524 | 532 | } |
|
| 525 | 533 | } |
|
| 526 | 534 | ||
| 527 | 535 | /// Build a range expression node with an optional start and end expression. |
|
| 528 | - | unsafe fn parseRangeExpr(p: &mut Parser, start: ?*ast::Node) -> *ast::Node |
|
| 536 | + | unsafe fn parseRangeExpr 'pool (p: &mut Parser 'pool, start: ?*ast::Node) -> *ast::Node |
|
| 529 | 537 | throws (ParseError) |
|
| 530 | 538 | { |
|
| 531 | 539 | let mut endExpr: ?*ast::Node = nil; |
|
| 532 | 540 | ||
| 533 | 541 | if not isRangeTerminator(p.current.kind) { |
| 538 | 546 | ast::Range { start, end: endExpr } |
|
| 539 | 547 | )); |
|
| 540 | 548 | } |
|
| 541 | 549 | ||
| 542 | 550 | /// Parse binary expressions using precedence climbing. |
|
| 543 | - | unsafe fn parseBinary(p: &mut Parser, left: *ast::Node, minPrec: i32) -> *ast::Node |
|
| 551 | + | unsafe fn parseBinary 'pool (p: &mut Parser 'pool, left: *ast::Node, minPrec: i32) -> *ast::Node |
|
| 544 | 552 | throws (ParseError) |
|
| 545 | 553 | { |
|
| 546 | 554 | let mut result = left; |
|
| 547 | 555 | ||
| 548 | 556 | loop { |
| 607 | 615 | else => return true, |
|
| 608 | 616 | } |
|
| 609 | 617 | } |
|
| 610 | 618 | ||
| 611 | 619 | /// Parse a primary leaf expression without postfix operators. |
|
| 612 | - | unsafe fn parseLeaf(p: &mut Parser) -> *ast::Node |
|
| 620 | + | unsafe fn parseLeaf 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 613 | 621 | throws (ParseError) |
|
| 614 | 622 | { |
|
| 615 | 623 | match p.current.kind { |
|
| 616 | 624 | case scanner::TokenKind::True => { |
|
| 617 | 625 | advance(p); |
| 695 | 703 | } |
|
| 696 | 704 | } |
|
| 697 | 705 | } |
|
| 698 | 706 | ||
| 699 | 707 | /// Parse a primary expression (leaf nodes followed by postfix operators). |
|
| 700 | - | unsafe fn parsePrimary(p: &mut Parser) -> *ast::Node |
|
| 708 | + | unsafe fn parsePrimary 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 701 | 709 | throws (ParseError) |
|
| 702 | 710 | { |
|
| 703 | 711 | let leaf = try parseLeaf(p); |
|
| 704 | 712 | return try parsePostfix(p, leaf); |
|
| 705 | 713 | } |
|
| 706 | 714 | ||
| 707 | 715 | /// Parse a builtin function call like `@sizeOf(T)` or `@alignOf(T)`. |
|
| 708 | - | unsafe fn parseBuiltin(p: &mut Parser) -> *ast::Node |
|
| 716 | + | unsafe fn parseBuiltin 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 709 | 717 | throws (ParseError) |
|
| 710 | 718 | { |
|
| 711 | 719 | // Skip the '@' to get the name. |
|
| 712 | 720 | let ident = p.current.source; |
|
| 713 | 721 | advance(p); |
| 748 | 756 | ||
| 749 | 757 | /// Parse a single expression. |
|
| 750 | 758 | /// |
|
| 751 | 759 | /// Parses unary and binary operators using precedence climbing. |
|
| 752 | 760 | /// Conditional expressions (`x if cond else y`) have lowest precedence. |
|
| 753 | - | export unsafe fn parseExpr(p: &mut Parser) -> *ast::Node |
|
| 761 | + | export unsafe fn parseExpr 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 754 | 762 | throws (ParseError) |
|
| 755 | 763 | { |
|
| 756 | 764 | let left = try parseUnary(p); |
|
| 757 | 765 | let expr = try parseBinary(p, left, -1); |
|
| 758 | 766 | return try parseCondExpr(p, expr); |
|
| 759 | 767 | } |
|
| 760 | 768 | ||
| 761 | 769 | /// Try to consume a compound assignment operator and return its binary op. |
|
| 762 | - | unsafe fn tryCompoundAssignOp(p: &mut Parser) -> ?ast::BinaryOp { |
|
| 770 | + | fn tryCompoundAssignOp 'pool (p: &mut Parser 'pool) -> ?ast::BinaryOp { |
|
| 763 | 771 | match p.current.kind { |
|
| 764 | 772 | case scanner::TokenKind::PlusEqual => { advance(p); return ast::BinaryOp::Add; } |
|
| 765 | 773 | case scanner::TokenKind::MinusEqual => { advance(p); return ast::BinaryOp::Sub; } |
|
| 766 | 774 | case scanner::TokenKind::StarEqual => { advance(p); return ast::BinaryOp::Mul; } |
|
| 767 | 775 | case scanner::TokenKind::SlashEqual => { advance(p); return ast::BinaryOp::Div; } |
| 774 | 782 | else => return nil, |
|
| 775 | 783 | } |
|
| 776 | 784 | } |
|
| 777 | 785 | ||
| 778 | 786 | /// Parse an expression statement. |
|
| 779 | - | export unsafe fn parseExprStmt(p: &mut Parser) -> *ast::Node |
|
| 787 | + | export unsafe fn parseExprStmt 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 780 | 788 | throws (ParseError) |
|
| 781 | 789 | { |
|
| 782 | 790 | let expr = try parseExpr(p); |
|
| 783 | 791 | return node(p, ast::NodeValue::ExprStmt(expr)); |
|
| 784 | 792 | } |
|
| 785 | 793 | ||
| 786 | 794 | /// Parse a `set` statement assignment. |
|
| 787 | - | unsafe fn parseSetStmt(p: &mut Parser) -> *ast::Node |
|
| 795 | + | unsafe fn parseSetStmt 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 788 | 796 | throws (ParseError) |
|
| 789 | 797 | { |
|
| 790 | 798 | let target = try parseUnary(p); |
|
| 791 | 799 | if not ast::isPlaceExpr(target) { |
|
| 792 | 800 | throw failParsing(p, "invalid assignment target"); |
| 810 | 818 | } |
|
| 811 | 819 | throw failParsing(p, "expected assignment after `set`"); |
|
| 812 | 820 | } |
|
| 813 | 821 | ||
| 814 | 822 | /// Parse leading attributes and declaration modifiers. |
|
| 815 | - | unsafe fn parseAttributes(p: &mut Parser) -> ?ast::Attributes { |
|
| 823 | + | unsafe fn parseAttributes 'pool (p: &mut Parser 'pool) -> ?ast::Attributes { |
|
| 816 | 824 | let mut attrs = ast::nodeSlice(p.arena, 4); |
|
| 817 | 825 | ||
| 818 | 826 | if let attr = tryParseAnnotation(p) { |
|
| 819 | 827 | attrs.append(attr, p.allocator); |
|
| 820 | 828 | } |
| 832 | 840 | ||
| 833 | 841 | /// Try to parse an annotation like `@default`. |
|
| 834 | 842 | /// |
|
| 835 | 843 | /// Returns `nil` if not a known annotation (e.g. `@sizeOf` or `@alignOf` which are builtins). |
|
| 836 | 844 | /// Only consumes tokens if a valid annotation is found. |
|
| 837 | - | unsafe fn tryParseAnnotation(p: &mut Parser) -> ?*ast::Node { |
|
| 845 | + | unsafe fn tryParseAnnotation 'pool (p: &mut Parser 'pool) -> ?*ast::Node { |
|
| 838 | 846 | if not check(p, scanner::TokenKind::AtIdent) { |
|
| 839 | 847 | return nil; |
|
| 840 | 848 | } |
|
| 841 | 849 | // Token is @identifier, skip the '@' to get the name. |
|
| 842 | 850 | let ident = p.current.source; |
| 856 | 864 | } |
|
| 857 | 865 | ||
| 858 | 866 | /// Parse a single statement. |
|
| 859 | 867 | /// |
|
| 860 | 868 | /// Dispatches to the appropriate statement parser based on the current token. |
|
| 861 | - | export unsafe fn parseStmt(p: &mut Parser) -> *ast::Node |
|
| 869 | + | export unsafe fn parseStmt 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 862 | 870 | throws (ParseError) |
|
| 863 | 871 | { |
|
| 864 | 872 | // TODO: Why is `parseStmt` checking for attributes? |
|
| 865 | 873 | // We should have a `parseDecl` which is top-level, and `parseStmt` which |
|
| 866 | 874 | // is inside functions. |
| 986 | 994 | } |
|
| 987 | 995 | } |
|
| 988 | 996 | } |
|
| 989 | 997 | ||
| 990 | 998 | /// Return whether the current `let` statement starts a regional block. |
|
| 991 | - | unsafe fn isRegionBlock(p: &Parser) -> bool { |
|
| 999 | + | fn isRegionBlock 'pool (p: &mut Parser 'pool) -> bool { |
|
| 992 | 1000 | let mut lookahead = p.scanner; |
|
| 993 | 1001 | return scanner::next(&mut lookahead, p.pool).kind == scanner::TokenKind::Ident |
|
| 994 | 1002 | and scanner::next(&mut lookahead, p.pool).kind == scanner::TokenKind::Colon |
|
| 995 | 1003 | and scanner::next(&mut lookahead, p.pool).kind == scanner::TokenKind::Region; |
|
| 996 | 1004 | } |
|
| 997 | 1005 | ||
| 998 | 1006 | /// Return whether the current `use` statement has an allocation-session header. |
|
| 999 | - | unsafe fn isSessionBlock(p: &mut Parser) -> bool { |
|
| 1007 | + | unsafe fn isSessionBlock 'pool (p: &mut Parser 'pool) -> bool { |
|
| 1000 | 1008 | let saved = saveState(p); |
|
| 1001 | 1009 | advance(p); |
|
| 1002 | 1010 | let source: ?*ast::Node = try? parseUnaryExpr(p); |
|
| 1003 | 1011 | let result = source <> nil |
|
| 1004 | 1012 | and consume(p, scanner::TokenKind::As) |
| 1009 | 1017 | } |
|
| 1010 | 1018 | ||
| 1011 | 1019 | /// Parse statements until the specified ending token is encountered. |
|
| 1012 | 1020 | /// |
|
| 1013 | 1021 | /// Returns the completed immutable statement list. |
|
| 1014 | - | export unsafe fn parseStmtsUntil(p: &mut Parser, end: scanner::TokenKind, capacity: u32) -> *[*ast::Node] |
|
| 1022 | + | export unsafe fn parseStmtsUntil 'pool (p: &mut Parser 'pool, end: scanner::TokenKind, capacity: u32) -> *[*ast::Node] |
|
| 1015 | 1023 | throws (ParseError) |
|
| 1016 | 1024 | { |
|
| 1017 | 1025 | let mut statements = ast::nodeSlice(p.arena, capacity); |
|
| 1018 | 1026 | while not check(p, end) { |
|
| 1019 | 1027 | let stmt = try parseStmt(p); |
| 1031 | 1039 | } |
|
| 1032 | 1040 | return statements; |
|
| 1033 | 1041 | } |
|
| 1034 | 1042 | ||
| 1035 | 1043 | /// Parse a block of statements enclosed in curly braces. |
|
| 1036 | - | export unsafe fn parseBlock(p: &mut Parser) -> *ast::Node |
|
| 1044 | + | export unsafe fn parseBlock 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1037 | 1045 | throws (ParseError) |
|
| 1038 | 1046 | { |
|
| 1039 | 1047 | return try parseBlockBody(p, false); |
|
| 1040 | 1048 | } |
|
| 1041 | 1049 | ||
| 1042 | 1050 | /// Parse a statement block with the specified unsafe permission. |
|
| 1043 | - | unsafe fn parseBlockBody(p: &mut Parser, isUnsafe: bool) -> *ast::Node |
|
| 1051 | + | unsafe fn parseBlockBody 'pool (p: &mut Parser 'pool, isUnsafe: bool) -> *ast::Node |
|
| 1044 | 1052 | throws (ParseError) |
|
| 1045 | 1053 | { |
|
| 1046 | 1054 | let start = p.current; |
|
| 1047 | 1055 | ||
| 1048 | 1056 | if not consume(p, scanner::TokenKind::LBrace) { |
| 1054 | 1062 | ||
| 1055 | 1063 | return node(p, ast::NodeValue::Block(blk)); |
|
| 1056 | 1064 | } |
|
| 1057 | 1065 | ||
| 1058 | 1066 | /// Create a block containing a single statement node. |
|
| 1059 | - | unsafe fn mkBlockWith(p: &mut Parser, node: *ast::Node) -> ast::Block { |
|
| 1067 | + | unsafe fn mkBlockWith 'pool (p: &mut Parser 'pool, node: *ast::Node) -> ast::Block { |
|
| 1060 | 1068 | let stmts = ast::nodeSlice(p.arena, 1).append(node, p.allocator); |
|
| 1061 | 1069 | return ast::Block { statements: stmts, isUnsafe: false }; |
|
| 1062 | 1070 | } |
|
| 1063 | 1071 | ||
| 1064 | 1072 | /// Parse the branch that follows `else` in let-else style constructs. |
|
| 1065 | 1073 | /// |
|
| 1066 | 1074 | /// Allows either a block, a single statement like `return`, |
|
| 1067 | 1075 | /// or a standalone expression which is returned directly. |
|
| 1068 | - | unsafe fn parseLetElseBranch(p: &mut Parser) -> *ast::Node |
|
| 1076 | + | unsafe fn parseLetElseBranch 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1069 | 1077 | throws (ParseError) |
|
| 1070 | 1078 | { |
|
| 1071 | 1079 | if check(p, scanner::TokenKind::LBrace) { |
|
| 1072 | 1080 | return try parseBlock(p); |
|
| 1073 | 1081 | } |
| 1078 | 1086 | } |
|
| 1079 | 1087 | return branch; |
|
| 1080 | 1088 | } |
|
| 1081 | 1089 | ||
| 1082 | 1090 | /// Allocate a new node from the parser's arena. |
|
| 1083 | - | unsafe fn node(p: &mut Parser, value: ast::NodeValue) -> *mut ast::Node { |
|
| 1091 | + | unsafe fn node 'pool (p: &mut Parser 'pool, value: ast::NodeValue) -> *mut ast::Node { |
|
| 1084 | 1092 | let span = ast::Span { |
|
| 1085 | 1093 | offset: p.previous.offset, |
|
| 1086 | 1094 | length: p.previous.source.len, |
|
| 1087 | 1095 | }; |
|
| 1088 | 1096 | let n = ast::allocNode(p.arena, span, value); |
| 1090 | 1098 | ||
| 1091 | 1099 | return n; |
|
| 1092 | 1100 | } |
|
| 1093 | 1101 | ||
| 1094 | 1102 | /// Update the span of `node` using the most recently consumed token. |
|
| 1095 | - | fn finishSpan(p: &mut Parser, node: &mut ast::Node) { |
|
| 1103 | + | fn finishSpan 'pool (p: &mut Parser 'pool, node: &mut ast::Node) { |
|
| 1096 | 1104 | let start: u32 = node.span.offset; |
|
| 1097 | 1105 | let mut end: u32 = p.previous.offset + p.previous.source.len; |
|
| 1098 | 1106 | ||
| 1099 | 1107 | if end >= start { |
|
| 1100 | 1108 | set node.span.length = end - start; |
| 1102 | 1110 | set node.span.length = 0; |
|
| 1103 | 1111 | } |
|
| 1104 | 1112 | } |
|
| 1105 | 1113 | ||
| 1106 | 1114 | /// Save parser state for speculative parsing. |
|
| 1107 | - | unsafe fn saveState(p: &Parser) -> SavedState { |
|
| 1115 | + | unsafe fn saveState 'pool (p: &Parser 'pool) -> SavedState { |
|
| 1108 | 1116 | return SavedState { |
|
| 1109 | - | parser: *p, |
|
| 1117 | + | scanner: p.scanner, |
|
| 1118 | + | current: p.current, |
|
| 1119 | + | previous: p.previous, |
|
| 1120 | + | errors: p.errors, |
|
| 1121 | + | context: p.context, |
|
| 1110 | 1122 | arena: alloc::save(&p.arena.arena), |
|
| 1111 | 1123 | nextId: p.arena.nextId, |
|
| 1112 | 1124 | }; |
|
| 1113 | 1125 | } |
|
| 1114 | 1126 | ||
| 1115 | 1127 | /// Restore scanner state, diagnostics, arena storage, and node identifiers. |
|
| 1116 | 1128 | /// Tentative nodes must be unreachable from all state retained by the caller. |
|
| 1117 | 1129 | /// Interned tokens retain source storage, which must outlive the string pool. |
|
| 1118 | - | unsafe fn restoreState(p: &mut Parser, s: &SavedState) { |
|
| 1119 | - | set *p = s.parser; |
|
| 1130 | + | unsafe fn restoreState 'pool (p: &mut Parser 'pool, s: &SavedState) { |
|
| 1131 | + | set p.scanner = s.scanner; |
|
| 1132 | + | set p.current = s.current; |
|
| 1133 | + | set p.previous = s.previous; |
|
| 1134 | + | set p.errors = s.errors; |
|
| 1135 | + | set p.context = s.context; |
|
| 1120 | 1136 | alloc::restore(&mut p.arena.arena, s.arena); |
|
| 1121 | 1137 | set p.arena.nextId = s.nextId; |
|
| 1122 | 1138 | } |
|
| 1123 | 1139 | ||
| 1124 | 1140 | /// Report a parser error. |
|
| 1125 | - | fn reportError(p: &mut Parser, token: scanner::Token, message: *[u8]) { |
|
| 1141 | + | fn reportError 'pool (p: &mut Parser 'pool, token: scanner::Token, message: *[u8]) { |
|
| 1126 | 1142 | assert message.len > 0; |
|
| 1127 | 1143 | ||
| 1128 | 1144 | // Ignore errors once the error list is full. |
|
| 1129 | 1145 | if p.errors.count < p.errors.list.len { |
|
| 1130 | 1146 | set p.errors.list[p.errors.count] = Error { message, token }; |
|
| 1131 | 1147 | set p.errors.count += 1; |
|
| 1132 | 1148 | } |
|
| 1133 | 1149 | } |
|
| 1134 | 1150 | ||
| 1135 | 1151 | /// Fail the parsing process with the given error. |
|
| 1136 | - | fn failParsing(p: &mut Parser, err: *[u8]) -> ParseError { |
|
| 1152 | + | fn failParsing 'pool (p: &mut Parser 'pool, err: *[u8]) -> ParseError { |
|
| 1137 | 1153 | let token = p.current; |
|
| 1138 | 1154 | reportError(p, token, err); |
|
| 1139 | 1155 | return ParseError::UnexpectedToken; |
|
| 1140 | 1156 | } |
|
| 1141 | 1157 | ||
| 1142 | 1158 | /// Print all errors that have been collected during parsing. |
|
| 1143 | - | export fn printErrors(p: &Parser) { |
|
| 1159 | + | export fn printErrors 'pool (p: &Parser 'pool) { |
|
| 1144 | 1160 | for i in 0..p.errors.count { |
|
| 1145 | 1161 | let e = p.errors.list[i]; |
|
| 1146 | 1162 | if let loc = scanner::getLocation( |
|
| 1147 | 1163 | p.scanner.sourceLoc, p.scanner.source, e.token.offset |
|
| 1148 | 1164 | ) { |
| 1169 | 1185 | io::print("\n"); |
|
| 1170 | 1186 | } |
|
| 1171 | 1187 | } |
|
| 1172 | 1188 | ||
| 1173 | 1189 | /// Check whether the current token matches the expected kind. |
|
| 1174 | - | export fn check(p: &Parser, kind: scanner::TokenKind) -> bool { |
|
| 1190 | + | export fn check 'pool (p: &Parser 'pool, kind: scanner::TokenKind) -> bool { |
|
| 1175 | 1191 | return p.current.kind == kind; |
|
| 1176 | 1192 | } |
|
| 1177 | 1193 | ||
| 1178 | 1194 | /// Advance the parser by one token. |
|
| 1179 | - | export unsafe fn advance(p: &mut Parser) { |
|
| 1195 | + | export fn advance 'pool (p: &mut Parser 'pool) { |
|
| 1180 | 1196 | set p.previous = p.current; |
|
| 1181 | 1197 | set p.current = scanner::next(&mut p.scanner, p.pool); |
|
| 1182 | 1198 | } |
|
| 1183 | 1199 | ||
| 1184 | 1200 | /// Parse an `if let` pattern matching statement. |
|
| 1185 | 1201 | /// |
|
| 1186 | 1202 | /// Syntax: `if let binding = scrutinee { ... }` |
|
| 1187 | 1203 | /// Syntax: `if let mut binding = scrutinee { ... }` |
|
| 1188 | - | unsafe fn parseIfLet(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 1204 | + | unsafe fn parseIfLet 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 1189 | 1205 | try expect(p, scanner::TokenKind::Let, "expected `let`"); |
|
| 1190 | 1206 | ||
| 1191 | 1207 | // Parse pattern: either `case <pattern>`, `mut <ident>`, or simple `<ident>`. |
|
| 1192 | 1208 | let mut pattern: *ast::Node = undefined; |
|
| 1193 | 1209 | let mut kind = ast::PatternKind::Binding; |
| 1227 | 1243 | elseBranch, |
|
| 1228 | 1244 | })); |
|
| 1229 | 1245 | } |
|
| 1230 | 1246 | ||
| 1231 | 1247 | /// Parse a `while let` statement. |
|
| 1232 | - | unsafe fn parseWhileLet(p: &mut Parser) -> *ast::Node |
|
| 1248 | + | unsafe fn parseWhileLet 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1233 | 1249 | throws (ParseError) |
|
| 1234 | 1250 | { |
|
| 1235 | 1251 | try expect(p, scanner::TokenKind::Let, "expected `let`"); |
|
| 1236 | 1252 | ||
| 1237 | 1253 | // Parse pattern: either `case <pattern>`, `mut <ident>`, or simple `<ident>`. |
| 1265 | 1281 | elseBranch, |
|
| 1266 | 1282 | })); |
|
| 1267 | 1283 | } |
|
| 1268 | 1284 | ||
| 1269 | 1285 | /// Parse a `while` statement. |
|
| 1270 | - | unsafe fn parseWhile(p: &mut Parser) -> *ast::Node |
|
| 1286 | + | unsafe fn parseWhile 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1271 | 1287 | throws (ParseError) |
|
| 1272 | 1288 | { |
|
| 1273 | 1289 | try expect(p, scanner::TokenKind::While, "expected `while`"); |
|
| 1274 | 1290 | ||
| 1275 | 1291 | // Check for `while let` or `while let case` syntax. |
| 1287 | 1303 | condition, body, elseBranch, |
|
| 1288 | 1304 | })); |
|
| 1289 | 1305 | } |
|
| 1290 | 1306 | ||
| 1291 | 1307 | /// Parse a `loop` statement. |
|
| 1292 | - | unsafe fn parseLoop(p: &mut Parser) -> *ast::Node |
|
| 1308 | + | unsafe fn parseLoop 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1293 | 1309 | throws (ParseError) |
|
| 1294 | 1310 | { |
|
| 1295 | 1311 | try expect(p, scanner::TokenKind::Loop, "expected `loop`"); |
|
| 1296 | 1312 | let body = try parseBlock(p); |
|
| 1297 | 1313 | ||
| 1298 | 1314 | return node(p, ast::NodeValue::Loop { body }); |
|
| 1299 | 1315 | } |
|
| 1300 | 1316 | ||
| 1301 | 1317 | /// Parse a `for` statement. |
|
| 1302 | - | unsafe fn parseFor(p: &mut Parser) -> *ast::Node |
|
| 1318 | + | unsafe fn parseFor 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1303 | 1319 | throws (ParseError) |
|
| 1304 | 1320 | { |
|
| 1305 | 1321 | try expect(p, scanner::TokenKind::For, "expected `for`"); |
|
| 1306 | 1322 | ||
| 1307 | 1323 | let binding = try parseIdentOrPlaceholder(p, "expected identifier or `_`"); |
| 1323 | 1339 | binding, index, iterable, body, elseBranch, |
|
| 1324 | 1340 | })); |
|
| 1325 | 1341 | } |
|
| 1326 | 1342 | ||
| 1327 | 1343 | /// Parse a `return` statement. |
|
| 1328 | - | unsafe fn parseReturn(p: &mut Parser) -> *ast::Node |
|
| 1344 | + | unsafe fn parseReturn 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1329 | 1345 | throws (ParseError) |
|
| 1330 | 1346 | { |
|
| 1331 | 1347 | try expect(p, scanner::TokenKind::Return, "expected `return`"); |
|
| 1332 | 1348 | ||
| 1333 | 1349 | // Speculatively try to parse a return value expression. |
| 1338 | 1354 | } |
|
| 1339 | 1355 | return node(p, ast::NodeValue::Return { value }); |
|
| 1340 | 1356 | } |
|
| 1341 | 1357 | ||
| 1342 | 1358 | /// Parse a `throw` statement. |
|
| 1343 | - | unsafe fn parseThrow(p: &mut Parser) -> *ast::Node |
|
| 1359 | + | unsafe fn parseThrow 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1344 | 1360 | throws (ParseError) |
|
| 1345 | 1361 | { |
|
| 1346 | 1362 | try expect(p, scanner::TokenKind::Throw, "expected `throw`"); |
|
| 1347 | 1363 | let expr = try parseExpr(p); |
|
| 1348 | 1364 | ||
| 1349 | 1365 | return node(p, ast::NodeValue::Throw { expr }); |
|
| 1350 | 1366 | } |
|
| 1351 | 1367 | ||
| 1352 | 1368 | /// Parse a `panic` statement. |
|
| 1353 | - | unsafe fn parsePanic(p: &mut Parser) -> *ast::Node |
|
| 1369 | + | unsafe fn parsePanic 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1354 | 1370 | throws (ParseError) |
|
| 1355 | 1371 | { |
|
| 1356 | 1372 | try expect(p, scanner::TokenKind::Panic, "expected `panic`"); |
|
| 1357 | 1373 | ||
| 1358 | 1374 | // `panic { expr }`. |
| 1374 | 1390 | /// |
|
| 1375 | 1391 | /// Forms: |
|
| 1376 | 1392 | /// `assert <expr>` |
|
| 1377 | 1393 | /// `assert <expr>, "message"` |
|
| 1378 | 1394 | /// `assert { <expr> }, "message"` |
|
| 1379 | - | unsafe fn parseAssert(p: &mut Parser) -> *ast::Node |
|
| 1395 | + | unsafe fn parseAssert 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1380 | 1396 | throws (ParseError) |
|
| 1381 | 1397 | { |
|
| 1382 | 1398 | try expect(p, scanner::TokenKind::Assert, "expected `assert`"); |
|
| 1383 | 1399 | ||
| 1384 | 1400 | // `assert { expr }` block form or `assert <expr>`. |
| 1395 | 1411 | } |
|
| 1396 | 1412 | return node(p, ast::NodeValue::Assert { condition, message }); |
|
| 1397 | 1413 | } |
|
| 1398 | 1414 | ||
| 1399 | 1415 | /// Parse a `try` expression with optional `catch` clause(s). |
|
| 1400 | - | unsafe fn parseTryExpr(p: &mut Parser) -> *ast::Node |
|
| 1416 | + | unsafe fn parseTryExpr 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1401 | 1417 | throws (ParseError) |
|
| 1402 | 1418 | { |
|
| 1403 | 1419 | try expect(p, scanner::TokenKind::Try, "expected `try`"); |
|
| 1404 | 1420 | ||
| 1405 | 1421 | let shouldPanic = consume(p, scanner::TokenKind::Bang); |
| 1468 | 1484 | /// d |
|
| 1469 | 1485 | /// } |
|
| 1470 | 1486 | /// } |
|
| 1471 | 1487 | /// } |
|
| 1472 | 1488 | /// |
|
| 1473 | - | unsafe fn parseIf(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 1489 | + | unsafe fn parseIf 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 1474 | 1490 | try expect(p, scanner::TokenKind::If, "expected `if`"); |
|
| 1475 | 1491 | ||
| 1476 | 1492 | // Check for `if let` or `if let case` syntax. |
|
| 1477 | 1493 | if check(p, scanner::TokenKind::Let) { |
|
| 1478 | 1494 | return try parseIfLet(p); |
| 1498 | 1514 | condition: cond, thenBranch, elseBranch, |
|
| 1499 | 1515 | })); |
|
| 1500 | 1516 | } |
|
| 1501 | 1517 | ||
| 1502 | 1518 | /// Parse a `match` statement. |
|
| 1503 | - | unsafe fn parseMatch(p: &mut Parser) -> *ast::Node |
|
| 1519 | + | unsafe fn parseMatch 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1504 | 1520 | throws (ParseError) |
|
| 1505 | 1521 | { |
|
| 1506 | 1522 | try expect(p, scanner::TokenKind::Match, "expected `match`"); |
|
| 1507 | 1523 | ||
| 1508 | 1524 | let subject = try parseCond(p); |
| 1522 | 1538 | ast::Match { subject, prongs } |
|
| 1523 | 1539 | )); |
|
| 1524 | 1540 | } |
|
| 1525 | 1541 | ||
| 1526 | 1542 | /// Parse a single `match` prong. |
|
| 1527 | - | unsafe fn parseMatchProng(p: &mut Parser) -> *ast::Node |
|
| 1543 | + | unsafe fn parseMatchProng 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1528 | 1544 | throws (ParseError) |
|
| 1529 | 1545 | { |
|
| 1530 | 1546 | let mut guard: ?*ast::Node = nil; |
|
| 1531 | 1547 | ||
| 1532 | 1548 | // Case prong: `case <pattern>, ... if <guard> => <body>`. |
| 1581 | 1597 | )); |
|
| 1582 | 1598 | } |
|
| 1583 | 1599 | ||
| 1584 | 1600 | /// Parse a pattern expression used by `case` constructs. |
|
| 1585 | 1601 | /// Uses `Pattern` context to allow record literals but not conditional expressions. |
|
| 1586 | - | unsafe fn parseMatchPattern(p: &mut Parser) -> *ast::Node |
|
| 1602 | + | unsafe fn parseMatchPattern 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1587 | 1603 | throws (ParseError) |
|
| 1588 | 1604 | { |
|
| 1589 | 1605 | let saved = p.context; |
|
| 1590 | 1606 | set p.context = Context::Pattern; |
|
| 1591 | 1607 | let pattern = try parseExpr(p); |
| 1593 | 1609 | ||
| 1594 | 1610 | return pattern; |
|
| 1595 | 1611 | } |
|
| 1596 | 1612 | ||
| 1597 | 1613 | /// Parse a region name. |
|
| 1598 | - | unsafe fn parseRegion(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 1614 | + | unsafe fn parseRegion 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 1599 | 1615 | let name = try expect(p, scanner::TokenKind::Region, "expected region name"); |
|
| 1600 | 1616 | return node(p, ast::NodeValue::Region { name, parent: nil }); |
|
| 1601 | 1617 | } |
|
| 1602 | 1618 | ||
| 1603 | 1619 | /// Parse consecutive region names. |
|
| 1604 | - | unsafe fn parseRegions(p: &mut Parser) -> *mut [*ast::Node] throws (ParseError) { |
|
| 1620 | + | unsafe fn parseRegions 'pool (p: &mut Parser 'pool) -> *mut [*ast::Node] throws (ParseError) { |
|
| 1605 | 1621 | let mut regions = ast::nodeSlice(p.arena, 4); |
|
| 1606 | 1622 | while check(p, scanner::TokenKind::Region) { |
|
| 1607 | 1623 | regions.append(try parseRegion(p), p.allocator); |
|
| 1608 | 1624 | } |
|
| 1609 | 1625 | return regions; |
|
| 1610 | 1626 | } |
|
| 1611 | 1627 | ||
| 1612 | 1628 | /// Parse region bounds for a declaration. |
|
| 1613 | - | unsafe fn parseRegionBounds(p: &mut Parser, regions: &mut [*ast::Node]) |
|
| 1629 | + | unsafe fn parseRegionBounds 'pool (p: &mut Parser 'pool, regions: &mut [*ast::Node]) |
|
| 1614 | 1630 | throws (ParseError) |
|
| 1615 | 1631 | { |
|
| 1616 | 1632 | if not consume(p, scanner::TokenKind::Where) { |
|
| 1617 | 1633 | return; |
|
| 1618 | 1634 | } |
| 1642 | 1658 | } |
|
| 1643 | 1659 | } |
|
| 1644 | 1660 | } |
|
| 1645 | 1661 | ||
| 1646 | 1662 | /// Parse scoped borrow bindings. |
|
| 1647 | - | unsafe fn parseRegionBlock(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 1663 | + | unsafe fn parseRegionBlock 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 1648 | 1664 | advance(p); |
|
| 1649 | 1665 | let mut binding = try parseIdent(p, "expected region binding name"); |
|
| 1650 | 1666 | try expect(p, scanner::TokenKind::Colon, "expected `:` after region binding"); |
|
| 1651 | 1667 | let regionName = try expect(p, scanner::TokenKind::Region, "expected region name after `:`"); |
|
| 1652 | 1668 | let mut region = node(p, ast::NodeValue::Region { name: regionName, parent: nil }); |
| 1676 | 1692 | let body = try parseBlock(p); |
|
| 1677 | 1693 | return node(p, ast::NodeValue::RegionBlock { region, bindings, body, isSession: false }); |
|
| 1678 | 1694 | } |
|
| 1679 | 1695 | ||
| 1680 | 1696 | /// Create a region name from an allocation-session binding name. |
|
| 1681 | - | unsafe fn sessionRegion(p: &mut Parser, binding: *ast::Node) -> *ast::Node { |
|
| 1697 | + | unsafe fn sessionRegion 'pool (p: &mut Parser 'pool, binding: *ast::Node) -> *ast::Node { |
|
| 1682 | 1698 | let case ast::NodeValue::Ident(name) = binding.value |
|
| 1683 | 1699 | else panic "sessionRegion: invalid binding"; |
|
| 1684 | 1700 | let len = name.len + 1; |
|
| 1685 | 1701 | let buf = alloc::remainingBuf(&mut p.arena.arena); |
|
| 1686 | 1702 | assert buf.len >= len, "sessionRegion: node arena is full"; |
| 1689 | 1705 | alloc::commit(&mut p.arena.arena, len); |
|
| 1690 | 1706 | return node(p, ast::NodeValue::Region { name: &buf[..len], parent: nil }); |
|
| 1691 | 1707 | } |
|
| 1692 | 1708 | ||
| 1693 | 1709 | /// Parse an allocation session with an implicit exclusive source borrow. |
|
| 1694 | - | unsafe fn parseSessionBlock(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 1710 | + | unsafe fn parseSessionBlock 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 1695 | 1711 | try expect(p, scanner::TokenKind::Use, "expected `use`"); |
|
| 1696 | 1712 | let target = try parseUnaryExpr(p); |
|
| 1697 | 1713 | let value = node(p, ast::NodeValue::AddressOf({ target, kind: ast::AddressKind::Mutable })); |
|
| 1698 | 1714 | try expect(p, scanner::TokenKind::As, "expected `as` after allocation source"); |
|
| 1699 | 1715 | let binding = try parseIdent(p, "expected allocation binding after `as`"); |
| 1706 | 1722 | let body = try parseBlock(p); |
|
| 1707 | 1723 | return node(p, ast::NodeValue::RegionBlock { region, bindings, body, isSession: true }); |
|
| 1708 | 1724 | } |
|
| 1709 | 1725 | ||
| 1710 | 1726 | /// Parse an identifier. |
|
| 1711 | - | unsafe fn parseIdent(p: &mut Parser, err: *[u8]) -> *ast::Node |
|
| 1727 | + | unsafe fn parseIdent 'pool (p: &mut Parser 'pool, err: *[u8]) -> *ast::Node |
|
| 1712 | 1728 | throws (ParseError) |
|
| 1713 | 1729 | { |
|
| 1714 | 1730 | let source = try expect(p, scanner::TokenKind::Ident, err); |
|
| 1715 | 1731 | return node(p, ast::NodeValue::Ident(source)); |
|
| 1716 | 1732 | } |
|
| 1717 | 1733 | ||
| 1718 | 1734 | /// Parse either an identifier or a placeholder (`_`). |
|
| 1719 | - | unsafe fn parseIdentOrPlaceholder(p: &mut Parser, err: *[u8]) -> *ast::Node |
|
| 1735 | + | unsafe fn parseIdentOrPlaceholder 'pool (p: &mut Parser 'pool, err: *[u8]) -> *ast::Node |
|
| 1720 | 1736 | throws (ParseError) |
|
| 1721 | 1737 | { |
|
| 1722 | 1738 | if consume(p, scanner::TokenKind::Underscore) { |
|
| 1723 | 1739 | return node(p, ast::NodeValue::Placeholder); |
|
| 1724 | 1740 | } |
| 1726 | 1742 | } |
|
| 1727 | 1743 | ||
| 1728 | 1744 | /// Parse an alignment specifier. |
|
| 1729 | 1745 | /// |
|
| 1730 | 1746 | /// Syntax: `align(N)` where N is a power of 2. |
|
| 1731 | - | unsafe fn parseAlign(p: &mut Parser) -> *ast::Node |
|
| 1747 | + | unsafe fn parseAlign 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1732 | 1748 | throws (ParseError) |
|
| 1733 | 1749 | { |
|
| 1734 | 1750 | try expect(p, scanner::TokenKind::Align, "expected `align`"); |
|
| 1735 | 1751 | let value = try parseParenthesized(p); |
|
| 1736 | 1752 | return node(p, ast::NodeValue::Align { value }); |
| 1738 | 1754 | ||
| 1739 | 1755 | /// Parse a comma-separated list of record fields. |
|
| 1740 | 1756 | /// The opening delimiter should already be consumed. |
|
| 1741 | 1757 | /// For labeled fields: `{ name: T, ... }`. |
|
| 1742 | 1758 | /// For unlabeled fields: `(T, T, ...)`. |
|
| 1743 | - | unsafe fn parseRecordFields( |
|
| 1744 | - | p: &mut Parser, |
|
| 1759 | + | unsafe fn parseRecordFields 'pool ( |
|
| 1760 | + | p: &mut Parser 'pool, |
|
| 1745 | 1761 | mode: RecordFieldMode |
|
| 1746 | 1762 | ) -> *mut [*ast::Node] |
|
| 1747 | 1763 | throws (ParseError) |
|
| 1748 | 1764 | { |
|
| 1749 | 1765 | let terminator = scanner::TokenKind::RBrace if mode == RecordFieldMode::Labeled |
| 1787 | 1803 | ||
| 1788 | 1804 | return fields; |
|
| 1789 | 1805 | } |
|
| 1790 | 1806 | ||
| 1791 | 1807 | /// Parse an optional declaration list and separate regions from derives. |
|
| 1792 | - | unsafe fn parseNominalClauses( |
|
| 1793 | - | p: &mut Parser, |
|
| 1808 | + | unsafe fn parseNominalClauses 'pool ( |
|
| 1809 | + | p: &mut Parser 'pool, |
|
| 1794 | 1810 | regions: &mut *mut [*ast::Node], |
|
| 1795 | 1811 | derives: &mut *mut [*ast::Node], |
|
| 1796 | 1812 | ) throws (ParseError) { |
|
| 1797 | 1813 | if not consume(p, scanner::TokenKind::Colon) { |
|
| 1798 | 1814 | return; |
| 1814 | 1830 | } |
|
| 1815 | 1831 | } |
|
| 1816 | 1832 | } |
|
| 1817 | 1833 | ||
| 1818 | 1834 | /// Parse an optional list of trait names. |
|
| 1819 | - | unsafe fn parseDerives(p: &mut Parser) -> *mut [*ast::Node] throws (ParseError) { |
|
| 1835 | + | unsafe fn parseDerives 'pool (p: &mut Parser 'pool) -> *mut [*ast::Node] throws (ParseError) { |
|
| 1820 | 1836 | if not consume(p, scanner::TokenKind::Colon) { |
|
| 1821 | 1837 | return &mut []; |
|
| 1822 | 1838 | } |
|
| 1823 | 1839 | let mut derives = ast::nodeSlice(p.arena, 4); |
|
| 1824 | 1840 | loop { |
| 1830 | 1846 | return derives; |
|
| 1831 | 1847 | } |
|
| 1832 | 1848 | ||
| 1833 | 1849 | /// Parse a single record literal field. |
|
| 1834 | 1850 | /// Can be either labeled, or shorthand. |
|
| 1835 | - | unsafe fn parseRecordLitField(p: &mut Parser) -> *ast::Node |
|
| 1851 | + | unsafe fn parseRecordLitField 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1836 | 1852 | throws (ParseError) |
|
| 1837 | 1853 | { |
|
| 1838 | 1854 | let name = try parseIdent(p, "expected field name"); |
|
| 1839 | 1855 | if consume(p, scanner::TokenKind::Colon) { |
|
| 1840 | 1856 | // Labeled field: `name: value`. |
| 1850 | 1866 | } |
|
| 1851 | 1867 | ||
| 1852 | 1868 | /// Parse a record literal body. |
|
| 1853 | 1869 | /// Eg. `{ x: 1, y: 2 }` |
|
| 1854 | 1870 | /// Eg. `{ x: 1, .. }` |
|
| 1855 | - | unsafe fn parseRecordLit(p: &mut Parser, typeName: ?*ast::Node) -> *ast::Node |
|
| 1871 | + | unsafe fn parseRecordLit 'pool (p: &mut Parser 'pool, typeName: ?*ast::Node) -> *ast::Node |
|
| 1856 | 1872 | throws (ParseError) |
|
| 1857 | 1873 | { |
|
| 1858 | 1874 | let mut fields = ast::nodeSlice(p.arena, MAX_RECORD_FIELDS); |
|
| 1859 | 1875 | let mut ignoreRest = false; |
|
| 1860 | 1876 | try expect(p, scanner::TokenKind::LBrace, "expected `{` to begin record literal"); |
| 1879 | 1895 | )); |
|
| 1880 | 1896 | } |
|
| 1881 | 1897 | ||
| 1882 | 1898 | /// Parse a named record declaration. |
|
| 1883 | 1899 | /// `record Point { x: i32, y: i32 }`, or `record Pair(i32, i32);` |
|
| 1884 | - | unsafe fn parseRecordDecl(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 1900 | + | unsafe fn parseRecordDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 1885 | 1901 | throws (ParseError) |
|
| 1886 | 1902 | { |
|
| 1887 | 1903 | try expect(p, scanner::TokenKind::Record, "expected `record`"); |
|
| 1888 | 1904 | ||
| 1889 | 1905 | let name = try parseIdent(p, "expected record name"); |
| 1911 | 1927 | } |
|
| 1912 | 1928 | } |
|
| 1913 | 1929 | ||
| 1914 | 1930 | /// Parse a union declaration. |
|
| 1915 | 1931 | /// Example: `union Color { Red, Green, Blue = 5 }` |
|
| 1916 | - | unsafe fn parseUnionDecl(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 1932 | + | unsafe fn parseUnionDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 1917 | 1933 | throws (ParseError) |
|
| 1918 | 1934 | { |
|
| 1919 | 1935 | try expect(p, scanner::TokenKind::Union, "expected `union`"); |
|
| 1920 | 1936 | ||
| 1921 | 1937 | let name = try parseIdent(p, "expected union name"); |
| 1972 | 1988 | } |
|
| 1973 | 1989 | )); |
|
| 1974 | 1990 | } |
|
| 1975 | 1991 | ||
| 1976 | 1992 | /// Parse a function parameter. |
|
| 1977 | - | unsafe fn parseFnParam(p: &mut Parser) -> *ast::Node |
|
| 1993 | + | unsafe fn parseFnParam 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 1978 | 1994 | throws (ParseError) |
|
| 1979 | 1995 | { |
|
| 1980 | 1996 | let ntv = try parseNameTypeValue(p); |
|
| 1981 | 1997 | let type = ntv.type |
|
| 1982 | 1998 | else throw failParsing(p, "missing type in function parameter"); |
| 1985 | 2001 | ast::FnParam { name: ntv.name, type } |
|
| 1986 | 2002 | )); |
|
| 1987 | 2003 | } |
|
| 1988 | 2004 | ||
| 1989 | 2005 | /// Parse an optional `throws` clause and return the collected type list. |
|
| 1990 | - | unsafe fn parseThrowList(p: &mut Parser) -> *mut [*ast::Node] |
|
| 2006 | + | unsafe fn parseThrowList 'pool (p: &mut Parser 'pool) -> *mut [*ast::Node] |
|
| 1991 | 2007 | throws (ParseError) |
|
| 1992 | 2008 | { |
|
| 1993 | 2009 | if not consume(p, scanner::TokenKind::Throws) { |
|
| 1994 | 2010 | return ast::nodeSlice(p.arena, 0); |
|
| 1995 | 2011 | } |
|
| 1996 | 2012 | return try parseList( |
|
| 1997 | 2013 | p, |
|
| 1998 | 2014 | scanner::TokenKind::LParen, |
|
| 1999 | 2015 | scanner::TokenKind::RParen, |
|
| 2000 | - | parseType |
|
| 2016 | + | parseType 'pool |
|
| 2001 | 2017 | ); |
|
| 2002 | 2018 | } |
|
| 2003 | 2019 | ||
| 2004 | 2020 | /// Parse a function type signature. |
|
| 2005 | - | unsafe fn parseFnType(p: &mut Parser) -> *ast::Node |
|
| 2021 | + | unsafe fn parseFnType 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 2006 | 2022 | throws (ParseError) |
|
| 2007 | 2023 | { |
|
| 2008 | 2024 | let isUnsafe = consume(p, scanner::TokenKind::Unsafe); |
|
| 2009 | 2025 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
|
| 2010 | 2026 | let params = try parseList( |
|
| 2011 | 2027 | p, |
|
| 2012 | 2028 | scanner::TokenKind::LParen, |
|
| 2013 | 2029 | scanner::TokenKind::RParen, |
|
| 2014 | - | parseType |
|
| 2030 | + | parseType 'pool |
|
| 2015 | 2031 | ); |
|
| 2016 | 2032 | let mut returnType: ?*ast::Node = nil; |
|
| 2017 | 2033 | ||
| 2018 | 2034 | if consume(p, scanner::TokenKind::Arrow) { |
|
| 2019 | 2035 | set returnType = try parseReturnType(p); |
| 2024 | 2040 | ast::TypeSig::Fn { sig, isUnsafe } |
|
| 2025 | 2041 | )); |
|
| 2026 | 2042 | } |
|
| 2027 | 2043 | ||
| 2028 | 2044 | /// Parse a function signature following the function name. |
|
| 2029 | - | unsafe fn parseFnTypeSig(p: &mut Parser) -> ast::FnSig |
|
| 2045 | + | unsafe fn parseFnTypeSig 'pool (p: &mut Parser 'pool) -> ast::FnSig |
|
| 2030 | 2046 | throws (ParseError) |
|
| 2031 | 2047 | { |
|
| 2032 | 2048 | try expect(p, scanner::TokenKind::LParen, "expected `(` after function name"); |
|
| 2033 | 2049 | let mut params = ast::nodeSlice(p.arena, 8); |
|
| 2034 | 2050 |
| 2050 | 2066 | ||
| 2051 | 2067 | return ast::FnSig { params, returnType, throwList }; |
|
| 2052 | 2068 | } |
|
| 2053 | 2069 | ||
| 2054 | 2070 | /// Parse a function return type, including the uninhabited type. |
|
| 2055 | - | unsafe fn parseReturnType(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 2071 | + | unsafe fn parseReturnType 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 2056 | 2072 | if consume(p, scanner::TokenKind::Bang) { |
|
| 2057 | 2073 | return node(p, ast::NodeValue::TypeSig(ast::TypeSig::Never)); |
|
| 2058 | 2074 | } |
|
| 2059 | 2075 | return try parseType(p); |
|
| 2060 | 2076 | } |
|
| 2061 | 2077 | ||
| 2062 | 2078 | /// Parse a function declaration. |
|
| 2063 | - | unsafe fn parseFnDecl(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2079 | + | unsafe fn parseFnDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2064 | 2080 | throws (ParseError) |
|
| 2065 | 2081 | { |
|
| 2066 | 2082 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
|
| 2067 | 2083 | ||
| 2068 | 2084 | // Method syntax: `fn (recv: *Type) name(params) { body }`. |
| 2097 | 2113 | ast::FnDecl { name, regions, sig, body, attrs: fnAttrs } |
|
| 2098 | 2114 | )); |
|
| 2099 | 2115 | } |
|
| 2100 | 2116 | ||
| 2101 | 2117 | /// Parse a pointer-like type after its ownership prefix. |
|
| 2102 | - | unsafe fn parsePointerLikeType( |
|
| 2103 | - | p: &mut Parser, |
|
| 2118 | + | unsafe fn parsePointerLikeType 'pool ( |
|
| 2119 | + | p: &mut Parser 'pool, |
|
| 2104 | 2120 | class: ast::PointerClass, |
|
| 2105 | 2121 | ) -> *ast::Node throws (ParseError) { |
|
| 2106 | 2122 | if check(p, scanner::TokenKind::Ident) and mem::eq(p.current.source, "cell") { |
|
| 2107 | 2123 | advance(p); |
|
| 2108 | 2124 | let payload = try parseType(p); |
| 2138 | 2154 | ast::TypeSig::Pointer { class, valueType, mutable } |
|
| 2139 | 2155 | )); |
|
| 2140 | 2156 | } |
|
| 2141 | 2157 | ||
| 2142 | 2158 | /// Parse an array type. |
|
| 2143 | - | unsafe fn parseArrayType(p: &mut Parser) -> *ast::Node |
|
| 2159 | + | unsafe fn parseArrayType 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 2144 | 2160 | throws (ParseError) |
|
| 2145 | 2161 | { |
|
| 2146 | 2162 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
|
| 2147 | 2163 | let itemType = try parseType(p); |
|
| 2148 | 2164 |
| 2155 | 2171 | )); |
|
| 2156 | 2172 | } |
|
| 2157 | 2173 | ||
| 2158 | 2174 | /// Parse a type path: an identifier optionally followed by `::` scope access. |
|
| 2159 | 2175 | /// Returns an identifier node or a scope access chain. |
|
| 2160 | - | unsafe fn parseTypePath(p: &mut Parser) -> *ast::Node |
|
| 2176 | + | unsafe fn parseTypePath 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 2161 | 2177 | throws (ParseError) |
|
| 2162 | 2178 | { |
|
| 2163 | 2179 | let mut path: *ast::Node = undefined; |
|
| 2164 | 2180 | if p.current.kind == scanner::TokenKind::Super { |
|
| 2165 | 2181 | advance(p); |
| 2175 | 2191 | } |
|
| 2176 | 2192 | return path; |
|
| 2177 | 2193 | } |
|
| 2178 | 2194 | ||
| 2179 | 2195 | /// Parse a type annotation. |
|
| 2180 | - | export unsafe fn parseType(p: &mut Parser) -> *ast::Node |
|
| 2196 | + | export unsafe fn parseType 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 2181 | 2197 | throws (ParseError) |
|
| 2182 | 2198 | { |
|
| 2183 | 2199 | match p.current.kind { |
|
| 2184 | 2200 | case scanner::TokenKind::Question => { |
|
| 2185 | 2201 | advance(p); |
| 2272 | 2288 | ||
| 2273 | 2289 | /// Parse a name, optional type, and optional value. |
|
| 2274 | 2290 | /// |
|
| 2275 | 2291 | /// Used for record field declarations, variable declarations, |
|
| 2276 | 2292 | /// and record field initializations. |
|
| 2277 | - | unsafe fn parseNameTypeValue(p: &mut Parser) -> NameTypeValue |
|
| 2293 | + | unsafe fn parseNameTypeValue 'pool (p: &mut Parser 'pool) -> NameTypeValue |
|
| 2278 | 2294 | throws (ParseError) |
|
| 2279 | 2295 | { |
|
| 2280 | 2296 | let name = try parseIdentOrPlaceholder(p, "expected identifier or `_`"); |
|
| 2281 | 2297 | let mut type: ?*ast::Node = nil; |
|
| 2282 | 2298 | let mut alignment: ?*ast::Node = nil; |
| 2294 | 2310 | } |
|
| 2295 | 2311 | return NameTypeValue { name, type, value, alignment }; |
|
| 2296 | 2312 | } |
|
| 2297 | 2313 | ||
| 2298 | 2314 | /// Parse a constant declaration. |
|
| 2299 | - | unsafe fn parseConst(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2315 | + | unsafe fn parseConst 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2300 | 2316 | throws (ParseError) |
|
| 2301 | 2317 | { |
|
| 2302 | 2318 | try expect(p, scanner::TokenKind::Constant, "expected `constant`"); |
|
| 2303 | 2319 | ||
| 2304 | 2320 | let ident = try parseIdent(p, "expected identifier in constant declaration"); |
| 2313 | 2329 | ast::ConstDecl { ident, type, value, attrs } |
|
| 2314 | 2330 | )); |
|
| 2315 | 2331 | } |
|
| 2316 | 2332 | ||
| 2317 | 2333 | /// Parse a static declaration. |
|
| 2318 | - | unsafe fn parseStatic(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2334 | + | unsafe fn parseStatic 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2319 | 2335 | throws (ParseError) |
|
| 2320 | 2336 | { |
|
| 2321 | 2337 | try expect(p, scanner::TokenKind::Static, "expected `static`"); |
|
| 2322 | 2338 | ||
| 2323 | 2339 | let ident = try parseIdent(p, "expected identifier in static declaration"); |
| 2332 | 2348 | ast::StaticDecl { ident, type, value, attrs } |
|
| 2333 | 2349 | )); |
|
| 2334 | 2350 | } |
|
| 2335 | 2351 | ||
| 2336 | 2352 | /// Parse a `use` declaration. |
|
| 2337 | - | unsafe fn parseUse(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2353 | + | unsafe fn parseUse 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2338 | 2354 | throws (ParseError) |
|
| 2339 | 2355 | { |
|
| 2340 | 2356 | try expect(p, scanner::TokenKind::Use, "expected `use`"); |
|
| 2341 | 2357 | ||
| 2342 | 2358 | // Allow `super` or identifier as the first part of the path. |
| 2362 | 2378 | ast::Use { path, wildcard: false, attrs } |
|
| 2363 | 2379 | )); |
|
| 2364 | 2380 | } |
|
| 2365 | 2381 | ||
| 2366 | 2382 | /// Parse a `mod` declaration. |
|
| 2367 | - | unsafe fn parseMod(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2383 | + | unsafe fn parseMod 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2368 | 2384 | throws (ParseError) |
|
| 2369 | 2385 | { |
|
| 2370 | 2386 | try expect(p, scanner::TokenKind::Mod, "expected `mod`"); |
|
| 2371 | 2387 | let name = try parseIdent(p, "expected module name after `mod`"); |
|
| 2372 | 2388 |
| 2379 | 2395 | /// |
|
| 2380 | 2396 | /// Eg. `let case <pattern> = <expr> else { ... };` |
|
| 2381 | 2397 | /// Eg. `let case <pattern> = <expr> if <guard> else { ... };` |
|
| 2382 | 2398 | /// |
|
| 2383 | 2399 | /// Expects `let case` tokens to have already been consumed. |
|
| 2384 | - | unsafe fn parseLetCase(p: &mut Parser) -> *ast::Node throws (ParseError) { |
|
| 2400 | + | unsafe fn parseLetCase 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
|
| 2385 | 2401 | let pattern = try parseMatchPattern(p); |
|
| 2386 | 2402 | ||
| 2387 | 2403 | try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern"); |
|
| 2388 | 2404 | let expr = try parseCond(p); |
|
| 2389 | 2405 |
| 2408 | 2424 | /// Eg. `let mut <ident> = <expr> else { ... };` |
|
| 2409 | 2425 | /// Eg. `let <ident> = <expr> if <guard> else { ... };` |
|
| 2410 | 2426 | /// Eg. `mut <ident> = <expr>;` |
|
| 2411 | 2427 | /// |
|
| 2412 | 2428 | /// Expects `let` or `mut` token to have already been consumed. |
|
| 2413 | - | unsafe fn parseLet(p: &mut Parser, mutable: bool) -> *ast::Node throws (ParseError) { |
|
| 2429 | + | unsafe fn parseLet 'pool (p: &mut Parser 'pool, mutable: bool) -> *ast::Node throws (ParseError) { |
|
| 2414 | 2430 | let binding = try parseNameTypeValue(p); |
|
| 2415 | 2431 | let value = binding.value |
|
| 2416 | 2432 | else throw failParsing(p, "expected value initializer"); |
|
| 2417 | 2433 | ||
| 2418 | 2434 | // Check for optional `else` clause (let-else). |
| 2428 | 2444 | ident: binding.name, type: binding.type, value, alignment: binding.alignment, mutable, |
|
| 2429 | 2445 | })); |
|
| 2430 | 2446 | } |
|
| 2431 | 2447 | ||
| 2432 | 2448 | /// Parse a module from source text using the provided arena for node storage. |
|
| 2433 | - | export unsafe fn parse(sourceLoc: scanner::SourceLoc, input: *[u8], arena: &mut ast::NodeArena, pool: *unsafe mut strings::Pool) -> *mut ast::Node |
|
| 2449 | + | export unsafe fn parse(sourceLoc: scanner::SourceLoc, input: *[u8], arena: &mut ast::NodeArena, pool: &mut strings::Pool) -> *mut ast::Node |
|
| 2434 | 2450 | throws (ParseError) |
|
| 2435 | 2451 | { |
|
| 2436 | - | let mut p = mkParser(sourceLoc, input, arena, pool); |
|
| 2437 | - | return try parseModule(&mut p) catch { |
|
| 2438 | - | printErrors(&p); |
|
| 2439 | - | throw ParseError::UnexpectedToken; |
|
| 2440 | - | }; |
|
| 2452 | + | let poolRef: 'pool = &mut *pool in { |
|
| 2453 | + | let mut p = mkParser(sourceLoc, input, arena, poolRef); |
|
| 2454 | + | return try parseModule(&mut p) catch { |
|
| 2455 | + | printErrors(&p); |
|
| 2456 | + | throw ParseError::UnexpectedToken; |
|
| 2457 | + | }; |
|
| 2458 | + | } |
|
| 2441 | 2459 | } |
|
| 2442 | 2460 | ||
| 2443 | 2461 | /// Parse a complete module into a block of top-level statements. |
|
| 2444 | 2462 | /// |
|
| 2445 | 2463 | /// This is the main entry point for parsing an entire Radiance source file. |
|
| 2446 | 2464 | /// The parser must already be initialized with source code. |
|
| 2447 | - | export unsafe fn parseModule(p: &mut Parser) -> *mut ast::Node |
|
| 2465 | + | export unsafe fn parseModule 'pool (p: &mut Parser 'pool) -> *mut ast::Node |
|
| 2448 | 2466 | throws (ParseError) |
|
| 2449 | 2467 | { |
|
| 2450 | 2468 | advance(p); // Set the parser up with a first token. |
|
| 2451 | 2469 | ||
| 2452 | 2470 | let statements = try parseStmtsUntil(p, scanner::TokenKind::Eof, 512); |
| 2455 | 2473 | ||
| 2456 | 2474 | return node(p, ast::NodeValue::Block(blk)); |
|
| 2457 | 2475 | } |
|
| 2458 | 2476 | ||
| 2459 | 2477 | /// Consume a token of the given kind if present. |
|
| 2460 | - | export unsafe fn consume(p: &mut Parser, kind: scanner::TokenKind) -> bool { |
|
| 2478 | + | export fn consume 'pool (p: &mut Parser 'pool, kind: scanner::TokenKind) -> bool { |
|
| 2461 | 2479 | if check(p, kind) { |
|
| 2462 | 2480 | advance(p); |
|
| 2463 | 2481 | return true; |
|
| 2464 | 2482 | } |
|
| 2465 | 2483 | return false; |
|
| 2466 | 2484 | } |
|
| 2467 | 2485 | ||
| 2468 | 2486 | /// Expect a token of the given kind or report an error. |
|
| 2469 | - | export unsafe fn expect(p: &mut Parser, kind: scanner::TokenKind, message: *[u8]) -> *[u8] |
|
| 2487 | + | export fn expect 'pool (p: &mut Parser 'pool, kind: scanner::TokenKind, message: *[u8]) -> *[u8] |
|
| 2470 | 2488 | throws (ParseError) |
|
| 2471 | 2489 | { |
|
| 2472 | 2490 | if not consume(p, kind) { |
|
| 2473 | 2491 | let token = p.current; |
|
| 2474 | 2492 | reportError(p, token, message); |
| 2490 | 2508 | } |
|
| 2491 | 2509 | } |
|
| 2492 | 2510 | ||
| 2493 | 2511 | /// Parse a trait declaration. |
|
| 2494 | 2512 | /// Syntax: `trait Name { fn (*Trait) method(...) -> T; ... }` |
|
| 2495 | - | unsafe fn parseTraitDecl(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2513 | + | unsafe fn parseTraitDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2496 | 2514 | throws (ParseError) |
|
| 2497 | 2515 | { |
|
| 2498 | 2516 | try expect(p, scanner::TokenKind::Trait, "expected `trait`"); |
|
| 2499 | 2517 | let name = try parseIdent(p, "expected trait name"); |
|
| 2500 | 2518 | let supertraits = try parseDerives(p); |
| 2512 | 2530 | return node(p, ast::NodeValue::TraitDecl { name, supertraits, methods, attrs }); |
|
| 2513 | 2531 | } |
|
| 2514 | 2532 | ||
| 2515 | 2533 | /// Parse a trait method signature. |
|
| 2516 | 2534 | /// Syntax: `fn (*Trait) fnord(<params>) -> ReturnType;` |
|
| 2517 | - | unsafe fn parseTraitMethodSig(p: &mut Parser) -> *ast::Node |
|
| 2535 | + | unsafe fn parseTraitMethodSig 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 2518 | 2536 | throws (ParseError) |
|
| 2519 | 2537 | { |
|
| 2520 | 2538 | let attrs = parseAttributes(p); |
|
| 2521 | 2539 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
|
| 2522 | 2540 | try expect(p, scanner::TokenKind::LParen, "expected `(` before receiver"); |
| 2541 | 2559 | /// Parse an instance block. |
|
| 2542 | 2560 | /// Syntax: `instance Trait for Type { fn (t: *mut Type) fnord(..) {..} }` |
|
| 2543 | 2561 | /// |
|
| 2544 | 2562 | /// Instance declarations do not accept attributes (e.g. `export`). |
|
| 2545 | 2563 | /// Visibility is determined by the trait declaration itself. |
|
| 2546 | - | unsafe fn parseInstanceDecl(p: &mut Parser) -> *ast::Node |
|
| 2564 | + | unsafe fn parseInstanceDecl 'pool (p: &mut Parser 'pool) -> *ast::Node |
|
| 2547 | 2565 | throws (ParseError) |
|
| 2548 | 2566 | { |
|
| 2549 | 2567 | try expect(p, scanner::TokenKind::Instance, "expected `instance`"); |
|
| 2550 | 2568 | let traitName = try parseTypePath(p); |
|
| 2551 | 2569 | try expect(p, scanner::TokenKind::For, "expected `for` after trait name"); |
| 2573 | 2591 | /// Parse a method declaration with a receiver. |
|
| 2574 | 2592 | /// Syntax: `fn (t: *mut Type) fnord(<params>) -> ReturnType { body }` |
|
| 2575 | 2593 | /// |
|
| 2576 | 2594 | /// Used both inside `instance` blocks and as standalone methods at the top level. |
|
| 2577 | 2595 | /// Expects the `fn` token to have already been consumed. |
|
| 2578 | - | unsafe fn parseMethodDecl(p: &mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2596 | + | unsafe fn parseMethodDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2579 | 2597 | throws (ParseError) |
|
| 2580 | 2598 | { |
|
| 2581 | 2599 | try expect(p, scanner::TokenKind::LParen, "expected `(` before receiver"); |
|
| 2582 | 2600 | ||
| 2583 | 2601 | let receiverName = try parseIdent(p, "expected receiver name"); |
| 2600 | 2618 | name, modifiers, receiverName, receiverType, sig, body, |
|
| 2601 | 2619 | }); |
|
| 2602 | 2620 | } |
|
| 2603 | 2621 | ||
| 2604 | 2622 | /// Parse a comma-separated list enclosed by the given delimiters. |
|
| 2605 | - | unsafe fn parseList( |
|
| 2606 | - | p: &mut Parser, |
|
| 2623 | + | unsafe fn parseList 'pool ( |
|
| 2624 | + | p: &mut Parser 'pool, |
|
| 2607 | 2625 | open: scanner::TokenKind, |
|
| 2608 | 2626 | close: scanner::TokenKind, |
|
| 2609 | - | parseItem: unsafe fn (&mut Parser) -> *ast::Node throws (ParseError) |
|
| 2627 | + | parseItem: unsafe fn (&mut Parser 'pool) -> *ast::Node throws (ParseError) |
|
| 2610 | 2628 | ) -> *mut [*ast::Node] throws (ParseError) { |
|
| 2611 | 2629 | try expect(p, open, listExpectMessage(open)); |
|
| 2612 | 2630 | let mut items = ast::nodeSlice(p.arena, 8); |
|
| 2613 | 2631 | ||
| 2614 | 2632 | while not check(p, close) { |
lib/std/lang/parser/tests.rad
+135 -90
| 68 | 68 | } else { |
|
| 69 | 69 | try testing::expect(range.end == nil); |
|
| 70 | 70 | } |
|
| 71 | 71 | } |
|
| 72 | 72 | ||
| 73 | + | /// Token operations use the parser's checked pool borrow. |
|
| 74 | + | fn checkTokenOperations 'pool (p: &mut super::Parser 'pool) throws (testing::TestError) { |
|
| 75 | + | super::advance(p); |
|
| 76 | + | let name = try super::expect(p, scanner::TokenKind::Ident, "expected name") catch { |
|
| 77 | + | throw testing::TestError::Failed; |
|
| 78 | + | }; |
|
| 79 | + | try testing::expectBytesEq(name, "alpha"); |
|
| 80 | + | try testing::expect(super::consume(p, scanner::TokenKind::Comma)); |
|
| 81 | + | try testing::expect(not super::consume(p, scanner::TokenKind::Comma)); |
|
| 82 | + | try testing::expect(super::check(p, scanner::TokenKind::Ident)); |
|
| 83 | + | super::advance(p); |
|
| 84 | + | try testing::expect(super::check(p, scanner::TokenKind::Eof)); |
|
| 85 | + | } |
|
| 86 | + | ||
| 87 | + | /// Scanner state can advance without an unsafe token operation. |
|
| 88 | + | @test unsafe fn testSafeTokenOperations() throws (testing::TestError) { |
|
| 89 | + | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 90 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 91 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, "alpha, beta", &mut arena, poolRef); |
|
| 92 | + | try checkTokenOperations(&mut parser); |
|
| 93 | + | } |
|
| 94 | + | } |
|
| 95 | + | ||
| 73 | 96 | /// Parse multiple statements from a string. |
|
| 74 | 97 | unsafe fn parseStmtsStr(input: *[u8]) -> *ast::Node |
|
| 75 | 98 | throws (testing::TestError) |
|
| 76 | 99 | { |
|
| 77 | 100 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 78 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, &mut STRING_POOL); |
|
| 79 | - | return try super::parseModule(&mut parser) catch { |
|
| 80 | - | throw testing::TestError::Failed; |
|
| 81 | - | }; |
|
| 101 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 102 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, poolRef); |
|
| 103 | + | return try super::parseModule(&mut parser) catch { |
|
| 104 | + | throw testing::TestError::Failed; |
|
| 105 | + | }; |
|
| 106 | + | } |
|
| 82 | 107 | } |
|
| 83 | 108 | ||
| 84 | 109 | /// Parse a single type from a string. |
|
| 85 | 110 | unsafe fn parseTypeStr(input: *[u8]) -> *ast::Node |
|
| 86 | 111 | throws (super::ParseError) |
|
| 87 | 112 | { |
|
| 88 | 113 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 89 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, &mut STRING_POOL); |
|
| 90 | - | super::advance(&mut parser); |
|
| 91 | - | let root = try super::parseType(&mut parser); |
|
| 92 | - | try super::expect(&mut parser, scanner::TokenKind::Eof, "expected end of type"); |
|
| 114 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 115 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, poolRef); |
|
| 116 | + | super::advance(&mut parser); |
|
| 117 | + | let root = try super::parseType(&mut parser); |
|
| 118 | + | try super::expect(&mut parser, scanner::TokenKind::Eof, "expected end of type"); |
|
| 93 | 119 | ||
| 94 | - | return root; |
|
| 120 | + | return root; |
|
| 121 | + | } |
|
| 95 | 122 | } |
|
| 96 | 123 | ||
| 97 | 124 | /// Parse a single expression from a string. |
|
| 98 | 125 | export unsafe fn parseExprStr(input: *[u8]) -> *ast::Node |
|
| 99 | 126 | throws (super::ParseError) |
|
| 100 | 127 | { |
|
| 101 | 128 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 102 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, &mut STRING_POOL); |
|
| 103 | - | super::advance(&mut parser); |
|
| 104 | - | return try super::parseExpr(&mut parser); |
|
| 129 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 130 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, poolRef); |
|
| 131 | + | super::advance(&mut parser); |
|
| 132 | + | return try super::parseExpr(&mut parser); |
|
| 133 | + | } |
|
| 105 | 134 | } |
|
| 106 | 135 | ||
| 107 | 136 | /// Parse a single statement from a string. |
|
| 108 | 137 | unsafe fn parseStmtStr(input: *[u8]) -> *ast::Node |
|
| 109 | 138 | throws (super::ParseError) |
|
| 110 | 139 | { |
|
| 111 | 140 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 112 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, &mut STRING_POOL); |
|
| 113 | - | super::advance(&mut parser); |
|
| 114 | - | let root = try super::parseStmt(&mut parser); |
|
| 115 | - | while super::consume(&mut parser, scanner::TokenKind::Semicolon) {} |
|
| 116 | - | try super::expect(&mut parser, scanner::TokenKind::Eof, "expected end of statement"); |
|
| 141 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 142 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, input, &mut arena, poolRef); |
|
| 143 | + | super::advance(&mut parser); |
|
| 144 | + | let root = try super::parseStmt(&mut parser); |
|
| 145 | + | while super::consume(&mut parser, scanner::TokenKind::Semicolon) {} |
|
| 146 | + | try super::expect(&mut parser, scanner::TokenKind::Eof, "expected end of statement"); |
|
| 117 | 147 | ||
| 118 | - | return root; |
|
| 148 | + | return root; |
|
| 149 | + | } |
|
| 119 | 150 | } |
|
| 120 | 151 | ||
| 121 | 152 | /// Parse an expression expected to be a number literal and return its payload. |
|
| 122 | 153 | unsafe fn parseNumberLiteral(text: *[u8]) -> fmt::IntLiteral |
|
| 123 | 154 | throws (testing::TestError) |
|
| 124 | 155 | { |
|
| 125 | 156 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 126 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, text, &mut arena, &mut STRING_POOL); |
|
| 127 | - | super::advance(&mut parser); |
|
| 157 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 158 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, text, &mut arena, poolRef); |
|
| 159 | + | super::advance(&mut parser); |
|
| 128 | 160 | ||
| 129 | - | let node = try! super::parseExpr(&mut parser); |
|
| 161 | + | let node = try! super::parseExpr(&mut parser); |
|
| 130 | 162 | ||
| 131 | - | if not super::check(&parser, scanner::TokenKind::Eof) { |
|
| 132 | - | throw testing::TestError::Failed; |
|
| 133 | - | } |
|
| 134 | - | let case ast::NodeValue::Number(lit) = node.value |
|
| 135 | - | else throw testing::TestError::Failed; |
|
| 163 | + | if not super::check(&parser, scanner::TokenKind::Eof) { |
|
| 164 | + | throw testing::TestError::Failed; |
|
| 165 | + | } |
|
| 166 | + | let case ast::NodeValue::Number(lit) = node.value |
|
| 167 | + | else throw testing::TestError::Failed; |
|
| 136 | 168 | ||
| 137 | - | return lit; |
|
| 169 | + | return lit; |
|
| 170 | + | } |
|
| 138 | 171 | } |
|
| 139 | 172 | ||
| 140 | 173 | /// Ensure that parsing the supplied literal source fails. |
|
| 141 | 174 | unsafe fn expectNumberLiteralFail(text: *[u8]) |
|
| 142 | 175 | throws (testing::TestError) |
|
| 143 | 176 | { |
|
| 144 | 177 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 145 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, text, &mut arena, &mut STRING_POOL); |
|
| 146 | - | super::advance(&mut parser); |
|
| 178 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 179 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, text, &mut arena, poolRef); |
|
| 180 | + | super::advance(&mut parser); |
|
| 147 | 181 | ||
| 148 | - | try super::parseExpr(&mut parser) catch { |
|
| 149 | - | return; |
|
| 150 | - | }; |
|
| 151 | - | if not super::check(&parser, scanner::TokenKind::Eof) { |
|
| 152 | - | return; |
|
| 182 | + | try super::parseExpr(&mut parser) catch { |
|
| 183 | + | return; |
|
| 184 | + | }; |
|
| 185 | + | if not super::check(&parser, scanner::TokenKind::Eof) { |
|
| 186 | + | return; |
|
| 187 | + | } |
|
| 188 | + | throw testing::TestError::Failed; |
|
| 153 | 189 | } |
|
| 154 | - | throw testing::TestError::Failed; |
|
| 155 | 190 | } |
|
| 156 | 191 | ||
| 157 | 192 | /// Assert that a node is a type signature matching the expected type. |
|
| 158 | 193 | fn expectType(node: *ast::Node, type: ast::TypeSig) |
|
| 159 | 194 | throws (testing::TestError) |
| 1123 | 1158 | } |
|
| 1124 | 1159 | ||
| 1125 | 1160 | /// Test scanning source-level `void` produces an identifier, not a type keyword. |
|
| 1126 | 1161 | @test unsafe fn testParseTypeVoidRejected() throws (testing::TestError) { |
|
| 1127 | 1162 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 1128 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, "void", &mut arena, &mut STRING_POOL); |
|
| 1129 | - | super::advance(&mut parser); |
|
| 1130 | - | try testing::expect(super::check(&parser, scanner::TokenKind::Ident)); |
|
| 1163 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 1164 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, "void", &mut arena, poolRef); |
|
| 1165 | + | super::advance(&mut parser); |
|
| 1166 | + | try testing::expect(super::check(&parser, scanner::TokenKind::Ident)); |
|
| 1167 | + | } |
|
| 1131 | 1168 | } |
|
| 1132 | 1169 | ||
| 1133 | 1170 | /// Test parsing the unsafe function modifier. |
|
| 1134 | 1171 | @test unsafe fn testParseUnsafeFnDecl() throws (testing::TestError) { |
|
| 1135 | 1172 | let node = try! parseStmtStr("unsafe fn run() {}"); |
| 3209 | 3246 | /// Measure committed storage for a statement after an existing node. |
|
| 3210 | 3247 | unsafe fn statementStorageUsed(source: *[u8]) -> u32 { |
|
| 3211 | 3248 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 3212 | 3249 | ast::allocNode(&mut arena, ast::Span { offset: 0, length: 0 }, ast::NodeValue::Bool(true)); |
|
| 3213 | 3250 | let start = alloc::used(&arena.arena); |
|
| 3214 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, source, &mut arena, &mut STRING_POOL); |
|
| 3215 | - | super::advance(&mut parser); |
|
| 3216 | - | try! super::parseStmt(&mut parser); |
|
| 3217 | - | return alloc::used(&arena.arena) - start; |
|
| 3251 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 3252 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, source, &mut arena, poolRef); |
|
| 3253 | + | super::advance(&mut parser); |
|
| 3254 | + | try! super::parseStmt(&mut parser); |
|
| 3255 | + | return alloc::used(&arena.arena) - start; |
|
| 3256 | + | } |
|
| 3218 | 3257 | } |
|
| 3219 | 3258 | ||
| 3220 | 3259 | /// Rewinding a failed expression preserves published nodes and source tokens. |
|
| 3221 | 3260 | @test unsafe fn testSpeculativeRestoreStorage() throws (testing::TestError) { |
|
| 3222 | 3261 | let expectedBytes = statementStorageUsed("return"); |
|
| 3223 | 3262 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 3224 | 3263 | let retained = ast::allocNode(&mut arena, ast::Span { offset: 3, length: 1 }, ast::NodeValue::Bool(true)); |
|
| 3225 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, |
|
| 3226 | - | "return [speculativeRestoreIdentifier, 1 +", &mut arena, &mut STRING_POOL); |
|
| 3227 | - | super::advance(&mut parser); |
|
| 3228 | - | try super::expect(&mut parser, scanner::TokenKind::Eof, "retained diagnostic") catch { |
|
| 3229 | - | }; |
|
| 3230 | - | let mut expected = parser; |
|
| 3231 | - | super::advance(&mut expected); |
|
| 3232 | - | let startOffset = alloc::used(&arena.arena); |
|
| 3233 | - | let startId = arena.nextId; |
|
| 3234 | - | let statement = try! super::parseStmt(&mut parser); |
|
| 3235 | - | let case ast::NodeValue::Return { value } = statement.value else throw testing::TestError::Failed; |
|
| 3236 | - | try testing::expect(value == nil); |
|
| 3237 | - | try testing::expect(statement.id == startId); |
|
| 3238 | - | try testing::expect(alloc::used(&arena.arena) == startOffset + expectedBytes); |
|
| 3239 | - | try testing::expect(arena.nextId == startId + 1); |
|
| 3240 | - | try testing::expect(parser.scanner.cursor == expected.scanner.cursor); |
|
| 3241 | - | try testing::expect(parser.scanner.token == expected.scanner.token); |
|
| 3242 | - | try testing::expect(parser.current.kind == expected.current.kind); |
|
| 3243 | - | try testing::expect(parser.current.offset == expected.current.offset); |
|
| 3244 | - | try testing::expect(parser.previous.kind == expected.previous.kind); |
|
| 3245 | - | try testing::expect(parser.previous.offset == expected.previous.offset); |
|
| 3246 | - | try testing::expect(parser.context == expected.context); |
|
| 3247 | - | try testing::expect(parser.errors.count == 1); |
|
| 3248 | - | for i in alloc::used(&arena.arena)..ARENA_STORAGE.len { |
|
| 3249 | - | set ARENA_STORAGE[i] = 0xA5; |
|
| 3264 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 3265 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, |
|
| 3266 | + | "return [speculativeRestoreIdentifier, 1 +", &mut arena, poolRef); |
|
| 3267 | + | super::advance(&mut parser); |
|
| 3268 | + | try super::expect(&mut parser, scanner::TokenKind::Eof, "retained diagnostic") catch { |
|
| 3269 | + | }; |
|
| 3270 | + | let mut expectedScanner = parser.scanner; |
|
| 3271 | + | let expectedCurrent = scanner::next(&mut expectedScanner, parser.pool); |
|
| 3272 | + | let expectedPrevious = parser.current; |
|
| 3273 | + | let expectedContext = parser.context; |
|
| 3274 | + | let startOffset = alloc::used(&arena.arena); |
|
| 3275 | + | let startId = arena.nextId; |
|
| 3276 | + | let statement = try! super::parseStmt(&mut parser); |
|
| 3277 | + | let case ast::NodeValue::Return { value } = statement.value else throw testing::TestError::Failed; |
|
| 3278 | + | try testing::expect(value == nil); |
|
| 3279 | + | try testing::expect(statement.id == startId); |
|
| 3280 | + | try testing::expect(alloc::used(&arena.arena) == startOffset + expectedBytes); |
|
| 3281 | + | try testing::expect(arena.nextId == startId + 1); |
|
| 3282 | + | try testing::expect(parser.scanner.cursor == expectedScanner.cursor); |
|
| 3283 | + | try testing::expect(parser.scanner.token == expectedScanner.token); |
|
| 3284 | + | try testing::expect(parser.current.kind == expectedCurrent.kind); |
|
| 3285 | + | try testing::expect(parser.current.offset == expectedCurrent.offset); |
|
| 3286 | + | try testing::expect(parser.previous.kind == expectedPrevious.kind); |
|
| 3287 | + | try testing::expect(parser.previous.offset == expectedPrevious.offset); |
|
| 3288 | + | try testing::expect(parser.context == expectedContext); |
|
| 3289 | + | try testing::expect(parser.errors.count == 1); |
|
| 3290 | + | for i in alloc::used(&arena.arena)..ARENA_STORAGE.len { |
|
| 3291 | + | set ARENA_STORAGE[i] = 0xA5; |
|
| 3292 | + | } |
|
| 3293 | + | let case ast::NodeValue::Bool(true) = retained.value else throw testing::TestError::Failed; |
|
| 3294 | + | try testing::expect(retained.span.offset == 3); |
|
| 3295 | + | try testing::expect(retained.span.length == 1); |
|
| 3296 | + | try testing::expect(mem::eq(parser.errors.list[0].message, "retained diagnostic")); |
|
| 3297 | + | try testing::expect(mem::eq(parser.errors.list[0].token.source, "return")); |
|
| 3298 | + | let interned = strings::find(parser.pool, "speculativeRestoreIdentifier") else throw testing::TestError::Failed; |
|
| 3299 | + | try testing::expect(mem::eq(interned, "speculativeRestoreIdentifier")); |
|
| 3300 | + | let replacement = ast::allocNode(&mut arena, ast::Span { offset: 0, length: 0 }, ast::NodeValue::Bool(false)); |
|
| 3301 | + | try testing::expect(replacement.id == startId + 1); |
|
| 3302 | + | let case ast::NodeValue::Bool(true) = retained.value else throw testing::TestError::Failed; |
|
| 3250 | 3303 | } |
|
| 3251 | - | let case ast::NodeValue::Bool(true) = retained.value else throw testing::TestError::Failed; |
|
| 3252 | - | try testing::expect(retained.span.offset == 3); |
|
| 3253 | - | try testing::expect(retained.span.length == 1); |
|
| 3254 | - | try testing::expect(mem::eq(parser.errors.list[0].message, "retained diagnostic")); |
|
| 3255 | - | try testing::expect(mem::eq(parser.errors.list[0].token.source, "return")); |
|
| 3256 | - | let interned = strings::find(&STRING_POOL, "speculativeRestoreIdentifier") else throw testing::TestError::Failed; |
|
| 3257 | - | try testing::expect(mem::eq(interned, "speculativeRestoreIdentifier")); |
|
| 3258 | - | let replacement = ast::allocNode(&mut arena, ast::Span { offset: 0, length: 0 }, ast::NodeValue::Bool(false)); |
|
| 3259 | - | try testing::expect(replacement.id == startId + 1); |
|
| 3260 | - | let case ast::NodeValue::Bool(true) = retained.value else throw testing::TestError::Failed; |
|
| 3261 | 3304 | } |
|
| 3262 | 3305 | ||
| 3263 | 3306 | /// Optional return and panic expressions publish only their wrapper after failure. |
|
| 3264 | 3307 | @test unsafe fn testSpeculativeStatementPublication() throws (testing::TestError) { |
|
| 3265 | 3308 | let expectedBytes = statementStorageUsed("return"); |
|
| 3266 | 3309 | for source in ["return (speculativeReturnIdentifier +", "panic (speculativePanicIdentifier +"] { |
|
| 3267 | 3310 | let mut arena = ast::nodeArena(&mut ARENA_STORAGE[..]); |
|
| 3268 | 3311 | ast::allocNode(&mut arena, ast::Span { offset: 0, length: 0 }, ast::NodeValue::Bool(true)); |
|
| 3269 | 3312 | let startOffset = alloc::used(&arena.arena); |
|
| 3270 | - | let mut parser = super::mkParser(scanner::SourceLoc::String, source, &mut arena, &mut STRING_POOL); |
|
| 3271 | - | super::advance(&mut parser); |
|
| 3272 | - | let startId = arena.nextId; |
|
| 3273 | - | let statement = try! super::parseStmt(&mut parser); |
|
| 3274 | - | try testing::expect(statement.id == startId); |
|
| 3275 | - | try testing::expect(arena.nextId == startId + 1); |
|
| 3276 | - | try testing::expect(alloc::used(&arena.arena) == startOffset + expectedBytes); |
|
| 3277 | - | try testing::expect(parser.errors.count == 0); |
|
| 3278 | - | try testing::expect(parser.current.kind == scanner::TokenKind::LParen); |
|
| 3279 | - | match statement.value { |
|
| 3280 | - | case ast::NodeValue::Return { value } => try testing::expect(value == nil), |
|
| 3281 | - | case ast::NodeValue::Panic { message } => try testing::expect(message == nil), |
|
| 3282 | - | else => throw testing::TestError::Failed, |
|
| 3313 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 3314 | + | let mut parser = super::mkParser(scanner::SourceLoc::String, source, &mut arena, poolRef); |
|
| 3315 | + | super::advance(&mut parser); |
|
| 3316 | + | let startId = arena.nextId; |
|
| 3317 | + | let statement = try! super::parseStmt(&mut parser); |
|
| 3318 | + | try testing::expect(statement.id == startId); |
|
| 3319 | + | try testing::expect(arena.nextId == startId + 1); |
|
| 3320 | + | try testing::expect(alloc::used(&arena.arena) == startOffset + expectedBytes); |
|
| 3321 | + | try testing::expect(parser.errors.count == 0); |
|
| 3322 | + | try testing::expect(parser.current.kind == scanner::TokenKind::LParen); |
|
| 3323 | + | match statement.value { |
|
| 3324 | + | case ast::NodeValue::Return { value } => try testing::expect(value == nil), |
|
| 3325 | + | case ast::NodeValue::Panic { message } => try testing::expect(message == nil), |
|
| 3326 | + | else => throw testing::TestError::Failed, |
|
| 3327 | + | } |
|
| 3283 | 3328 | } |
|
| 3284 | 3329 | } |
|
| 3285 | 3330 | } |
lib/std/lang/resolver/tests.rad
+11 -9
| 105 | 105 | } |
|
| 106 | 106 | ||
| 107 | 107 | /// Parse and analyze an expression string for testing. |
|
| 108 | 108 | unsafe fn resolveExprStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) { |
|
| 109 | 109 | let mut arena = ast::nodeArena(&mut AST_ARENA[..]); |
|
| 110 | - | let mut p = parser::mkParser(scanner::SourceLoc::String, stmt, &mut arena, &mut STRING_POOL); |
|
| 111 | - | parser::advance(&mut p); |
|
| 110 | + | let poolRef: 'pool = &mut STRING_POOL in { |
|
| 111 | + | let mut p = parser::mkParser(scanner::SourceLoc::String, stmt, &mut arena, poolRef); |
|
| 112 | + | parser::advance(&mut p); |
|
| 112 | 113 | ||
| 113 | - | let expr = try parser::parseExpr(&mut p) catch { |
|
| 114 | - | panic "resolveExprStr: parsing failed"; |
|
| 115 | - | }; |
|
| 116 | - | let diagnostics = try super::resolveExpr(self, expr, &mut arena) catch { |
|
| 117 | - | throw testing::TestError::Failed; |
|
| 118 | - | }; |
|
| 119 | - | return TestResult { diagnostics, root: expr }; |
|
| 114 | + | let expr = try parser::parseExpr(&mut p) catch { |
|
| 115 | + | panic "resolveExprStr: parsing failed"; |
|
| 116 | + | }; |
|
| 117 | + | let diagnostics = try super::resolveExpr(self, expr, &mut arena) catch { |
|
| 118 | + | throw testing::TestError::Failed; |
|
| 119 | + | }; |
|
| 120 | + | return TestResult { diagnostics, root: expr }; |
|
| 121 | + | } |
|
| 120 | 122 | } |
|
| 121 | 123 | ||
| 122 | 124 | /// Parse and analyze a module string for testing. |
|
| 123 | 125 | /// Use this for code with `fn`, `record`, `union`, etc. at the top level. |
|
| 124 | 126 | export unsafe fn resolveProgramStr 'arena (self: &mut super::Resolver 'arena, stmt: *[u8]) -> TestResult throws (testing::TestError) { |