LANGUAGE_REFERENCE.md
Rama main · réplica de lectura del repositorio original.
# Rove v4 Language Reference
This document describes the `v4.0.0-rc.2` (`Bodhi`) source-language contract.
Rove source files use the `.rove` extension and are built with the `rove` CLI.
Backend availability is a capability decision, not a change to language syntax.
## 1. Bindings and assignment
```rove
var attempts: int = 0 // mutable binding
let limit: int = 3 // immutable binding
const APP_NAME = "Rove" // immutable binding
set attempts = attempts + 1
```
`let` and `const` prevent rebinding. They do not deep-freeze a struct, array, or
other value reachable through the binding. `set target = value` is the explicit
assignment form; `target = value` remains equivalent for source compatibility.
Array and positional struct destructuring declarations bind several names while
evaluating the initializer exactly once:
```rove
let [left, right] = read_pair()
struct Point { x: int, y: int }
let Point(x, y) = Point(10, 20)
let [first, _] = values // `_` discards one position
```
An array pattern requires an `Array<T>`; insufficient input fails through a
checked bounds path. A struct pattern must name a declared struct and provide
one position for every field in declaration order. Nested and `..rest` patterns
are not part of this first contract.
```rove
struct Counter { value: int }
let counter = Counter(0)
set counter.value = 1 // valid: the binding still refers to the same Counter
// set counter = Counter(2) // error: counter is an immutable binding
```
## 2. Core types
The portable scalar types are `int`, `float`, `bool`, `string`, `char`,
`uintptr`, and `void`. Generic library/compiler types include `Array<T>`,
`Option<T>`, `Result<T, E>`, `Channel<T>`, and `Task<T>`.
Fixed-width scalar spellings are `i8`, `i16`, `i32`, `i64`, `u8`, `u16`,
`u32`, `u64`, `f32`, and `f64`. They select concrete storage widths on native
and Rust backends. A directly assigned integer literal
must fit its declared width (`E2024`); implicit narrowing is not permitted.
The hosted cross-backend arithmetic contract remains the canonical `int` and
`float` contract below until width-specific overflow semantics are frozen for
JavaScript and Python.
`int` is a signed 64-bit two's-complement value. Addition, subtraction,
multiplication, negation, bitwise operations, and left shift wrap modulo 2⁶⁴.
Integer division truncates toward zero, remainder keeps the dividend's sign,
and shift counts are reduced modulo 64. Division by zero raises an error.
Integer literals must be between `-9223372036854775808` and
`9223372036854775807`; an out-of-range literal is `E2012`. The minimum value is
accepted in its directly negated decimal or hexadecimal spelling.
`float` is IEEE-754 binary64. Division by zero produces the corresponding
infinity or NaN; `%` uses a truncating remainder with the dividend's sign.
Canonical text uses `nan`, `inf`, `-inf`, normalized exponents such as `1e-7`,
and renders negative zero as `0`. Finite values use a shortest round-tripping
decimal without a redundant `.0`. Nonzero magnitudes from `1e-6` (inclusive)
to `1e21` (exclusive) use fixed notation; other magnitudes use scientific
notation with an explicit `+` for positive exponents and no exponent padding.
An `int` widens to `float` by IEEE-754 binary64 conversion when required by an
operator, parameter, field, or return type. The conversion can round integers
whose magnitude exceeds 2⁵³; it never changes the original `int` binding's
type. `float` does not narrow to `int` implicitly. Canonical booleans are
rendered as lowercase `true` and `false`.
The full numeric and scalar-text contract is declared by `cpp`, `js`, and
`python`. The beta `wasm` ABI remains explicitly `wasm32` and does not claim
signed-i64 conformance until its numeric ABI is revised.
```rove
let answer: int = 42
let ratio: float = 0.5
let title: string = "Rove"
let maybe_name: string? = null
let values: Array<int> = [1, 2, 3]
```
Strings are Unicode values. Literals support common escapes, embedded `\0`,
four-hex-digit Unicode escapes such as `\u0301`, and interpolation:
```rove
let city = "İstanbul"
print($"hello, {city} 🌙")
```
Rove does not normalize Unicode automatically; NFC and NFD spellings remain
distinct byte sequences.
## 3. Functions
```rove
fn add(a: int, b: int) -> int {
return a + b
}
fn greet(name: string) {
print("Hello, " + name)
}
fn square(value: int) -> int = value * value
fn classify(value: int) -> string = if value < 0 {
"negative"
} elif value == 0 {
"zero"
} else {
"positive"
}
```
Parameters and return values are typed. A missing return annotation means
`void` unless the compiler can safely infer a value type in an inference-enabled
context. `= expression` is an expression-bodied function and behaves as one
implicit `return`. A value-producing `if` requires an `else`; each arm contains
one expression and every arm must have a compatible result type.
A parameter may declare a default value with `= expression`. An omitted trailing
argument is filled with that default value at the call site, so the default is
re-evaluated on every call. Only trailing parameters may be omitted; a required
parameter before an omitted one is an arity error.
```rove
fn greet(name: string = "world", times: int = 1) {
var count: int = 0
while count < times {
print("hi", name)
set count = count + 1
}
}
greet() // name = "world", times = 1
greet("rove") // name = "rove", times = 1
greet("rove", 3) // name = "rove", times = 3
```
A default value whose type does not match its declared parameter type is a
compile-time error, as is omitting a parameter that has no default.
## 4. Async tasks
```rove
async fn compute() -> int {
return 42
}
async fn main() {
let task: Task<int> = compute()
let first: int = await task
let second: int = await task
print(first + second)
}
```
An `async fn ... -> T` call returns `Task<T>`. `await` is valid only inside an
async function and unwraps one `Task<T>` to `T`. A task is reusable: awaiting the
same task more than once observes the same completion. Errors thrown by the task
propagate at `await` and can be caught normally. The exact instant at which a
task begins execution is intentionally not part of the language contract.
The `Task<T>` ABI is currently implemented by `cpp`, `js`, and `python`.
Other targets reject it with a capability diagnostic instead of silently
changing its behavior.
## 5. Control flow
```rove
if score >= 90 {
print("A")
} else if score >= 80 {
print("B")
} else {
print("C")
}
for i in 1..10 {
if i == 5 { continue }
print(i)
}
var remaining = 3
while remaining > 0 {
set remaining = remaining - 1
}
loop {
break
}
```
`a..b` is an inclusive range. `elif` and `else if` are equivalent spellings.
`break` and `continue` are valid only inside loops. Conditions accept only
`bool`; a dynamically typed `any` value is checked at runtime rather than
using C++/JavaScript/Python truthiness.
`match` can also produce a value without a `return` in every arm:
```rove
fn http_label(code: int) -> string = match code {
200 => "ok",
404 => "missing",
_ => "other"
}
```
The final `_` fallback is mandatory and arm values must share a compatible
type. Maya's first value-match form accepts literals. The subject is evaluated
exactly once, including calls and other side-effecting expressions:
```rove
let label = match read_status() { 200 => "ok", _ => "other" }
```
`guard` expresses an early-exit precondition, while `defer` runs an expression
when the current scope exits:
```rove
fn save(value: string?) {
guard value != null else { return }
defer print("save finished")
print(value)
}
```
## 6. Structs, traits, and implementations
```rove
struct Point {
x: int,
y: int
}
trait Show {
fn show(self) -> string
}
impl Show for Point {
fn show(self) -> string {
return $"({self.x}, {self.y})"
}
}
let point = Point(10, 20)
print(point.show())
```
An inherent implementation omits the trait name: `impl Point { ... }`.
Instance methods declare `self` explicitly as their first parameter; an
inherent implementation may also contain an associated function without
`self`. Trait methods are signatures, not default implementations, and
therefore have no body. An `impl Trait for Type` must provide every required
method with the same async marker, parameter types, and return type. The target
must be a declared struct.
## 7. Errors and cleanup
```rove
fn parse_port(value: int) -> int {
if value < 1 { throw "port must be positive" }
return value
}
try {
print(parse_port(0))
} catch error {
print("caught:", error)
}
```
`throw` converts its value to the canonical Rove string representation for the
current exception boundary. `try`/`catch`/`throw` are available on `cpp`,
`js`, and `python`; unsupported targets fail during capability validation.
For recoverable domain errors that are part of an API, prefer `Result<T, E>` and
pattern matching:
```rove
let result: Result<int, string> = Ok(42)
match result {
Ok(value) => print(value),
Err(error) => print(error),
_ => print("unreachable")
}
```
Statement `match` keeps `"_"` as a legacy wildcard for source compatibility;
use `_` in new code. Comparison patterns must match the subject type, except
that an `int` pattern may widen to a `float` subject.
## 8. Pipelines and null safety
```rove
fn doubled(value: int) -> int { return value * 2 }
let result = 21 |> doubled
let display_name = user?.profile?.name ?? "anonymous"
```
`value |> function` passes `value` as the next call's input. `?.` propagates
absence and `??` supplies a fallback.
## 9. Modules
```rove
import "./helper"
import "std/math"
import { sqrt, clamp } from "std/math"
```
Local modules use `.rove` files. Standard-library availability is target-specific
and can be inspected with `rove targets --json`.
Local packages can be locked without a registry:
```text
rove add physics --path ../physics
rove install
```
The lockfile records canonical relative paths and source-content checksums;
recursive dependency cycles are rejected.
For WebAssembly browser programs, `std/web` provides opaque `WebElement`,
`WebEvent`, and `WebListener` handles plus DOM, event, animation-frame, and
Canvas 2D functions. These calls require the generated `nyx_host_v1` adapter
and are rejected on non-WASM targets. The namespace keeps its historical name
for Bundle ABI v1 compatibility.
## 10. Tests and unsafe boundaries
```rove
test "addition" {
assert(add(2, 3) == 5, "addition must be exact")
}
unsafe {
let address = addr(answer)
print(peek(address))
}
```
Raw memory operations must remain inside an explicit `unsafe` boundary.
## 11. CLI
```text
rove check main.rove
rove run main.rove --target cpp
rove build main.rove --target js
rove bundle main.rove --output dist --package --react --vue --svelte
rove test main.rove
rove self-host verify
rove targets --json
```
The canonical stable hosted backends are `cpp` (C++20/native), `js`
(ES2022/Node.js), and `python` (Python 3). `wasm`, `rust`, `react`, and `asm`
expose narrower, machine-readable capability sets and must
reject unsupported semantics.