Allow trailing commas in parser

4bb2cff33178f88bc59dcaaf2955ab2602d3ed7ef7432f4e1bc954f460d96be6
Alexis Sellier committed ago 1 parent c8b1ee9e
lib/std/lang/parser.rad +8 -11
816 816
    let mut args = ast::nodeSlice(p.arena, 4);
817 817
818 818
    if kind == ast::Builtin::SliceOf {
819 819
        // Parse comma-separated expressions until closing paren.
820 820
        // Argument count validation is done in semantic analysis.
821 -
        if p.current.kind != scanner::TokenKind::RParen {
821 +
        while not check(p, scanner::TokenKind::RParen) {
822 822
            args.append(try parseExpr(p), p.allocator);
823 -
            while p.current.kind == scanner::TokenKind::Comma {
824 -
                advance(p);
825 -
                args.append(try parseExpr(p), p.allocator);
823 +
            if not consume(p, scanner::TokenKind::Comma) {
824 +
                break;
826 825
            }
827 826
        }
828 827
    } else {
829 828
        args.append(try parseType(p), p.allocator);
830 829
    }
1902 1901
    throws (ParseError)
1903 1902
{
1904 1903
    try expect(p, scanner::TokenKind::LParen, "expected `(` after function name");
1905 1904
    let mut params = ast::nodeSlice(p.arena, 8);
1906 1905
1907 -
    if not check(p, scanner::TokenKind::RParen) {
1908 -
        loop {
1909 -
            let param = try parseFnParam(p);
1910 -
            params.append(param, p.allocator);
1906 +
    while not check(p, scanner::TokenKind::RParen) {
1907 +
        let param = try parseFnParam(p);
1908 +
        params.append(param, p.allocator);
1911 1909
1912 -
            if not consume(p, scanner::TokenKind::Comma) {
1913 -
                break;
1914 -
            }
1910 +
        if not consume(p, scanner::TokenKind::Comma) {
1911 +
            break;
1915 1912
        }
1916 1913
    }
1917 1914
    try expect(p, scanner::TokenKind::RParen, "expected `)` after function parameters");
1918 1915
1919 1916
    let mut returnType: ?*ast::Node = nil;
lib/std/lang/parser/tests.rad +49 -0
2663 2663
2664 2664
    try expectIdent(inner.thenExpr, "b");
2665 2665
    try expectIdent(inner.condition, "y");
2666 2666
    try expectIdent(inner.elseExpr, "c");
2667 2667
}
2668 +
2669 +
/// Test that trailing commas are allowed in all comma-separated lists.
2670 +
@test fn testTrailingCommas() throws (testing::TestError) {
2671 +
    // Function call arguments.
2672 +
    let call = try! parseExprStr("f(1, 2, 3,)");
2673 +
    let case ast::NodeValue::Call(c) = call.value else throw testing::TestError::Failed;
2674 +
    try testing::expect(c.args.len == 3);
2675 +
2676 +
    // Function parameters.
2677 +
    let fnNode = try! parseStmtStr("fn add(x: i32, y: i32,) {}");
2678 +
    let case ast::NodeValue::FnDecl(fnDecl) = fnNode.value else throw testing::TestError::Failed;
2679 +
    try testing::expect(fnDecl.sig.params.len == 2);
2680 +
2681 +
    // Record declarations.
2682 +
    let recNode = try! parseStmtStr("record R { x: i32, y: bool, }");
2683 +
    let case ast::NodeValue::RecordDecl(recDecl) = recNode.value else throw testing::TestError::Failed;
2684 +
    try testing::expect(recDecl.fields.len == 2);
2685 +
2686 +
    // Tuple record declarations.
2687 +
    let tupNode = try! parseStmtStr("record R(i32, bool,);");
2688 +
    let case ast::NodeValue::RecordDecl(tupDecl) = tupNode.value else throw testing::TestError::Failed;
2689 +
    try testing::expect(tupDecl.fields.len == 2);
2690 +
2691 +
    // Record literals.
2692 +
    let litNode = try! parseExprStr("Point { x: 1, y: 2, }");
2693 +
    let case ast::NodeValue::RecordLit(lit) = litNode.value else throw testing::TestError::Failed;
2694 +
    try testing::expect(lit.fields.len == 2);
2695 +
2696 +
    // Union declarations.
2697 +
    let unionNode = try! parseStmtStr("union Color { Red, Green, Blue, }");
2698 +
    let case ast::NodeValue::UnionDecl(unionDecl) = unionNode.value else throw testing::TestError::Failed;
2699 +
    try testing::expect(unionDecl.variants.len == 3);
2700 +
2701 +
    // Array literals.
2702 +
    let arrNode = try! parseExprStr("[1, 2, 3,]");
2703 +
    let case ast::NodeValue::ArrayLit(items) = arrNode.value else throw testing::TestError::Failed;
2704 +
    try testing::expect(items.len == 3);
2705 +
2706 +
    // Function type parameters.
2707 +
    let fnType = try! parseTypeStr("fn (i32, bool,) -> void");
2708 +
    let case ast::NodeValue::TypeSig(sigValue) = fnType.value else throw testing::TestError::Failed;
2709 +
    let case ast::TypeSig::Fn(sig) = sigValue else throw testing::TestError::Failed;
2710 +
    try testing::expect(sig.params.len == 2);
2711 +
2712 +
    // Throws lists.
2713 +
    let throwsNode = try! parseStmtStr("fn handle() throws (Error, Other,) {}");
2714 +
    let case ast::NodeValue::FnDecl(throwsDecl) = throwsNode.value else throw testing::TestError::Failed;
2715 +
    try testing::expect(throwsDecl.sig.throwList.len == 2);
2716 +
}