Add comprehensive Zig syntax test coverage

- Add support for error sets and error union types
- Implement for loops with index and payload syntax
- Add defer, break, continue, and switch statements
- Support unary expressions and array indexing
- Add unreachable expression and test declarations
- Extend AST with new type expressions (array, error union)
- Update formatter to handle all new syntax elements
- Fix formatting for switch prongs, payloads, and blocks
This commit is contained in:
2025-06-05 20:44:49 -05:00
parent 50b38254ab
commit 258b3c8e9b
4 changed files with 529 additions and 7 deletions

View File

@@ -92,6 +92,217 @@ fn main() void {
runZigASTTest(t, expected, root)
}
func TestCompoundFeatures(t *testing.T) {
expected := `const ProcessError = error{
InvalidInput,
OutOfBounds,
};
fn processData(values: [5]?i32) ProcessError!i32 {
var result: i32 = 0;
defer std.debug.print("Cleanup\n", .{});
for (values, 0..) |opt_val, idx| {
if (opt_val) |val| {
switch (val) {
-10...-1 => result += -val,
0 => continue,
1...10 => {
if (idx > 3) break;
result += val;
},
else => return ProcessError.InvalidInput,
}
} else {
if (idx == 0) return ProcessError.InvalidInput;
break;
}
}
if (values[0] == null) {
unreachable;
}
return result;
}
test "processData" {
const data = .{ 5, -3, 0, null, 10 };
const result = try processData(data);
try std.testing.expectEqual(@as(i32, 8), result);
}
`
root := &zig.Root{
ContainerMembers: []*zig.ContainerMember{
{
Decl: zig.DeclareGlobalVar("ProcessError",
zig.ErrorSet("InvalidInput", "OutOfBounds"),
zig.GlobalVarConst,
),
},
{
Decl: zig.DeclareFn(
"processData",
zig.ErrorUnionType(zig.Id("ProcessError"), zig.Id("i32")),
zig.NewBlock(
// var result: i32 = 0;
zig.DeclareVarStmt(false, []string{"result"}, zig.Id("i32"), zig.Lit("int", "0")),
// defer std.debug.print("Cleanup\n", .{});
zig.Defer(
zig.NewExprStmt(
zig.Call(
zig.FieldAccess(
zig.FieldAccess(zig.Id("std"), "debug"),
"print",
),
zig.Lit("string", `Cleanup\n`),
zig.InitList(),
),
),
),
// for (values, 0..) |opt_val, idx| { ... }
zig.ForLoop(
[]zig.ForArg{
zig.ForArgExpr(zig.Id("values")),
{Expr: zig.Lit("int", "0"), From: zig.Lit("", "")},
},
zig.PayloadNames([]string{"opt_val", "idx"}, []bool{false, false}),
zig.NewBlockStmt(
// if (opt_val) |val| { ... } else { ... }
zig.IfWithPayload(
zig.Id("opt_val"),
zig.PayloadNames([]string{"val"}, []bool{false}),
zig.NewBlockStmt(
// switch (val) { ... }
zig.Switch(
zig.Id("val"),
// -10...-1 => result += -val,
zig.Prong(
[]*zig.SwitchCase{
zig.Case(
zig.Unary("-", zig.Lit("int", "10")),
zig.Unary("-", zig.Lit("int", "1")),
),
},
nil,
zig.NewExprStmt(
zig.Binary("+=",
zig.Id("result"),
zig.Unary("-", zig.Id("val")),
),
),
),
// 0 => continue,
zig.Prong(
[]*zig.SwitchCase{
zig.Case(zig.Lit("int", "0"), nil),
},
nil,
zig.Continue(""),
),
// 1...10 => { ... }
zig.Prong(
[]*zig.SwitchCase{
zig.Case(zig.Lit("int", "1"), zig.Lit("int", "10")),
},
nil,
zig.NewBlockStmt(
zig.If(
zig.Binary(">", zig.Id("idx"), zig.Lit("int", "3")),
zig.Break("", nil),
nil,
),
zig.NewExprStmt(
zig.Binary("+=", zig.Id("result"), zig.Id("val")),
),
),
),
// else => return ProcessError.InvalidInput,
zig.Prong(
[]*zig.SwitchCase{zig.ElseCase()},
nil,
zig.Return(
zig.FieldAccess(zig.Id("ProcessError"), "InvalidInput"),
),
),
),
),
// else block
zig.NewBlockStmt(
zig.If(
zig.Binary("==", zig.Id("idx"), zig.Lit("int", "0")),
zig.Return(zig.FieldAccess(zig.Id("ProcessError"), "InvalidInput")),
nil,
),
zig.Break("", nil),
),
),
),
nil,
),
// if (values[0] == null) { unreachable; }
zig.If(
zig.Binary("==",
zig.Index(zig.Id("values"), zig.Lit("int", "0")),
zig.Id("null"),
),
zig.NewBlockStmt(
zig.NewExprStmt(zig.Unreachable()),
),
nil,
),
// return result;
zig.Return(zig.Id("result")),
),
[]*zig.ParamDecl{
zig.Param("values", zig.ArrayType(zig.Lit("int", "5"), zig.OptionalType(zig.Id("i32")))),
},
0,
),
},
{
Decl: zig.Test("processData",
zig.NewBlock(
// const data = [_]?i32{ 5, -3, 0, null, 10 };
zig.DeclareVarStmt(true, []string{"data"}, nil,
&zig.InitListExpr{
Values: []zig.Expr{
zig.Lit("int", "5"),
zig.Unary("-", zig.Lit("int", "3")),
zig.Lit("int", "0"),
zig.Id("null"),
zig.Lit("int", "10"),
},
},
),
// const result = try processData(data);
zig.DeclareVarStmt(true, []string{"result"}, nil,
zig.Try(zig.Call(zig.Id("processData"), zig.Id("data"))),
),
// try std.testing.expectEqual(@as(i32, 8), result);
zig.NewExprStmt(
zig.Try(
zig.Call(
zig.FieldAccess(
zig.FieldAccess(zig.Id("std"), "testing"),
"expectEqual",
),
zig.Call(
zig.Id("@as"),
zig.Id("i32"),
zig.Lit("int", "8"),
),
zig.Id("result"),
),
),
),
),
),
},
},
}
runZigASTTest(t, expected, root)
}
func TestEvenOdd(t *testing.T) {
expected := `//! Abc