Refactored code generator, tracks indentation, no error checking
This commit is contained in:
parent
dba4617520
commit
d002309e93
@ -6,123 +6,127 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type formatter struct {
|
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) {
|
const indentStr = " " // 4 spaces per indent
|
||||||
return f.Write([]byte(s))
|
|
||||||
|
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) {
|
func (f *formatter) writeIndent() {
|
||||||
_, err = fmt.Fprintf(f, format, a...)
|
for i := 0; i < f.indent; i++ {
|
||||||
return err
|
if _, err := f.w.Write([]byte(indentStr)); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
f.col += len(indentStr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Write(w io.Writer, root *Root) error {
|
func Write(w io.Writer, root *Root) (err error) {
|
||||||
f := &formatter{Writer: w}
|
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 root.ContainerDocComment != "" {
|
||||||
if err := f.Writef("//! %s\n\n", root.ContainerDocComment); err != nil {
|
f.Writef("//! %s\n\n", root.ContainerDocComment)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, member := range root.ContainerMembers {
|
for _, member := range root.ContainerMembers {
|
||||||
// Only handle Decl for now (fields not needed for hello world)
|
// Only handle Decl for now (fields not needed for hello world)
|
||||||
if member.Decl != nil {
|
if member.Decl != nil {
|
||||||
if err := writeDecl(f, member.Decl); err != nil {
|
writeDecl(f, member.Decl)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeDecl(f *formatter, decl Decl) error {
|
func writeDecl(f *formatter, decl Decl) {
|
||||||
switch fn := decl.(type) {
|
switch fn := decl.(type) {
|
||||||
case *FnDecl:
|
case *FnDecl:
|
||||||
if err := f.Writef("fn %s(", fn.Name); err != nil {
|
f.Writef("fn %s(", fn.Name)
|
||||||
return err
|
writeParams(f, fn.Params)
|
||||||
}
|
f.Writef(") ")
|
||||||
if err := writeParams(f, fn.Params); err != nil {
|
writeTypeExpr(f, fn.ReturnType)
|
||||||
return err
|
writeBlock(f, fn.Body)
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeParams(f *formatter, params []*ParamDecl) error {
|
func writeParams(f *formatter, params []*ParamDecl) {
|
||||||
for i, param := range params {
|
for i, param := range params {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
if _, err := f.WriteString(", "); err != nil {
|
f.Writef(", ")
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if param.Name != "" {
|
if param.Name != "" {
|
||||||
if _, err := f.WriteString(param.Name); err != nil {
|
f.Writef("%s: ", param.Name)
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := f.WriteString(": "); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := writeTypeExpr(f, param.Type); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
writeTypeExpr(f, param.Type)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeTypeExpr(f *formatter, typ TypeExpr) error {
|
func writeTypeExpr(f *formatter, typ TypeExpr) {
|
||||||
switch t := typ.(type) {
|
switch t := typ.(type) {
|
||||||
case *Identifier:
|
case *Identifier:
|
||||||
_, err := f.WriteString(t.Name)
|
f.Writef("%s", t.Name)
|
||||||
return err
|
|
||||||
case nil:
|
case nil:
|
||||||
return nil
|
// nothing
|
||||||
default:
|
default:
|
||||||
// fallback: print as string
|
f.Writef("%v", t)
|
||||||
_, err := f.WriteString(fmt.Sprintf("%v", t))
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeBlock(f *formatter, block *Block) error {
|
func writeBlock(f *formatter, block *Block) {
|
||||||
if block == nil {
|
if block == nil {
|
||||||
_, err := f.WriteString(";")
|
f.Writef(";")
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
if _, err := f.WriteString(" {\n"); err != nil {
|
f.Writef(" {\n")
|
||||||
return err
|
f.indent++
|
||||||
}
|
for i, stmt := range block.Stmts {
|
||||||
for _, stmt := range block.Stmts {
|
f.writeIndent()
|
||||||
if err := writeStmt(f, stmt); err != nil {
|
writeStmt(f, stmt)
|
||||||
return err
|
if i < len(block.Stmts)-1 {
|
||||||
}
|
f.Writef("\n")
|
||||||
if _, err := f.WriteString("\n"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := f.WriteString("}\n"); err != nil {
|
f.indent--
|
||||||
return err
|
f.Writef("\n")
|
||||||
}
|
f.writeIndent()
|
||||||
return nil
|
f.Writef("}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeStmt(f *formatter, stmt Stmt) error {
|
func writeStmt(f *formatter, stmt Stmt) {
|
||||||
switch stmt.(type) {
|
switch stmt.(type) {
|
||||||
case *ReturnStmt:
|
case *ReturnStmt:
|
||||||
if _, err := f.WriteString("return;"); err != nil {
|
f.Writef("return;")
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ func TestHelloWorld(t *testing.T) {
|
|||||||
expected := `//! Hello, world!
|
expected := `//! Hello, world!
|
||||||
|
|
||||||
fn main() void {
|
fn main() void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user