mygo is an experimental toy Go preprocessor/transpiler that adds a ? operator for concise error handling.
For example, mygo transforms this:
s := hello()?into standard Go:
s, err := hello()
if err != nil {
return err
}You can also provide a custom error handler block after ?:
s := hello()? {
return fmt.Errorf("hello failed: %w", err)
}which becomes:
s, err := hello()
if err != nil {
return fmt.Errorf("hello failed: %w", err)
}$ go install github.com/aisk/mygo@latestCreate hello.mygo:
package main
import (
"io"
"os"
)
func hello() error {
f := os.Open("hello.mygo")?
defer f.Close()
s := io.ReadAll(f)?
println(string(s))
return nil
}
func main() {
hello()
}mygo supports multiple ways to specify transpile targets:
$ cat hello.mygo | mygo > hello.go
$ mygo hello.mygo
$ mygo .
$ mygo ./...
$ mygo ...You can keep .mygo files as the editable source and generate .go files before normal Go builds:
// generate.go
package main
//go:generate mygo hello.mygoThen run:
$ go generate ./...
$ go test ./...For multiple files or packages, point the directive at a directory:
//go:generate mygo .
//go:generate mygo ./...mygo tries to add syntax sugar without adding runtime lock-in. The generated files are plain Go code:
- no runtime dependency
- no special library
- no custom Go compiler
To keep the generated Go readable, mygo intentionally avoids some rewrites:
- method chaining like
a()?.b()?is not supported ?inforinitialization statements is not supported yet- expression statements like
f()?requirefto return onlyerror; use_ = f()?when discarding non-error return values - custom handlers use the generated
errvariable and must return or otherwise handle control flow themselves