Mechanical Go-to-Moxie source transformer. Uses the Moxie compiler's own parser (compile.ParseFile), rewrites the AST in-place, emits transformed source, produces a semantic report of constructs requiring manual intervention.
All 11 mechanical transforms implemented and verified. Round-trip test (parse->print->parse->print->diff) passes with zero diff. Installed at ~/.local/bin/moxieport.
os.Args is always empty in standalone Moxie binaries. Root cause: os.runtime_args (defined in runtime_unix.mx via //go:linkname) is not compiled into sysroot/runtime.bc. The runtime.initAll() function generated by the compiler calls os.runtime_args() and stores the result in os.Args, but since the function doesn't exist in the binary, initAll compiles to just ret. moxieport works around this by reading /proc/self/cmdline.
/home/mleku/s/moxie/moxieport/ - new package, single binary.
Print(w io.Writer, f *compile.File) - walks a *File and emits syntactically valid Moxie source. Must handle all node types in compile/nodes.mx:
ImportDecl, ConstDecl, TypeDecl, VarDecl, FuncDeclName, BasicLit, CallExpr, SelectorExpr, IndexExpr, SliceExpr, Operation, CompositeLit, KeyValueExpr, FuncLit, AssertExpr, ParenExpr, ListExprArrayType, SliceType, StructType, InterfaceType, FuncType, MapType, ChanType, DotsTypeBlockStmt, ExprStmt, SendStmt, AssignStmt, ReturnStmt, IfStmt, ForStmt, RangeClause, SwitchStmt, CaseClause, SelectStmt, CommClause, BranchStmt, LabeledStmt, CallStmt, DeclStmt, EmptyStmtNo comment preservation (parser discards them). Pragmas (//go: directives, //export) preserved via Pragma fields on nodes.
Each transform is func(f *compile.File), mutates AST in-place, applied in sequence before printing.
| # | Transform | AST pattern | Rewrite to |
|---|---|---|---|
| 1 | int width | Name.Value == "int" in type or conversion position | "int64" |
| 2 | uint width | Name.Value == "uint" in type or conversion position | "uint64" |
| 3 | make slice | CallExpr where Fun is Name{"make"}, first arg is SliceType | CompositeLit with SliceType + colon-length syntax |
| 4 | make chan | CallExpr where Fun is Name{"make"}, first arg is ChanType | CompositeLit with ChanType + optional buffer arg |
| 5 | make map | CallExpr where Fun is Name{"make"}, first arg is MapType | CompositeLit with MapType |
| 6 | new(T) | CallExpr where Fun is Name{"new"} | Operation{Op: And, X: CompositeLit{Type: T}} (i.e. &T{}) |
| 7 | string concat | Operation{Op: Add} where operands are StringLit | Change Op to Or (pipe). Conservative: only rewrite when at least one operand is StringLit. Flag X + Y where neither is a literal. |
| 8 | strings import | ImportDecl with Path.Value == "strings" | Change to "bytes" |
| 9 | fallthrough | BranchStmt{Tok: Fallthrough} in CaseClause | Merge this clause's Cases with next clause's Cases, combine bodies, remove the BranchStmt |
| 10 | init rename | FuncDecl with Name.Value == "init" | Rename to init_N, add CallExpr at top of main() |
| 11 | file extension | Output filename | .go -> .mx |
Match on Name.Value must be exact-equal, not prefix (avoid mangling int32, int64, uint16, etc.).
Walk the transformed AST. One line per flag, file:line:col + construct. Machine-parseable for claude code consumption.
| Flag | Detection |
|---|---|
interface{} / any | InterfaceType with empty MethodList, or Name.Value == "any" |
reflect import | ImportDecl path contains "reflect" |
go statement | CallStmt{Tok: Go} |
sync.* import | ImportDecl path contains "sync" |
context import | ImportDecl path contains "context" |
uintptr | Name.Value == "uintptr" in type position |
complex64/128 | Name.Value matches "complex64" or "complex128" |
unsafe import | ImportDecl path is "unsafe" |
Package-level var | VarDecl at top-level DeclList |
Remaining + on unknown types | Operation{Op: Add} not rewritten by transform #7 |
.mx file, print it, parse the output, compare AST structure. Validates the printer independently of transforms.moxieport <file.go> writes <file.mx> + prints report to stderr. moxieport <dir>/ processes all .go files.Before writing the printer, read how the parser represents CompositeLit with colon-length syntax ([]T{:n}, []T{:n:c}, chan T{n}). The AST representation determines:
Check the parser's compositeLit / complitexpr handling to determine whether the colon-length form uses KeyValueExpr with a nil key, a dedicated node type, or some other encoding. Do not assume the structure.