Improve Zig AST developer experience

- Convert string-based type discrimination to type-safe enums
  - ContainerKind (struct, enum, union, opaque)
  - LiteralKind (int, float, string, char)
  - LoopKind (for, while)
- Remove duplicate AST nodes (consolidated init lists, removed unused types)
- Add comprehensive helper functions for all AST constructions
- Implement formatters for all AST nodes (expressions, statements, types)
- Add typed literal constructors: IntLit, FloatLit, StringLit, CharLit
- Improve documentation and add deprecation notices

This makes the AST more intuitive and type-safe for developers.
This commit is contained in:
2025-06-05 21:07:02 -05:00
parent 258b3c8e9b
commit 2af696078d
4 changed files with 339 additions and 129 deletions

View File

@@ -119,6 +119,14 @@ func writeDecl(f *formatter, decl Decl) {
}
writeBlock(f, d.Block)
f.writef("\n")
case *UsingNamespaceDecl:
f.writef("usingnamespace ")
writeExpr(f, d.Expr)
f.writef(";\n")
case *ComptimeDecl:
f.writef("comptime")
writeBlock(f, d.Block)
f.writef("\n")
}
}
@@ -148,6 +156,9 @@ func writeTypeExpr(f *formatter, typ TypeExpr) {
writeExpr(f, t.Size)
f.writef("]")
writeTypeExpr(f, t.Elem)
case *SliceTypeExpr:
f.writef("[]")
writeTypeExpr(f, t.Elem)
case *ErrorUnionTypeExpr:
writeTypeExpr(f, t.ErrSet)
f.writef("!")
@@ -217,7 +228,7 @@ 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(" ")
@@ -241,7 +252,7 @@ func writeStmt(f *formatter, stmt Stmt) {
}
}
case *LoopStmt:
if s.Kind == "while" {
if s.Kind == LoopWhile {
f.writef("while (")
if wp, ok := s.Prefix.(*WhilePrefix); ok {
writeExpr(f, wp.Cond)
@@ -258,7 +269,7 @@ func writeStmt(f *formatter, stmt Stmt) {
f.writef(" ")
writeStmt(f, s.Body)
}
} else if s.Kind == "for" {
} else if s.Kind == LoopFor {
f.writef("for (")
if fp, ok := s.Prefix.(*ForPrefix); ok {
for i, arg := range fp.Args {
@@ -289,45 +300,45 @@ func writeStmt(f *formatter, stmt Stmt) {
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("}")
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) {
@@ -431,7 +442,7 @@ func writeExpr(f *formatter, expr Expr) {
f.writef(".%s", e.Field)
case *Literal:
switch e.Kind {
case "string":
case LiteralString:
f.writef(`"%v"`, e.Value)
default:
f.writef("%v", e.Value)
@@ -456,11 +467,21 @@ func writeExpr(f *formatter, expr Expr) {
}
}
case *ContainerDecl:
if e.Kind == "struct" {
switch e.Kind {
case ContainerStruct:
f.writef("struct ")
writeStructBody(f, e)
} else {
panic("not implemented: " + e.Kind)
case ContainerEnum:
f.writef("enum ")
writeStructBody(f, e)
case ContainerUnion:
f.writef("union ")
writeStructBody(f, e)
case ContainerOpaque:
f.writef("opaque ")
writeStructBody(f, e)
default:
panic("unknown container kind")
}
case *TryExpr:
f.writef("try ")
@@ -489,6 +510,58 @@ func writeExpr(f *formatter, expr Expr) {
f.indent--
f.writeIndent()
f.writef("}")
case *GroupedExpr:
f.writef("(")
writeExpr(f, e.Expr)
f.writef(")")
case *ComptimeExpr:
f.writef("comptime ")
writeExpr(f, e.Expr)
case *NosuspendExpr:
f.writef("nosuspend ")
writeExpr(f, e.Expr)
case *AsyncExpr:
f.writef("async ")
writeExpr(f, e.Expr)
case *AwaitExpr:
f.writef("await ")
writeExpr(f, e.Expr)
case *ResumeExpr:
f.writef("resume ")
writeExpr(f, e.Expr)
case *DotAsteriskExpr:
writeExpr(f, e.Receiver)
f.writef(".*")
case *DotQuestionExpr:
writeExpr(f, e.Receiver)
f.writef(".?")
case *IfExpr:
f.writef("if (")
writeExpr(f, e.Cond)
f.writef(")")
if e.Payload != nil {
f.writef(" ")
writePayload(f, e.Payload)
}
f.writef(" ")
writeExpr(f, e.Then)
if e.Else != nil {
f.writef(" else ")
writeExpr(f, e.Else)
}
case *SwitchExpr:
f.writef("switch (")
writeExpr(f, e.Cond)
f.writef(") {\n")
f.indent++
for _, prong := range e.Prongs {
f.writeIndent()
writeSwitchProng(f, prong)
f.writef("\n")
}
f.indent--
f.writeIndent()
f.writef("}")
}
}