compiler: Borrow parser string pools without copying snapshots

929c447c0daba09a85c93ee38046cec627475bde163cb3ec374e3aa8394a2008
Alexis Sellier committed ago 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) {