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:
@@ -98,6 +98,7 @@ func writeDecl(f *formatter, decl Decl) {
|
||||
f.writef(") ")
|
||||
writeTypeExpr(f, d.ReturnType)
|
||||
writeBlock(f, d.Body)
|
||||
f.writef("\n")
|
||||
case *GlobalVarDecl:
|
||||
if d.Flags&GlobalVarConst != 0 {
|
||||
f.writef("const %s = ", d.Name)
|
||||
@@ -109,6 +110,15 @@ func writeDecl(f *formatter, decl Decl) {
|
||||
case *ContainerDecl:
|
||||
f.writef("struct ")
|
||||
writeStructBody(f, d)
|
||||
case *ErrorSetDecl:
|
||||
writeExpr(f, d)
|
||||
case *TestDecl:
|
||||
f.writef("test ")
|
||||
if d.Name != "" {
|
||||
f.writef(`"%s"`, d.Name)
|
||||
}
|
||||
writeBlock(f, d.Block)
|
||||
f.writef("\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +143,15 @@ func writeTypeExpr(f *formatter, typ TypeExpr) {
|
||||
case *PrefixTypeExpr:
|
||||
f.writef("%s", t.Op)
|
||||
writeTypeExpr(f, t.Base)
|
||||
case *ArrayTypeExpr:
|
||||
f.writef("[")
|
||||
writeExpr(f, t.Size)
|
||||
f.writef("]")
|
||||
writeTypeExpr(f, t.Elem)
|
||||
case *ErrorUnionTypeExpr:
|
||||
writeTypeExpr(f, t.ErrSet)
|
||||
f.writef("!")
|
||||
writeTypeExpr(f, t.Type)
|
||||
case nil:
|
||||
// nothing
|
||||
default:
|
||||
@@ -198,6 +217,12 @@ func writeStmt(f *formatter, stmt Stmt) {
|
||||
f.writef("if (")
|
||||
writeExpr(f, s.Cond)
|
||||
f.writef(")")
|
||||
|
||||
// Handle payload if present
|
||||
if s.Payload != nil {
|
||||
f.writef(" ")
|
||||
writePayload(f, s.Payload)
|
||||
}
|
||||
|
||||
// Always write the then branch as a block
|
||||
if block, ok := s.Then.(*BlockStmt); ok {
|
||||
@@ -233,7 +258,156 @@ func writeStmt(f *formatter, stmt Stmt) {
|
||||
f.writef(" ")
|
||||
writeStmt(f, s.Body)
|
||||
}
|
||||
} else if s.Kind == "for" {
|
||||
f.writef("for (")
|
||||
if fp, ok := s.Prefix.(*ForPrefix); ok {
|
||||
for i, arg := range fp.Args {
|
||||
if i > 0 {
|
||||
f.writef(", ")
|
||||
}
|
||||
writeExpr(f, arg.Expr)
|
||||
if arg.From != nil {
|
||||
if lit, ok := arg.From.(*Literal); ok && lit.Value == "" {
|
||||
f.writef("..")
|
||||
} else {
|
||||
f.writef("...")
|
||||
writeExpr(f, arg.From)
|
||||
}
|
||||
}
|
||||
}
|
||||
f.writef(")")
|
||||
if fp.Payload != nil {
|
||||
f.writef(" ")
|
||||
writePayload(f, fp.Payload)
|
||||
}
|
||||
}
|
||||
// Always write the body as a block
|
||||
if block, ok := s.Body.(*BlockStmt); ok {
|
||||
writeBlock(f, block.Block)
|
||||
} else {
|
||||
f.writef(" ")
|
||||
writeStmt(f, s.Body)
|
||||
}
|
||||
}
|
||||
case *DeferStmt:
|
||||
if s.ErrDefer {
|
||||
f.writef("errdefer")
|
||||
} else {
|
||||
f.writef("defer")
|
||||
}
|
||||
f.writef(" ")
|
||||
writeStmt(f, s.Stmt)
|
||||
case *BreakStmt:
|
||||
f.writef("break")
|
||||
if s.Label != "" {
|
||||
f.writef(" :%s", s.Label)
|
||||
}
|
||||
if s.Value != nil {
|
||||
f.writef(" ")
|
||||
writeExpr(f, s.Value)
|
||||
}
|
||||
f.writef(";")
|
||||
case *ContinueStmt:
|
||||
f.writef("continue")
|
||||
if s.Label != "" {
|
||||
f.writef(" :%s", s.Label)
|
||||
}
|
||||
f.writef(";")
|
||||
case *SwitchStmt:
|
||||
f.writef("switch (")
|
||||
writeExpr(f, s.Cond)
|
||||
f.writef(") {\n")
|
||||
f.indent++
|
||||
for _, prong := range s.Prongs {
|
||||
f.writeIndent()
|
||||
writeSwitchProng(f, prong)
|
||||
f.writef("\n")
|
||||
}
|
||||
f.indent--
|
||||
f.writeIndent()
|
||||
f.writef("}")
|
||||
}
|
||||
}
|
||||
|
||||
// writePayload emits a payload (|x|, |*x|, |*x, y|, etc).
|
||||
func writePayload(f *formatter, payload *Payload) {
|
||||
f.writef("|")
|
||||
for i, name := range payload.Names {
|
||||
if i > 0 {
|
||||
f.writef(", ")
|
||||
}
|
||||
if payload.Pointers[i] {
|
||||
f.writef("*")
|
||||
}
|
||||
f.writef("%s", name)
|
||||
}
|
||||
f.writef("|")
|
||||
}
|
||||
|
||||
// writeSwitchProng emits a switch prong.
|
||||
func writeSwitchProng(f *formatter, prong *SwitchProng) {
|
||||
for i, c := range prong.Cases {
|
||||
if i > 0 {
|
||||
f.writef(", ")
|
||||
}
|
||||
if c.IsElse {
|
||||
f.writef("else")
|
||||
} else {
|
||||
writeExpr(f, c.Expr)
|
||||
if c.To != nil {
|
||||
f.writef("...")
|
||||
writeExpr(f, c.To)
|
||||
}
|
||||
}
|
||||
}
|
||||
f.writef(" => ")
|
||||
// Check if the expression is actually a statement (like return or break)
|
||||
if stmt, ok := prong.Expr.(Stmt); ok {
|
||||
// If it's a block, write it directly without the leading space
|
||||
if blockStmt, isBlock := stmt.(*BlockStmt); isBlock {
|
||||
f.writef("{\n")
|
||||
f.indent++
|
||||
for _, s := range blockStmt.Block.Stmts {
|
||||
f.writeIndent()
|
||||
writeStmt(f, s)
|
||||
f.writef("\n")
|
||||
}
|
||||
f.indent--
|
||||
f.writeIndent()
|
||||
f.writef("},")
|
||||
} else {
|
||||
// For single statements, write without the semicolon
|
||||
switch s := stmt.(type) {
|
||||
case *ReturnStmt:
|
||||
f.writef("return")
|
||||
if s.Value != nil {
|
||||
f.writef(" ")
|
||||
writeExpr(f, s.Value)
|
||||
}
|
||||
case *BreakStmt:
|
||||
f.writef("break")
|
||||
if s.Label != "" {
|
||||
f.writef(" :%s", s.Label)
|
||||
}
|
||||
if s.Value != nil {
|
||||
f.writef(" ")
|
||||
writeExpr(f, s.Value)
|
||||
}
|
||||
case *ContinueStmt:
|
||||
f.writef("continue")
|
||||
if s.Label != "" {
|
||||
f.writef(" :%s", s.Label)
|
||||
}
|
||||
case *ExprStmt:
|
||||
writeExpr(f, s.Expr)
|
||||
default:
|
||||
writeStmt(f, stmt)
|
||||
}
|
||||
f.writef(",")
|
||||
}
|
||||
} else {
|
||||
writeExpr(f, prong.Expr)
|
||||
f.writef(",")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,14 +440,20 @@ func writeExpr(f *formatter, expr Expr) {
|
||||
if e.Empty {
|
||||
f.writef(".{}")
|
||||
} else if len(e.Values) > 0 {
|
||||
f.writef(".{")
|
||||
for i, v := range e.Values {
|
||||
if i > 0 {
|
||||
f.writef(", ")
|
||||
if len(e.Values) == 1 {
|
||||
f.writef(".{")
|
||||
writeExpr(f, e.Values[0])
|
||||
f.writef("}")
|
||||
} else {
|
||||
f.writef(".{ ")
|
||||
for i, v := range e.Values {
|
||||
if i > 0 {
|
||||
f.writef(", ")
|
||||
}
|
||||
writeExpr(f, v)
|
||||
}
|
||||
writeExpr(f, v)
|
||||
f.writef(" }")
|
||||
}
|
||||
f.writef("}")
|
||||
}
|
||||
case *ContainerDecl:
|
||||
if e.Kind == "struct" {
|
||||
@@ -289,6 +469,26 @@ func writeExpr(f *formatter, expr Expr) {
|
||||
writeExpr(f, e.Left)
|
||||
f.writef(" %s ", e.Op)
|
||||
writeExpr(f, e.Right)
|
||||
case *UnaryExpr:
|
||||
f.writef("%s", e.Op)
|
||||
writeExpr(f, e.Expr)
|
||||
case *IndexExpr:
|
||||
writeExpr(f, e.Receiver)
|
||||
f.writef("[")
|
||||
writeExpr(f, e.Index)
|
||||
f.writef("]")
|
||||
case *UnreachableExpr:
|
||||
f.writef("unreachable")
|
||||
case *ErrorSetDecl:
|
||||
f.writef("error{\n")
|
||||
f.indent++
|
||||
for _, name := range e.Names {
|
||||
f.writeIndent()
|
||||
f.writef("%s,\n", name)
|
||||
}
|
||||
f.indent--
|
||||
f.writeIndent()
|
||||
f.writef("}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +521,6 @@ func writeStructBody(f *formatter, decl *ContainerDecl) {
|
||||
f.writef("\n")
|
||||
f.writeIndent()
|
||||
writeDecl(f, member.Decl)
|
||||
f.writef("\n")
|
||||
}
|
||||
}
|
||||
f.indent--
|
||||
|
Reference in New Issue
Block a user