# goishc — Goish compiler (Go → Goish Rust)

A Go → Goish Rust source-to-source transpiler. Reads one `.go` file at a
time and emits a `.rs` file that compiles against the `goish` crate.

```bash
cd transpiler
go build -o goishc ./
./goishc -o hello.rs hello.go
```

## What it covers

Faithful port of the constructs in the project-root `REFERENCES.md`:

- **Preamble.** Emits `use goish::prelude::*;` plus the usual `#![allow(...)]`
  attributes so common Go naming styles survive rustc.
- **Types.** Primitive name mapping (`int`→`int`, `string`→`string`, etc.),
  `[]T`→`slice<T>`, `map[K]V`→`map<K, V>`, `chan T`→`Chan<T>`, `*T`→`&T`,
  named types via `Type!`, interfaces as `trait`.
- **Declarations.** `type X struct {...}` → `Struct!{...}`. `type X Y` →
  `Type!(X = Y)`. `var X = v` (pkg level) → `var!(X = v)`. `const` blocks
  with `iota` → `Const! { ... }`.
- **Functions.** Multi-return → tuple `(A, B)`. Receivers →
  `impl T { fn ... }` with an automatic `let <recvName> = self;` so the
  body doesn't need rewriting.
- **Statements.** `if`, classic counting `for i := 0; i < n; i++` →
  `for i in 0..n`, `for cond` → `while cond`, `for {}` → `loop {}`,
  `for i, v := range xs` → `for (i, v) in range!(xs)`, `switch` tag-form
  → `match`, `switch {}` → `if/else if`, `select {}` → `select!{}`,
  `defer f()` → `defer!{ f(); }`, `go f()` → `go!{ f(); }`, `ch <- v`
  → `ch.Send(v)`, `x := <-ch` → `let (x, _) = ch.Recv();`.
- **Builtins.** `len` / `cap` / `append` / `copy` / `delete` / `close` /
  `make` → their `!`-macro forms. `panic(x)` → `panic!("{}", x)`.
  `println(x)` → `Println!(x)`. `new(T)` → `T::default()` approximation.
- **fmt / log rewrites.** `fmt.Println/Printf/Sprintf/Errorf/Fprintf`
  → the corresponding prelude macros. Same for `log.*`.
- **Composite literals.** `[]T{...}` → `slice!([]T{...})`;
  `map[K]V{...}` → `map!([K]V{...})`; named `T{...}` → `T { ... }` when
  all fields are key-value, else positional `T!(...)` matching the
  companion macro generated by `Struct!`.
- **Call-site assumption.** Function / method calls pass through
  verbatim — `pkg.F(x, y)` → `pkg::F(x, y)`, `x.F()` → `x.F()`. No
  signature checks, no auto-`&`/`.into()`. You tune at the call site.

## What it flags rather than guess

The transpiler never silently drops a construct. When there's no safe
1:1 port it emits `/* TODO: goishc: <reason> */` at the source location
and prints a summary to stderr:

- Third-party imports (`github.com/...`) — no mapping table entry.
- Embedded struct fields — Goish has no method promotion.
- Type switches (`switch v := x.(type)`) — needs hand-porting to `match`
  on a concrete enum.
- Type assertions (`x.(T)`) — same reason.
- `goto`, labeled `break`/`continue`, `fallthrough` — no direct Rust form.
- Variadic splat (`f(xs...)`) — Rust has no splat; rewrite to explicit
  args or `.extend_from_slice`.
- Three-index slice `s[i:j:k]` — deferred in Goish.
- Imaginary number literals.

### When imports get complex

The transpiler ships an import table covering the Go stdlib packages
listed in `REFERENCES.md`. Anything outside that table (third-party
modules, unported stdlib like `go/ast` or `crypto/tls`, vendored code)
is emitted as:

```rust
// TODO: complex import "github.com/foo/bar" — no direct Goish mapping
```

You'll also see that entry in the stderr summary so it's not missed.
For those cases: decide whether to pull in a native Rust crate, port
by hand, or skip the file — the transpiler won't make that call for
you.

## Layout

```
transpiler/
├── main.go       — CLI entry
├── transpile.go  — AST walker + emitters
├── imports.go    — Go stdlib → Goish Rust mapping table
└── testdata/
    └── hello.go  — smoke test input
```

## Smoke test

```bash
./goishc -o ../examples/transpiled_hello.rs testdata/hello.go
cd .. && cargo run --example transpiled_hello
```

`testdata/hello.go` exercises: struct decl, iota const, package var,
multi-return fn, classic for, range-over-slice, range-over-map,
`errors.New`, `nil` comparison, `fmt.Printf`, `strconv.Atoi`. The
emitted `.rs` compiles and runs against the in-repo `goish` crate.

## Not a goal (yet)

- Rewriting method chains to use refs / `&mut` automatically.
- Resolving which `Sprintf!("{}", …)` vs `Sprintf!("%v", …)` to emit.
- Package-level multi-file projects. Transpile file-by-file and assemble.
- Formatting output with rustfmt. Pipe through `rustfmt` yourself.
