133 lines
2.4 KiB
Go
133 lines
2.4 KiB
Go
package zig
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
type formatter struct {
|
|
w io.Writer
|
|
line int // 1-based
|
|
col int // 1-based, reset to 1 after newline
|
|
indent int // indentation level
|
|
}
|
|
|
|
const indentStr = " " // 4 spaces per indent
|
|
|
|
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
|
|
if i+1 < len(s) && s[i+1] != '\n' && s[i+1] != '}' {
|
|
f.writeIndent()
|
|
}
|
|
} else {
|
|
if f.col == 0 {
|
|
f.col = 1
|
|
} else {
|
|
f.col++
|
|
}
|
|
}
|
|
}
|
|
if _, err := f.w.Write([]byte(s)); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (f *formatter) writeIndent() {
|
|
for i := 0; i < f.indent; i++ {
|
|
if _, err := f.w.Write([]byte(indentStr)); err != nil {
|
|
panic(err)
|
|
}
|
|
f.col += len(indentStr)
|
|
}
|
|
}
|
|
|
|
func Write(w io.Writer, root *Root) (err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if e, ok := r.(error); ok {
|
|
err = e
|
|
} else {
|
|
panic(r)
|
|
}
|
|
}
|
|
}()
|
|
f := &formatter{w: w, line: 1, col: 1, indent: 0}
|
|
|
|
if root.ContainerDocComment != "" {
|
|
f.Writef("//! %s\n\n", root.ContainerDocComment)
|
|
}
|
|
for _, member := range root.ContainerMembers {
|
|
// Only handle Decl for now (fields not needed for hello world)
|
|
if member.Decl != nil {
|
|
writeDecl(f, member.Decl)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeDecl(f *formatter, decl Decl) {
|
|
switch fn := decl.(type) {
|
|
case *FnDecl:
|
|
f.Writef("fn %s(", fn.Name)
|
|
writeParams(f, fn.Params)
|
|
f.Writef(") ")
|
|
writeTypeExpr(f, fn.ReturnType)
|
|
writeBlock(f, fn.Body)
|
|
}
|
|
}
|
|
|
|
func writeParams(f *formatter, params []*ParamDecl) {
|
|
for i, param := range params {
|
|
if i > 0 {
|
|
f.Writef(", ")
|
|
}
|
|
if param.Name != "" {
|
|
f.Writef("%s: ", param.Name)
|
|
}
|
|
writeTypeExpr(f, param.Type)
|
|
}
|
|
}
|
|
|
|
func writeTypeExpr(f *formatter, typ TypeExpr) {
|
|
switch t := typ.(type) {
|
|
case *Identifier:
|
|
f.Writef("%s", t.Name)
|
|
case nil:
|
|
// nothing
|
|
default:
|
|
f.Writef("%v", t)
|
|
}
|
|
}
|
|
|
|
func writeBlock(f *formatter, block *Block) {
|
|
if block == nil {
|
|
f.Writef(";")
|
|
return
|
|
}
|
|
f.Writef(" {\n")
|
|
f.indent++
|
|
for i, stmt := range block.Stmts {
|
|
f.writeIndent()
|
|
writeStmt(f, stmt)
|
|
if i < len(block.Stmts)-1 {
|
|
f.Writef("\n")
|
|
}
|
|
}
|
|
f.indent--
|
|
f.Writef("\n")
|
|
f.writeIndent()
|
|
f.Writef("}\n")
|
|
}
|
|
|
|
func writeStmt(f *formatter, stmt Stmt) {
|
|
switch stmt.(type) {
|
|
case *ReturnStmt:
|
|
f.Writef("return;")
|
|
}
|
|
}
|