Refactored code generator, tracks indentation, no error checking

This commit is contained in:
Luke Wilson 2025-05-24 15:46:45 -05:00
parent dba4617520
commit d002309e93
2 changed files with 78 additions and 74 deletions

View File

@ -6,123 +6,127 @@ import (
)
type formatter struct {
io.Writer
w io.Writer
line int // 1-based
col int // 1-based, reset to 1 after newline
indent int // indentation level
}
func (f *formatter) WriteString(s string) (n int, err error) {
return f.Write([]byte(s))
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) Writef(format string, a ...any) (err error) {
_, err = fmt.Fprintf(f, format, a...)
return 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) error {
f := &formatter{Writer: w}
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 != "" {
if err := f.Writef("//! %s\n\n", root.ContainerDocComment); err != nil {
return err
}
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 {
if err := writeDecl(f, member.Decl); err != nil {
return err
}
writeDecl(f, member.Decl)
}
}
return nil
}
func writeDecl(f *formatter, decl Decl) error {
func writeDecl(f *formatter, decl Decl) {
switch fn := decl.(type) {
case *FnDecl:
if err := f.Writef("fn %s(", fn.Name); err != nil {
return err
}
if err := writeParams(f, fn.Params); err != nil {
return err
}
if _, err := f.WriteString(") "); err != nil {
return err
}
if err := writeTypeExpr(f, fn.ReturnType); err != nil {
return err
}
if err := writeBlock(f, fn.Body); err != nil {
return err
}
f.Writef("fn %s(", fn.Name)
writeParams(f, fn.Params)
f.Writef(") ")
writeTypeExpr(f, fn.ReturnType)
writeBlock(f, fn.Body)
}
return nil
}
func writeParams(f *formatter, params []*ParamDecl) error {
func writeParams(f *formatter, params []*ParamDecl) {
for i, param := range params {
if i > 0 {
if _, err := f.WriteString(", "); err != nil {
return err
}
f.Writef(", ")
}
if param.Name != "" {
if _, err := f.WriteString(param.Name); err != nil {
return err
}
if _, err := f.WriteString(": "); err != nil {
return err
}
}
if err := writeTypeExpr(f, param.Type); err != nil {
return err
f.Writef("%s: ", param.Name)
}
writeTypeExpr(f, param.Type)
}
return nil
}
func writeTypeExpr(f *formatter, typ TypeExpr) error {
func writeTypeExpr(f *formatter, typ TypeExpr) {
switch t := typ.(type) {
case *Identifier:
_, err := f.WriteString(t.Name)
return err
f.Writef("%s", t.Name)
case nil:
return nil
// nothing
default:
// fallback: print as string
_, err := f.WriteString(fmt.Sprintf("%v", t))
return err
f.Writef("%v", t)
}
}
func writeBlock(f *formatter, block *Block) error {
func writeBlock(f *formatter, block *Block) {
if block == nil {
_, err := f.WriteString(";")
return err
f.Writef(";")
return
}
if _, err := f.WriteString(" {\n"); err != nil {
return err
}
for _, stmt := range block.Stmts {
if err := writeStmt(f, stmt); err != nil {
return err
}
if _, err := f.WriteString("\n"); err != nil {
return err
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")
}
}
if _, err := f.WriteString("}\n"); err != nil {
return err
}
return nil
f.indent--
f.Writef("\n")
f.writeIndent()
f.Writef("}\n")
}
func writeStmt(f *formatter, stmt Stmt) error {
func writeStmt(f *formatter, stmt Stmt) {
switch stmt.(type) {
case *ReturnStmt:
if _, err := f.WriteString("return;"); err != nil {
return err
}
f.Writef("return;")
}
return nil
}

View File

@ -20,7 +20,7 @@ func TestHelloWorld(t *testing.T) {
expected := `//! Hello, world!
fn main() void {
return;
return;
}
`