Fix parser bug with speculative parsing

19053951a14546126547aec491eb0f1304083e5e9aa52777fde1c3efa168b5d7
Alexis Sellier committed ago 1 parent 3ca028fc
lib/std/lang/parser.rad +39 -1
75 75
    list: [Error; MAX_ERRORS],
76 76
    /// Number of errors currently in the list.
77 77
    count: u32,
78 78
}
79 79
80 +
/// Snapshot of parser state for speculative parsing.
81 +
record SavedState {
82 +
    parser: Parser,
83 +
    arena: u32,
84 +
    nextId: u32,
85 +
}
86 +
80 87
/// Operator metadata for precedence climbing.
81 88
record OpInfo {
82 89
    op: ast::BinaryOp,
83 90
    prec: i32,
84 91
}
1139 1146
    } else {
1140 1147
        node.span.length = 0;
1141 1148
    }
1142 1149
}
1143 1150
1151 +
/// Save parser state for speculative parsing.
1152 +
fn saveState(p: *Parser) -> SavedState {
1153 +
    return SavedState {
1154 +
        parser: *p,
1155 +
        arena: alloc::save(&p.arena.arena),
1156 +
        nextId: p.arena.nextId,
1157 +
    };
1158 +
}
1159 +
1160 +
/// Restore parser state from a snapshot, fully undoing any
1161 +
/// side effects of a failed speculative parse.
1162 +
fn restoreState(p: *mut Parser, s: *SavedState) {
1163 +
    *p = s.parser;
1164 +
    alloc::restore(&mut p.arena.arena, s.arena);
1165 +
    p.arena.nextId = s.nextId;
1166 +
}
1167 +
1144 1168
/// Report a parser error.
1145 1169
fn reportError(p: *mut Parser, token: scanner::Token, message: *[u8]) {
1146 1170
    assert message.len > 0;
1147 1171
1148 1172
    // Ignore errors once the error list is full.
1347 1371
/// Parse a `return` statement.
1348 1372
fn parseReturn(p: *mut Parser) -> *ast::Node
1349 1373
    throws (ParseError)
1350 1374
{
1351 1375
    try expect(p, scanner::TokenKind::Return, "expected `return`");
1352 -
    let value: ?*ast::Node = try? parseExpr(p);
1353 1376
1377 +
    // Speculatively try to parse a return value expression.
1378 +
    let saved = saveState(p);
1379 +
    let value: ?*ast::Node = try? parseExpr(p);
1380 +
    if value == nil {
1381 +
        restoreState(p, &saved);
1382 +
    }
1354 1383
    return node(p, ast::NodeValue::Return { value });
1355 1384
}
1356 1385
1357 1386
/// Parse a `throw` statement.
1358 1387
fn parseThrow(p: *mut Parser) -> *ast::Node
1375 1404
        let message: ?*ast::Node = try parseExpr(p);
1376 1405
        try expect(p, scanner::TokenKind::RBrace, "expected closing `}` after expression");
1377 1406
        return node(p, ast::NodeValue::Panic { message });
1378 1407
    }
1379 1408
    // `panic` or `panic "message"`.
1409 +
    let saved = saveState(p);
1380 1410
    let message: ?*ast::Node = try? parseExpr(p);
1411 +
    if message == nil {
1412 +
        restoreState(p, &saved);
1413 +
    }
1381 1414
    return node(p, ast::NodeValue::Panic { message });
1382 1415
}
1383 1416
1384 1417
/// Parse an `assert` statement.
1385 1418
///
1566 1599
            patterns.append(pattern, p.allocator);
1567 1600
1568 1601
            if not consume(p, scanner::TokenKind::Comma) {
1569 1602
                break;
1570 1603
            }
1604 +
            // After a comma, check for tokens that start a new prong.
1605 +
            // This catches mistakes like `case A, case B`.
1606 +
            if check(p, scanner::TokenKind::Case) or check(p, scanner::TokenKind::Else) {
1607 +
                throw failParsing(p, "unexpected keyword after `,` in case pattern list");
1608 +
            }
1571 1609
        }
1572 1610
        if consume(p, scanner::TokenKind::If) {
1573 1611
            guard = try parseCond(p);
1574 1612
        }
1575 1613
        try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after case pattern");