Skip to content

v0.41.0

Latest

Choose a tag to compare

@emil14 emil14 released this 08 Aug 10:56
· 24 commits to main since this release
bb7b330

Canonical Flow

Compared to v0.40.0, Neva v0.41.0 establishes one canonical, zero-config format for Neva source, exposes that formatter both through the CLI and a public Go package, adds a portable type-description substrate for future runtime tooling, and hardens several runtime and installation paths.

Highlights

  • neva fmt is now built into the Neva CLI. It formats valid Neva source with one fixed, syntax-only style and is available for stdin, files, and recursively scanned directories.
  • The public Go package pkg/formatter provides the same formatter to tools and integrations. It parses and renders standalone Neva source without module resolution, analysis, desugaring, or code generation.
  • The formatter canonicalizes import blocks and composite literals, wraps breakable layouts at 80 columns, and is checked against the repository source corpus in CI.
  • std/reflect.Type and TypeNode expose a portable finite, indexed description of a Neva type. Recursive edges are represented as indexes into the same descriptor.
  • Turn, Match, and Select now receive independent inputs concurrently, eliminating the sequential-receive deadlock risk when senders arrive in a different order.
  • The Unix installer no longer requires sudo; set NEVA_INSTALL_DIR to choose an explicit destination.

A first-party, zero-config formatter

Use neva fmt before committing, or make it a repository gate:

neva fmt -w .
neva fmt --check .

neva fmt is deliberately opinionated and has zero configuration: each valid source file has exactly one canonical layout. It is syntax-preserving, so semantic style rules and automated refactorings remain separate tooling concerns.

The design drew on gofmt, rustfmt, Prettier, Kotlin, Swift, Zig, and Odin formatters, while settling on Neva's own canon: compact layouts where they remain readable, vertical sequences when they do not, and no ambiguous alternatives for imports, indentation, or spacing.

For example, it sorts imports into their canonical groups and normalizes indentation:

Before

import {
    @:zeta
    third:omega
    fmt
    @:alpha
    third:alpha
    reflect
    third:zeta
    @:omega
    runtime
}

After

import {
	fmt
	reflect
	runtime

	third:alpha
	third:omega
	third:zeta

	@:alpha
	@:omega
	@:zeta
}

It also makes a single deterministic choice when a breakable sequence crosses 80 columns:

Before

type ExtremelyLongAlias very_long_package.SomeVeryLongGeneric<first_type, second_type, third_type>
interface VeryLongInterfaceName<first_very_long_type_parameter, second_very_long_type_parameter, third_very_long_type_parameter> () ()

After

type ExtremelyLongAlias very_long_package.SomeVeryLongGeneric<
	first_type,
	second_type,
	third_type,
>

interface VeryLongInterfaceName<
	first_very_long_type_parameter,
	second_very_long_type_parameter,
	third_very_long_type_parameter,
>() ()

For scripting and editor integration, the command supports standard output, in-place writes, diffs, file listing, parse-error continuation, and deterministic directory traversal:

neva fmt -d path/to/file.neva
neva fmt -l .

Go-based tools can import the same public package used by the CLI:

import "github.com/nevalang/neva/pkg/formatter"

formatted, err := formatter.Format(source)

Portable type descriptors: a foundation for future tooling

std/reflect.Type is a compact graph representation for carrying a resolved Neva type as data. Its public shape is a list of TypeNode values; the relevant node forms include scalar values and indexes to composite children:

pub type Type list<TypeNode>

pub type TypeNode union {
	String
	List int
	Struct list<StructField>
	Union list<UnionCase>
}

The root is node 0; composite relationships point to other nodes by index. For example, the Neva type list<string> is carried at runtime as:

const list_of_strings reflect.Type = [
	reflect.TypeNode::List(1),
	reflect.TypeNode::String,
]

This makes recursive types representable without a global registry or per-message metadata.

This release deliberately provides the descriptor substrate only: it is a foundation for future reflection-aware tooling. It does not add TypeOf, #bind_type, JSON conversion, or a global type registry.

Reliability and developer experience

  • Turn, Match, and Select preserve their existing behavior while accepting independent inputs in either sender order.
  • The installer uses a user-writable location by default and reports release-discovery and download failures correctly.
  • Node and declaration syntax, documentation, and the checked-in source corpus were aligned with the new canonical formatter output.

Included PRs

Full Changelog

v0.40.0...v0.41.0