MyGO is a new programming language that transpiles to Go. It follows Lisette-style nominal concrete types and structural interfaces, with generic enums, structs, interfaces, and functions.
The repository currently contains:
- The MyGO compiler frontend and two code generation pipelines:
internal/mygo/parser,internal/mygo/typeinference, andinternal/mygo/codegenfor the legacy path, plusinternal/mygo/parser2,internal/mygo/typeinference2, andinternal/mygo/codegen2for the default self-hosted bootstrap pipeline. - A prelude written primarily in MyGO under
prelude/. - A language server implemented in MyGO under
lsp/and exposed ascmd/mygo-lsp. - Reusable standard libraries under
lib/, including channels/spawn, sorting/searching, and an FParsec-inspired parser combinator library.
Build from this repository to use the current compiler:
go build -o mygo ./cmd/mygo
go build -o mygo-lsp ./cmd/mygo-lspThe binary can also be installed through the Go toolchain once a release is published:
go install github.com/mygo-lang/mygo/cmd/mygo@latestpackage main
import fmt "go:fmt"
enum Shape
Circle(Float64)
Rectangle(Float64, Float64)
end
func area(shape: Shape) -> Float64
switch shape
case Circle(r) => 3.14 * r * r
case Rectangle(w, h) => w * h
end
end
func main() -> ()
let circle = Shape.Circle(5.0)
fmt.Println("Area:", area(circle))
end
Compile <package dir> and generate one .gen.go file per .mygo source:
./mygo sync examples/mainMyGO files start with a leading package <name> header followed directly by
declarations. The old file-level module wrapper is no longer used. The build
command also accepts build to run go build after generating source.
Every package now receives a built-in prelude during compilation. The prelude is written in MyGO when possible and currently provides shared protocols such as ToString[A] and Eq[A], so generic formatting and comparison code can rely on those interfaces instead of falling back to ad hoc any usage.
Run with go run:
go run ./examples/main/Or build and run:
go build -o main.exe ./examples/main/
./main.exeRun the canonical example:
./mygo sync examples/main
go run ./examples/mainSync and build use the self-hosted bootstrap pipeline by default:
go run ./cmd/mygo sync internal/mygoSee docs/compiler2/core.md for the differences between the legacy pipeline and the self-hosted parser/typechecker/codegen pipeline.
Existing --bootstrap commands remain supported. To generate through the
legacy pipeline, use --legacy sync; the flag is only supported for sync.
For a legacy build, generate first and then invoke Go directly:
./mygo --legacy sync examples/main
go build ./examples/mainDo not combine --legacy with --bootstrap or --bootstrap-timing.
Bootstrap compilation failures are reported without an automatic legacy fallback.
See docs/compiler/dynamic-typeclass-values.md for generated dynamic typeclass value APIs and dependency metadata behavior.
- Explicit type parameters: Preserved in the AST and generated Go code.
- Lisette-style nominal concrete types and structural interfaces.
- Generic enums, structs, interfaces, and functions: Remain generic rather than collapsing to
any. - Named primitive spellings:
Int,String,Bool, and the other primitive spellings map to Go primitives. - Unit type:
()lowers to a Go function with no return values, not tostruct{}.
- Function bodies and other block forms: Newline-separated statement lists; the last plain expression in a block is the return value.
- If expression: Supports
if cond => a else band block formif cond then ... elsif ... else ... end. - Let binding: Introduces an immutable binding. Rebinding the same source name must use a later
letand is treated as shadowing, not assignment. - Letrec binding:
letrec ... endintroduces an immutable recursive binding group with explicit type annotations. - Var binding: Introduces a mutable binding and may be assigned again later in the same scope.
- Let type inference: May omit its type annotation when the initializer provides enough information for inference.
- Discard form:
let _ = ...is the supported discard form for return values that should not be bound.
- Constructor-like form: Such as
ABC { aaa: 123 }. - Generic struct literals with explicit type arguments: Like
Box[Int64] { value: 123 }. - Inherent impl methods: Methods on a struct are declared in
impl Typeblocks and lower to top-level Go functions with mangled names.
- Go package imports: Use
import "go:pkg/name", or an alias such asimport fmt "go:fmt". - Package-qualified selectors: Selectors such as
fmt.Sprint(...)lower as Go selectors. - Prelude protocols: Prefer
ToString[A],Eq[A],Ord[A],Default[A],From[A, B], andInto[A, B]from the built-in prelude. - Option and Result:
Option[A]andResult[A, E]are prelude algebraic data types mapped to generated Go sum types. - Slice, Map, and Set:
Slice[A],Map[K, V], andSet[A]lower directly to Go[]A,map[K]V, andmap[A]struct{}. - Fixed-length arrays (bootstrap):
Int32[5]lowers to Go[5]int32. Array literals require exactly the declared number of elements, such as[1, 2] as Int[2]; missing elements are rejected.[0] as Int[1] * 5explicitly repeats the array to produceInt[5]. Lengths and repetition counts are non-negative integer literals; unannotated list literals remain Slices. See array semantics. - List:
List[A]is a prelude-implemented singly linked list usingheadandtail: Option[Ref[List[A]]]. - Ref[T]: The non-nil reference form at the Go boundary lowers to
*Tin generated Go; useRef.new(expr). - Option[Ref[T]]: The preferred shape for possibly-nil pointer returns, preserved rather than collapsed to a bare pointer.
- Inline Go:
go[T] { code: "..."; in x = expr; type T = ... }embeds small Go snippets with operand substitution.
lib/concurrency provides channel wrappers on top of inline Go embedding:
Chan[T],SendChan[T], andRecvChan[T]for bidirectional and directional channels.MakeChan[T](buffer),MakeChanUnbuffered[T](),AsSend[T](), andAsRecv[T]().Spawn(fn)for starting goroutines.
The channel types implement IChannel, IReadableChan, and IWritableChan
interfaces. The compiler recognizes directional channel type strings in
inline Go code and generated type emission.
The lsp/ directory is a MyGO implementation of a language server exposing
completion, hover, diagnostics, symbols, definition, references, and workspace
symbols over the LSP protocol. Build it with:
go build -o mygo-lsp ./cmd/mygo-lspThe server uses full document synchronization and UTF-16 positions. Workspace
roots come from workspaceFolders or rootUri; without either, opened files
use their containing directories. Analysis includes unopened sibling files,
workspace MyGO imports, Prelude declarations, and available Go FFI metadata.
Open buffers override disk contents, and relevant disk changes are checked
before requests, including creation and deletion.
Completion covers visible bindings, type annotations and generic parameters, package members, fields, enum variants, and methods. Definition and references use source symbol identities across files and import aliases. Document symbols include nested fields, variants and methods; workspace symbol search is case insensitive. Invalid source retains syntax diagnostics and recoverable symbols; unavailable semantic results return null or empty results, while completion uses current recoverable declaration context.
Protocol handling and analysis adapters are written in MyGO; JSON uses Go FFI.
Generated Go files are refreshed with ./mygo sync lsp. Automatic imports,
rename, formatting, and external Go source navigation are outside this feature
set. The process communicates over stdin/stdout using Content-Length frames.
- Keep
examples/main/main.mygorunnable after compiler changes; itsmainfunction should actually do work. - Keep
examples/data-structure/data-structure.mygo,examples/parsec/, andlib/in sync when collection, parser, or library semantics change. - Prefer expressing prelude functionality in MyGO first; only fall back to Go for pieces that cannot yet be represented safely in the language itself.
- Generated
.gen.gofiles are checked in for the prelude, libraries, examples, LSP, and bootstrap compiler; refresh them when MyGO source changes. - When checking the build, use a writable Go cache if the default cache path is unavailable in this environment:
GOCACHE=/tmp/mygo-gocache go test ./...MIT License