Generate hello world Zig code

This commit is contained in:
2025-05-24 16:38:46 -05:00
parent d002309e93
commit 44f3cfca5c
3 changed files with 129 additions and 35 deletions

View File

@@ -12,15 +12,18 @@ type formatter struct {
indent int // indentation level
}
const indentStr = " " // 4 spaces per indent
// indentStr defines the string used for each indentation level (4 spaces).
const indentStr = " "
// Writef writes formatted text to the underlying writer and updates line/col counters.
// It also handles indentation after newlines when appropriate.
func (f *formatter) Writef(format string, a ...any) {
s := fmt.Sprintf(format, a...)
for i, r := range s {
if r == '\n' {
f.line++
f.col = 1
// If next character is not a newline and not end, and not a closing brace, write indentation
// After a newline, write indentation for the next line unless it's a closing brace or another newline.
if i+1 < len(s) && s[i+1] != '\n' && s[i+1] != '}' {
f.writeIndent()
}
@@ -37,6 +40,8 @@ func (f *formatter) Writef(format string, a ...any) {
}
}
// writeIndent writes the current indentation level to the output.
// Call this at the start of a new line before writing statements or closing braces.
func (f *formatter) writeIndent() {
for i := 0; i < f.indent; i++ {
if _, err := f.w.Write([]byte(indentStr)); err != nil {
@@ -46,6 +51,7 @@ func (f *formatter) writeIndent() {
}
}
// Write is the entry point for formatting a Zig AST.
func Write(w io.Writer, root *Root) (err error) {
defer func() {
if r := recover(); r != nil {
@@ -70,17 +76,27 @@ func Write(w io.Writer, root *Root) (err error) {
return nil
}
// writeDecl emits a top-level declaration.
func writeDecl(f *formatter, decl Decl) {
switch fn := decl.(type) {
switch d := decl.(type) {
case *FnDecl:
f.Writef("fn %s(", fn.Name)
writeParams(f, fn.Params)
f.Writef("\nfn %s(", d.Name)
writeParams(f, d.Params)
f.Writef(") ")
writeTypeExpr(f, fn.ReturnType)
writeBlock(f, fn.Body)
writeTypeExpr(f, d.ReturnType)
writeBlock(f, d.Body)
case *GlobalVarDecl:
if d.Const {
f.Writef("const %s = ", d.Name)
} else {
f.Writef("var %s = ", d.Name)
}
writeExpr(f, d.Value)
f.Writef(";\n")
}
}
// writeParams emits function parameters, separated by commas.
func writeParams(f *formatter, params []*ParamDecl) {
for i, param := range params {
if i > 0 {
@@ -93,6 +109,7 @@ func writeParams(f *formatter, params []*ParamDecl) {
}
}
// writeTypeExpr emits a type expression.
func writeTypeExpr(f *formatter, typ TypeExpr) {
switch t := typ.(type) {
case *Identifier:
@@ -104,29 +121,75 @@ func writeTypeExpr(f *formatter, typ TypeExpr) {
}
}
// writeBlock emits a block, handling indentation for statements and the closing brace.
func writeBlock(f *formatter, block *Block) {
if block == nil {
f.Writef(";")
return
}
f.Writef(" {\n")
f.indent++
f.indent++ // Increase indentation for block contents.
for i, stmt := range block.Stmts {
f.writeIndent()
f.writeIndent() // Indent each statement.
writeStmt(f, stmt)
if i < len(block.Stmts)-1 {
f.Writef("\n")
}
}
f.indent--
f.indent-- // Decrease indentation before closing brace.
f.Writef("\n")
f.writeIndent()
f.writeIndent() // Indent the closing brace.
f.Writef("}\n")
}
// writeStmt emits a statement. Indentation is handled by the caller (writeBlock).
func writeStmt(f *formatter, stmt Stmt) {
switch stmt.(type) {
switch s := stmt.(type) {
case *ReturnStmt:
f.Writef("return;")
f.Writef("return")
if s.Value != nil {
f.Writef(" ")
writeExpr(f, s.Value)
}
f.Writef(";")
case *ExprStmt:
writeExpr(f, s.Expr)
f.Writef(";")
}
}
// writeExpr emits an expression.
func writeExpr(f *formatter, expr Expr) {
switch e := expr.(type) {
case *Identifier:
f.Writef("%s", e.Name)
case *CallExpr:
writeExpr(f, e.Fun)
f.Writef("(")
for i, arg := range e.Args {
if i > 0 {
f.Writef(", ")
}
writeExpr(f, arg)
}
f.Writef(")")
case *FieldAccessExpr:
writeExpr(f, e.Receiver)
f.Writef(".%s", e.Field)
case *Literal:
switch e.Kind {
case "string":
f.Writef("%q", e.Value)
default:
f.Writef("%v", e.Value)
}
case *InitListExpr:
if e.Empty {
f.Writef(".{}")
} else {
f.Writef(".{")
// TODO
f.Writef("}")
}
}
}