package main import ( "flag" "fmt" "go/ast" "go/parser" "go/token" "os" "strings" "git.frop.prof/luke/go-zig-compiler/internal/zig" ) var ( outputFilepath *string = flag.String("o", "out.zig", "Zig output filename") ) func init() { flag.Parse() } func main() { inputFilepaths := flag.Args() if len(inputFilepaths) > 1 { panic("Only support one file!") } else if len(inputFilepaths) < 1 { panic("Must supply one input file") } inputFilepath := inputFilepaths[0] fset := token.NewFileSet() f, err := parser.ParseFile(fset, inputFilepath, nil, parser.AllErrors) if err != nil { panic(err) } zigRoot, err := translateToZig(f) if err != nil { panic(err) } outputFile, err := os.Create(*outputFilepath) if err != nil { panic(err) } defer outputFile.Close() err = zig.Write(outputFile, zigRoot) if err != nil { panic(err) } } func translateToZig(f *ast.File) (*zig.Root, error) { // Create the root AST node root := &zig.Root{ ContainerMembers: []*zig.ContainerMember{}, } // Add the std import root.ContainerMembers = append(root.ContainerMembers, &zig.ContainerMember{ Decl: zig.DeclareGlobalVar("std", zig.Call(zig.Id("@import"), zig.StringLit("std")), zig.GlobalVarConst, ), }) // Find and translate the main function for _, decl := range f.Decls { if fn, ok := decl.(*ast.FuncDecl); ok && fn.Name.Name == "main" { mainFunc, err := translateMainFunction(fn) if err != nil { return nil, err } root.ContainerMembers = append(root.ContainerMembers, &zig.ContainerMember{ Decl: mainFunc, }) } } return root, nil } func translateMainFunction(fn *ast.FuncDecl) (*zig.FnDecl, error) { // Create the main function stmts := []zig.Stmt{} // Translate each statement in the function body for _, stmt := range fn.Body.List { zigStmt, err := translateStatement(stmt) if err != nil { return nil, err } if zigStmt != nil { stmts = append(stmts, zigStmt) } } return zig.DeclareFn( "main", zig.Id("void"), zig.NewBlock(stmts...), nil, zig.FnExport, ), nil } func translateStatement(stmt ast.Stmt) (zig.Stmt, error) { switch s := stmt.(type) { case *ast.ExprStmt: // Handle expression statements (like function calls) expr, err := translateExpression(s.X) if err != nil { return nil, err } return zig.NewExprStmt(expr), nil default: return nil, fmt.Errorf("unsupported statement type: %T", stmt) } } func translateExpression(expr ast.Expr) (zig.Expr, error) { switch e := expr.(type) { case *ast.CallExpr: // Handle function calls if ident, ok := e.Fun.(*ast.Ident); ok && ident.Name == "print" { // Translate print() to std.debug.print() args := []zig.Expr{} // First argument is the format string if len(e.Args) > 0 { if lit, ok := e.Args[0].(*ast.BasicLit); ok && lit.Kind == token.STRING { // Remove quotes and use the string value args = append(args, zig.StringLit(strings.Trim(lit.Value, `"`))) } else { return nil, fmt.Errorf("print() requires a string literal argument") } } // Second argument is always .{} for now args = append(args, zig.InitList()) return zig.Call( zig.FieldAccess( zig.FieldAccess(zig.Id("std"), "debug"), "print", ), args..., ), nil } return nil, fmt.Errorf("unsupported function call: %v", e.Fun) default: return nil, fmt.Errorf("unsupported expression type: %T", expr) } }