<img src="https://raw.githubusercontent.com/halcyonnouveau/soppo/refs/heads/main/docs/assets/soppo.png" alt="soppo" style="max-width: 100%;">

# Soppo

A language that compiles to Go, adding ergonomic and type safety features that Go lacks. Soppo uses Go syntax wherever possible - if you know Go, you know most of Soppo.

**[Try it in the playground](https://play.soppolang.dev)**

See [docs/DESIGN.md](docs/design.md) for language design.

Soppo is not production ready.

## Installation

Soppo requires [Go](https://go.dev/doc/install/) to be installed.

Download a pre-built binary from [GitHub Releases](https://github.com/halcyonnouveau/soppo/releases).

Or build from source with Cargo (requires Rust):
```sh
cargo install soppo
```

## Features

- **Enums:** Tagged unions with struct variants
- **Pattern matching:** Exhaustive matching with destructuring
- **Error handling:** `?` propagation and `? err { }` custom handling
- **Nil safety:** Compile-time nil checks
- **Named arguments:** `func(name: value)` for clarity
- **String interpolation:** `"value: {var}"` syntax
- **Detailed error messages:** Rust-inspired compiler diagnostics

## Quick Look

```go
// Enums with struct variants
type Shape enum {
	Circle struct {
		radius float64
	}
	Rectangle struct {
		width float64
		height float64
	}
}

func calcArea(s Shape) float64 {
	var area float64

	// Pattern matching with destructuring
	match s {
	case Shape.Circle{radius: r}:
		area = 3.14159 * r * r
	case Shape.Rectangle{width: w, height: h}:
		area = w * h
	}

	return area
}

func printArea() error {
	// Named arguments and error propagation with `?`
	config := loadConfig(path: "app.toml") ?

	shape := Shape.Circle{radius: config.radius}
	area := calcArea(shape)

	// String interpolation
	fmt.Println("area: {area}")
	return nil
}

func main() {
	// Custom error handling with `? err { }`
	printArea() ? err {
		fmt.Println("error: {err}")
		os.Exit(1)
	}
}
```

### Error Messages

The compiler catches errors early with helpful messages:

```
  × Non-exhaustive match
    ╭─[main.sop:11:5]
 10 │         var message string
 11 │ ╭─▶     match colour {
 12 │ │       case Colour.Red:
 13 │ │           message = "Stop"
 14 │ │       case Colour.Yellow:
 15 │ │           message = "Wait"
 16 │ ├─▶     }
    · ╰──── missing variants: Green
 17 │     }
    ╰────
  help: Ensure all enum variants are handled, or add a `default` case
```

## License

BSD 3-Clause. See [LICENSE](LICENSE).
