zena:core

zena
import {…} from 'zena:core';

Foundational language types and utilities: strings, errors, options, results, boxes, ranges, arrays, iterators, and byte buffers.

Many declarations here are available automatically in the language prelude.

Evolving String Internals

String representation and low-level byte access methods are undergoing active redesign. See the Strings guide for current details.

Classes

String

zena
final class String implements Hashable
Implements Hashable
Re-exported from zena:core/string.zena

An immutable sequence of characters with value equality.

Strings are created from string literals, template literals, concatenation, slicing, and StringBuilder.

Evolving String Internals

Low-level byte operations like getByteAt and sliceBytes are temporary implementation details that will become private or restricted in future releases. See the Strings guide for current details.

Constructors
zena
new(data: ByteArray, start: i32, end: i32, encoding: Encoding)
#

Create a new array from a ByteArray.

Important: This should be considered a private constructor - strings are created by the compiler for literals or by StringBuilder/transcoding functions. When Zena supports private constructors, this will be marked as private to prevent misuse.

Properties
zena
encoding: Encoding { get; }
#

The encoding of the backing bytes. Encoding is deliberately an internal detail almost everywhere; this exists for boundary code — canonical-ABI marshaling, host interop — that copies the bytes verbatim and must assert what it is copying rather than assume.

zena
length: i32 { get; }
#

The length of the string in bytes.

Since string operations like slicing and getByteAt operate on bytes, this consistently returns the byte capacity of the view regardless of the underlying encoding (WTF-8 or WTF-16).

TODO: Rename to byteLength or remove entirely.

Methods
zena
static fromByteArray(data: ByteArray, start: i32, end: i32, encoding: Encoding): String
#

Creates a String from a ByteArray with given bounds and encoding. This is used by StringBuilder and other internal operations.

zena
static fromBytes(bytes: FixedArray<u8>): String
#

A String over a copy of bytes, taken as WTF-8 — the bytes a response body or a file arrives as. Zena strings are views over byte arrays, so nothing is re-encoded; the copy is what turns a fixed array into the backing store a view needs.

zena
toBytes(): FixedArray<u8>
#

A copy of this string's bytes, as they are stored — WTF-8 for every string a component builds. The inverse of fromBytes: what a list<u8> position wants, a header value or a body.

zena
static fromParts<A extends Array<String>>(parts: A): String
#

Creates a new string by concatenating all parts. This is more efficient than chained + operators for multiple strings, as it allocates the result array only once.

Generic over the array representation: element access resolves through the bound, so each specialization reads its receiver directly with no interface dispatch.

zena
static fromRawParts(parts: array<String>): String
#

The raw-array entry the compiler's synthesized string joins call — template-literal lowering resolves it by name against a one-parameter raw-array signature. Its body is also the call site that keeps the FixedArray specialization of fromParts reachable. User code calls fromParts.

zena
getByteAt(index: i32): i32
#

Returns the byte at the given index.

For WTF-8 strings, this is the UTF-8 byte at the given index. For WTF-16 strings, this is the byte (not code unit) at the given index.

zena
sliceBytes(start: i32, end: i32): String
#

O(1) zero-copy slice by byte indices. Returns a new String sharing the backing array.

SAFETY: Indices are byte offsets, not code point offsets. Slicing in the middle of a multi-byte UTF-8 sequence produces an invalid string. Use StringReader.mark() to get safe positions.

zena
copy(): String
#

Force a copy - creates a new String with its own backing array. Use this when you need to release the parent string's memory.

zena
copyBytesTo(target: ByteArray, targetOffset: i32, start: i32 = 0, length: i32 = -1): void
#

Copies bytes from this string to a target ByteArray.

target

The target ByteArray to copy to.

targetOffset

The offset in target to start writing.

start

Start byte offset in this string (default: 0).

length

Number of bytes to copy (default: rest of string from start).

zena
startsWith(prefix: String): boolean
#

Returns true if this string starts with the given prefix.

zena
endsWith(suffix: String): boolean
#

Returns true if this string ends with the given suffix.

zena
split(separator: String): FixedArray<String>
#

Splits the string into an array of substrings separated by the given separator.

zena
contains(needle: String): boolean
#
zena
getBackingArrayIfFull(): ByteArray | null
#

Returns the backing ByteArray if the String spans the entire array (i.e. not a slice). Used for optimization by StringBuilder.

zena
compareTo(other: String): i32
#

Compares this string with other in lexicographical code point order.

Returns:

  • < 0 if this < other
  • 0 if this == other
  • > 0 if this > other

In UTF-8, lexicographical byte comparison matches Unicode code point order.

zena
asciiLowerCase(): String
#

FNV-1a hash of the string's bytes, cached in #hashCode after the first computation. Delegates to the compiler's shared string hash helper (generateStringHashFunction), which reads and updates the cache field.

Returns this string with every ASCII letter lowercased; every other byte is left alone. See asciiLowerByte for why this is deliberately not Unicode-aware.

Byte-wise, which is exactly right for WTF-8: an ASCII byte is always a whole code point, and no continuation byte falls in 0x41..0x5A, so no multi-byte sequence can be corrupted. A WTF-16 string would instead need code-unit stepping — and that branch belongs here, on #encoding, rather than in every caller, which is the reason this lives on String at all. No String method supports WTF-16 yet and nothing constructs one today.

Returns this when there is nothing to change, so the common already-lowercase case does not allocate.

zena
asciiUpperCase(): String
#

Returns this string with every ASCII letter uppercased.

zena
hashCode(): i32
#
Operators
zena
operator +(other: String): String
#

Concatenates two strings and returns a new string.

zena
operator ==(other: String): boolean
#

Equality operator - compares the bytes in each view.

Error

zena
class Error
Re-exported from zena:core/error.zena
Constructors
zena
new(message: String)
#
Properties
zena
message: String
#
Methods
zena
getStackTrace(): String | null
#

LookupError

zena
class LookupError extends Error
Extends Error
Re-exported from zena:core/error.zena

Base class for errors when a lookup operation fails.

Constructors
zena
new(message: String)
#
2 inherited members
From Error
Properties
zena
message: String
#
Methods
zena
getStackTrace(): String | null
#

IndexOutOfBoundsError

zena
class IndexOutOfBoundsError extends LookupError
Extends LookupError
Re-exported from zena:core/error.zena

Thrown when an array/sequence index is out of bounds.

Constructors
zena
new(index: i32, length: i32)
#
Properties
zena
index: i32
#
zena
length: i32
#
2 inherited members
From Error
Properties
zena
message: String
#
Methods
zena
getStackTrace(): String | null
#

KeyNotFoundError

zena
class KeyNotFoundError extends LookupError
Extends LookupError
Re-exported from zena:core/error.zena

Thrown when a key is not found in a map or similar collection.

Constructors
zena
new()
#
2 inherited members
From Error
Properties
zena
message: String
#
Methods
zena
getStackTrace(): String | null
#

AsyncInSyncIteration

zena
class AsyncInSyncIteration extends Error
Extends Error
Re-exported from zena:core/error.zena

Thrown by a synchronous for when an iterator's next() reports a Pending step — a value that is not available synchronously. Consume such an iterator with for await instead (docs/design/async-iteration.md).

Constructors
zena
new()
#
2 inherited members
From Error
Properties
zena
message: String
#
Methods
zena
getStackTrace(): String | null
#

Some

zena
class Some<T>
Re-exported from zena:core/option.zena

Represents a present value.

Constructors
zena
new(value: T)
#
Properties
zena
value: T
#

None

zena
class None
Re-exported from zena:core/option.zena

Represents an absent value.

Outcome

zena
sealed class Outcome<T, E>
Re-exported from zena:core/result.zena

Result's storable counterpart: the same two arms as a sealed reference type, for when a result must outlive return position — an array of per-item outcomes, a field holding a deferred answer. Ok carries what the inline form's true arm does, Err the false arm's payload.

Reach for the inline Result<T, E> first: it allocates nothing. This type is for the positions inline tuples cannot occupy, and costs one allocation per outcome.

Variants
zena
case Ok
#
zena
case Err
#

Ok

zena
final class Ok<T, E>(value: T) extends Outcome<T, E>
Extends Outcome<T, E>
Re-exported from zena:core/result.zena

A value outcome.

Properties
zena
value: T
#
2 inherited members
From Outcome
zena
case Ok
#
zena
case Err
#

Err

zena
final class Err<T, E>(error: E) extends Outcome<T, E>
Extends Outcome<T, E>
Re-exported from zena:core/result.zena

An error outcome.

Properties
zena
error: E
#
2 inherited members
From Outcome
zena
case Ok
#
zena
case Err
#

Box

zena
class Box<T>
Re-exported from zena:core/box.zena
Constructors
zena
new(value: T)
#
Properties
zena
var value: T
#

BoundedRange

zena
final class BoundedRange
Re-exported from zena:core/range.zena

A bounded range with both start and end (exclusive). Represents [start, end) - includes start, excludes end.

Constructors
zena
new(start: i32, end: i32)
#
Properties
zena
start: i32
#
zena
end: i32
#

FromRange

zena
final class FromRange
Re-exported from zena:core/range.zena

A range from a start point to infinity/length. Represents [start, ∞) or [start, length).

Constructors
zena
new(start: i32)
#
Properties
zena
start: i32
#

ToRange

zena
final class ToRange
Re-exported from zena:core/range.zena

A range from zero to an end point (exclusive). Represents [0, end).

Constructors
zena
new(end: i32)
#
Properties
zena
end: i32
#

FullRange

zena
final class FullRange
Re-exported from zena:core/range.zena

A full range representing all elements. Represents [0, length).

Resource

zena
abstract resource class Resource implements OwnState
Implements OwnState
Re-exported from zena:core/ownership.zena

The classes declared with the resource modifier — those holding something the garbage collector cannot reclaim, and therefore carrying a release obligation.

resource class R satisfies this without an implements clause, the way a case class satisfies Hashable. It exists to be bounded against: disown and adopt take a T extends Resource rather than any T, because moving a value between the affine and manually-managed regimes is only meaningful for something that has a disposal obligation to move.

There is deliberately no way to hold one. Nothing is assignable to Resource, because the only reference to a resource a program can name is a handle — Own<R>, Borrow<R>, Unmanaged<R> — and those are nominally distinct types that assign to no supertype at all. That is what keeps a widening conversion from dropping the permissions the handle carries, and it is a property of the handles rather than of this interface: the same applies to every supertype, Resource or otherwise.

Resource-ness is what this names; affineness is what Own<T> declares. They are separate properties — see ownership.md §"Resource-ness and affineness are different properties" — so this bound restricts neither Own<T> itself nor the ordinary classes it will eventually wrap.

The root of every resource hierarchy. A resource class with no explicit superclass extends this one, so the lifecycle flag has an ordinary in-language home rather than a field codegen injects, and disown/adopt read it with an ordinary method call rather than an intrinsic. Being the root is also what makes ownership.md §"Resource-ness is inherited" cheap to satisfy: single inheritance means a resource cannot also extend an ordinary class, so the rule that its chain is all resources is structural rather than a check.

Declaring no method that returns this is load-bearing, not incidental. That is the whole reason an arbitrary superclass is unsafe for a resource and this one is not.

ResourceStateError

zena
class ResourceStateError extends Error
Extends Error
Re-exported from zena:core/ownership.zena

Raised when a regime change is handed a resource in the wrong state: adopting one that was never disowned, or disowning one twice.

Both are programming errors rather than expected conditions — the resource was already claimed by someone else, or already released — so they throw rather than returning a Result. A tryAdopt handing back the branch can be added if a caller ever wants it.

Constructors
zena
new(operation: String, actual: String, expected: String)
#
2 inherited members
From Error
Properties
zena
message: String
#
Methods
zena
getStackTrace(): String | null
#

TemplateStringsArray

zena
final class TemplateStringsArray
Re-exported from zena:core/template-strings-array.zena

Represents the string literals in a tagged template expression.

When you write tag\Hello ${name}!`` the tag function receives:

  • strings: TemplateStringsArray containing ["Hello ", "!"]
  • values: array containing [name]

Key properties:

  • Immutable: The strings array cannot be modified.
  • Cached: The same TemplateStringsArray instance is reused across invocations of the same tagged template expression.
  • Interleaved: Strings and values alternate, with strings on both ends. For \a${x}b${y}c`: strings = ["a", "b", "c"], values = [x, y]. This means there is always strings.length == values.length + 1`.

The raw property provides access to the raw (unescaped) string literals, where escape sequences like \\n appear as two characters (\ and n) rather than being interpreted as a newline.

Example:

text
let tag = (strings: TemplateStringsArray, values: FixedArray<anyref>): String => {
  // strings[0] = "Line 1\nLine 2" (newline interpreted)
  // strings.raw[0] = "Line 1\\nLine 2" (backslash-n literal)
  return strings[0];
};
tag\`Line 1\\nLine 2\`;
Constructors
zena
new(strings: ImmutableArray<String>, raw: ImmutableArray<String>)
#
Properties
zena
raw: ImmutableArray<String> { get; }
#

The raw string literals with escape sequences preserved.

zena
length: i32 { get; }
#

The number of string literals. This is always one more than the number of interpolated values.

Operators
zena
operator [](index: i32): String
#

Access a cooked string literal by index.

FilterIterator

zena
final class FilterIterator<T> implements Iterator<T>
Implements Iterator<T>
Re-exported from zena:core/iterable-utils.zena

An Iterator that yields elements matching a predicate.

Constructors
zena
new(iter: Iterator<T>, predicate: (item: T) => boolean)
#
Methods
zena
next(): inline (true, T) | inline (false, _)
#

FilteredIterable

zena
final class FilteredIterable<T> implements Iterable<T>
Implements Iterable<T>
Re-exported from zena:core/iterable-utils.zena

An Iterable that lazily filters elements using a predicate.

Constructors
zena
new(source: Iterable<T>, predicate: (item: T) => boolean)
#
Methods
zena
filter(predicate: (item: T) => boolean): Iterable<T>
#
zena
contains(value: T): boolean
#
zena
all(predicate: (item: T) => boolean): boolean
#
zena
some(predicate: (item: T) => boolean): boolean
#
zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#
zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#

ArrayIterator

zena
final class ArrayIterator<T> implements Iterator<T>
Implements Iterator<T>
Re-exported from zena:core/array-iterator.zena

Iterator over a FixedArray. Holds a reference to the array and tracks position.

Constructors
zena
new(arr: array<T>)
#
Methods
zena
next(): inline (true, T) | inline (false, _)
#

GrowableArrayIterator

zena
final class GrowableArrayIterator<T> implements Iterator<T>
Implements Iterator<T>
Re-exported from zena:core/growable-array-iterator.zena
Constructors
zena
new(buffer: FixedArray<T>, length: i32)
#
Methods
zena
next(): inline (true, T) | inline (false, _)
#

FixedArray

zena
final extension class FixedArray<T> with IterableUtils<T> implements MutableArray<T>, Iterable<T>
Implements MutableArray<T>, Iterable<T>
Mixes in IterableUtils<T>
Re-exported from zena:core/fixed-array.zena
Constructors
zena
new(length: i32, value: T)
#
Properties
zena
length: i32
#
Methods
zena
static from<A>(seq: Array<A>): FixedArray<A>
#
zena
map<U>(f: (item: T, index: i32, seq: FixedArray<T>) => U): FixedArray<U>
#
zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#
zena
reverse(): FixedArray<T>
#
zena
slice(start: i32, end: i32): FixedArray<T>
#

Returns a shallow copy of a portion of the array. The start index is inclusive, the end index is exclusive. Negative indices are not supported.

Operators
zena
operator [](index: i32): T
#
zena
operator []=(index: i32, value: T): void
#
zena
operator [](r: BoundedRange): FixedArray<T>
#

Returns a slice of the array using BoundedRange (a..b).

zena
operator [](r: FromRange): FixedArray<T>
#

Returns a slice from start to end of array (a..).

zena
operator [](r: ToRange): FixedArray<T>
#

Returns a slice from beginning to end index (..b).

zena
operator [](_r: FullRange): FixedArray<T>
#

Returns a copy of the entire array (..).

7 inherited members
From Array
zena
new growable(capacity: i32 = 8): GrowableArray<T>
#

The same as new Array(), named for symmetry with fixed.

zena
new fixed(length: i32, value: T): FixedArray<T>
#

A fixed-length array of length copies of value.

From Iterable
zena
contains(value: T): boolean
#

Returns true if the collection contains the specified value.

zena
all(predicate: (item: T) => boolean): boolean
#

Returns true if all elements match the given predicate. Returns true if the collection is empty.

zena
some(predicate: (item: T) => boolean): boolean
#

Returns true if at least one element matches the given predicate. Returns false if the collection is empty.

zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#

Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.

zena
filter(predicate: (item: T) => boolean): Iterable<T>
#

Returns a new iterable containing only the elements that match the predicate.

GrowableArray

zena
final class GrowableArray<T> implements MutableArray<T>, Iterable<T>
Implements MutableArray<T>, Iterable<T>
Re-exported from zena:core/growable-array.zena
Constructors
zena
new(capacity: i32 = 8, adopting: FixedArray<T> | null = null)
#

adopting, when given, becomes the backing storage, full: length starts at its length, no copy is made, and capacity is ignored. The caller must hand the buffer over — writes through either alias would be visible through the other. from copies; this adopts. (A constructor parameter rather than a static so it works from generic bodies — see the issue linked from growable below.)

Properties
zena
length: i32 { get; }
#
Methods
zena
static from<A>(seq: Array<A>): GrowableArray<A>
#
zena
push(value: T): void
#
zena
pop(): T
#
zena
map<U>(f: (item: T, index: i32, seq: GrowableArray<T>) => U): GrowableArray<U>
#
zena
contains(value: T): boolean
#
zena
all(predicate: (item: T) => boolean): boolean
#
zena
some(predicate: (item: T) => boolean): boolean
#
zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#
zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#
zena
filter(predicate: (item: T) => boolean): Iterable<T>
#
Operators
zena
operator [](index: i32): T
#
zena
operator []=(index: i32, value: T): void
#
2 inherited members
From Array
zena
new growable(capacity: i32 = 8): GrowableArray<T>
#

The same as new Array(), named for symmetry with fixed.

zena
new fixed(length: i32, value: T): FixedArray<T>
#

A fixed-length array of length copies of value.

ImmutableArray

zena
final extension class ImmutableArray<T> with IterableUtils<T> implements Array<T>
Implements Array<T>
Mixes in IterableUtils<T>
Re-exported from zena:core/immutable-array.zena
Properties
zena
length: i32
#
Methods
zena
map<U>(f: (item: T, index: i32, seq: ImmutableArray<T>) => U): FixedArray<U>
#
Operators
zena
operator [](index: i32): T
#
9 inherited members
From Array
zena
new(capacity: i32 = 8): GrowableArray<T>
#

An empty growable array, with room for capacity items before it grows.

zena
new growable(capacity: i32 = 8): GrowableArray<T>
#

The same as new Array(), named for symmetry with fixed.

zena
new fixed(length: i32, value: T): FixedArray<T>
#

A fixed-length array of length copies of value.

From Iterable
zena
contains(value: T): boolean
#

Returns true if the collection contains the specified value.

zena
all(predicate: (item: T) => boolean): boolean
#

Returns true if all elements match the given predicate. Returns true if the collection is empty.

zena
some(predicate: (item: T) => boolean): boolean
#

Returns true if at least one element matches the given predicate. Returns false if the collection is empty.

zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#

Reduces the collection to a single value by accumulating state.

zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#

Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.

zena
filter(predicate: (item: T) => boolean): Iterable<T>
#

Returns a new iterable containing only the elements that match the predicate.

ByteBuffer

zena
final class ByteBuffer
Re-exported from zena:core/byte-buffer.zena

A growable buffer for efficiently constructing binary data.

Constructors
zena
new(capacity: i32 = 256)
#

Creates a new ByteBuffer with the specified initial chunk capacity.

capacity

Initial capacity for the first chunk (default: 256).

Properties
zena
length: i32 { get; }
#

Total number of bytes written to the buffer.

zena
capacity: i32 { get; }
#

Total allocated capacity across all chunks.

Methods
zena
writeByte(b: i32): ByteBuffer
#

Write a single byte.

zena
writeBytes(src: ByteArray): ByteBuffer
#

Write all bytes from a ByteArray.

zena
writeBytesSlice(src: ByteArray, offset: i32, len: i32): ByteBuffer
#

Write a slice of bytes from a ByteArray.

src

Source byte array

offset

Starting offset in source

len

Number of bytes to write

zena
writeBufferRange(other: ByteBuffer, start: i32, end: i32): ByteBuffer
#

Write the byte range [start, end) of another ByteBuffer's contents.

zena
writeBuffer(other: ByteBuffer): ByteBuffer
#

Write another ByteBuffer's contents.

zena
writeU16(value: i32): ByteBuffer
#

Write a 16-bit unsigned integer (little-endian).

zena
writeU32(value: i32): ByteBuffer
#

Write a 32-bit unsigned integer (little-endian).

zena
writeU64(value: i64): ByteBuffer
#

Write a 64-bit integer (little-endian).

zena
writeF32(value: f32): ByteBuffer
#

Write a 32-bit float (little-endian).

zena
writeF64(value: f64): ByteBuffer
#

Write a 64-bit float (little-endian).

zena
writeULEB128(value: i32): ByteBuffer
#

Write an unsigned LEB128 encoded integer.

zena
writeSLEB128(value: i32): ByteBuffer
#

Write a signed LEB128 encoded integer.

zena
writeULEB128_64(value: i64): ByteBuffer
#

Write a 64-bit unsigned LEB128.

zena
writeSLEB128_64(value: i64): ByteBuffer
#

Write a 64-bit signed LEB128.

zena
getByte(index: i32): i32
#

Read a byte at an absolute position.

zena
setByte(index: i32, value: i32): void
#

Write a byte at an absolute position (for patching).

zena
patchU32(index: i32, value: i32): void
#

Patch a U32 at an absolute position (little-endian).

zena
toByteArray(): ByteArray
#

Convert to a single contiguous ByteArray.

zena
clear(): void
#

Clear the buffer, reusing the first chunk.

StringBuilder

zena
final class StringBuilder
Re-exported from zena:core/string-builder.zena

An append-only sequence of characters for efficient string construction.

Constructors
zena
new(capacity: i32 = 16)
#

Creates a new StringBuilder with the specified initial capacity.

capacity

Initial capacity for the first chunk.

Properties
zena
length: i32 { get; }
#

Current length of the built string in bytes.

zena
capacity: i32 { get; }
#

Current capacity (total allocated size).

Methods
zena
append(s: String): StringBuilder
#

Appends a string to the builder.

zena
appendByte(b: i32): StringBuilder
#

Appends a single byte.

zena
appendI32(n: i32): StringBuilder
#

Appends a signed 32-bit integer as decimal. Uses shared conversion from zena:string-convert.

zena
appendU32(n: u32): StringBuilder
#

Appends an unsigned 32-bit integer as decimal. Uses shared conversion from zena:string-convert.

zena
appendI64(n: i64): StringBuilder
#

Appends a signed 64-bit integer as decimal. Uses shared conversion from zena:string-convert.

zena
appendU64(n: u64): StringBuilder
#

Appends an unsigned 64-bit integer as decimal. Uses shared conversion from zena:string-convert.

zena
appendF32(n: f32): StringBuilder
#

Appends a 32-bit float as decimal. Uses shared conversion from zena:string-convert.

zena
appendF64(n: f64): StringBuilder
#

Appends a 64-bit float as decimal. Uses shared conversion from zena:string-convert.

zena
toString(): String
#

Returns the string content.

zena
clear(): void
#

Clears the builder.

zena
static fromString(s: String): StringBuilder
#

Creates a new StringBuilder initialized with the content of the given String. If the string uses its entire backing ByteArray, the builder will adopt the array directly (zero-copy).

IterableJoin

zena
extension class IterableJoin<T>
Re-exported from zena:core/string-builder.zena
Methods
zena
join(stringify: (item: T) => String, separator: String = ', '): String
#

StringReader

zena
final class StringReader
Re-exported from zena:core/string-reader.zena

StringReader - A cursor-based string parser that tracks byte positions.

Use StringReader for parsing to ensure slices are always at valid UTF-8 code point boundaries. Positions from mark() are safe to use with sliceBytes().

Example usage:

text
let r = new StringReader(input);
r.skipWhitespace();
let start = r.mark();
while (!r.isAtEnd && r.peekByte() != 34) {  // 34 = '"'
  r.advance();  // Move by code point (safe for Unicode)
}
let token = r.sliceFrom(start);  // Safe: positions from mark()
Constructors
zena
new(source: String)
#
Properties
zena
position: i32 { get; }
#

Current byte position in the string.

zena
isAtEnd: boolean { get; }
#

True if at end of string.

zena
source: String { get; }
#

The source string being read.

zena
remaining: i32 { get; }
#

Remaining length in bytes.

Methods
zena
peekByte(): i32
#

Peek at the current byte without consuming it. Returns -1 if at end of string. Use for ASCII characters (< 128) like delimiters: { } [ ] , : " etc.

zena
peekByteAt(offset: i32): i32
#

Peek at a byte at offset from current position. Returns -1 if out of bounds.

zena
advanceByte(): i32
#

Consume and return the current byte. Returns -1 if at end. WARNING: Only use for ASCII (< 128). For Unicode text, use advance().

zena
peek(): i32
#

Peek at the current Unicode code point without consuming it. Returns -1 if at end of string. Decodes UTF-8 sequences properly.

TODO: Use shift operators (<< 6, << 12, << 18) when available in Zena. Currently using multiplication as a workaround.

zena
advance(): i32
#

Consume and return the current Unicode code point. Returns -1 if at end. Advances by the correct number of bytes (1-4 for UTF-8).

TODO: Use shift operators (<< 6, << 12, << 18) when available in Zena. Currently using multiplication as a workaround.

zena
skip(count: i32): void
#

Skip N code points (not bytes). Properly handles multi-byte UTF-8 sequences.

zena
mark(): i32
#

Mark the current position for later slicing. Returns an opaque position value safe to use with sliceFrom/sliceRange.

zena
reset(pos: i32): void
#

Reset to a previously marked position.

zena
sliceFrom(start: i32): String
#

Extract a slice from a marked position to current position. This is SAFE because both positions are at code point boundaries.

zena
sliceRange(start: i32, end: i32): String
#

Extract a slice between two marked positions. This is SAFE because both positions are at code point boundaries.

zena
matchByte(expected: i32): boolean
#

Check if current byte matches, and advance if it does. Returns true if matched.

zena
skipWhitespace(): void
#

Skip ASCII whitespace (space, tab, newline, carriage return).

zena
skipBytes(n: i32): void
#

Skip N bytes (not code points). Use with caution - only when you know the bytes are at valid boundaries.

zena
skipBytesWhile(predicate: (byte: i32) => boolean): void
#

Skip bytes while predicate returns true. Predicate receives byte value (not code point). Useful for ASCII character classes: digits, letters, etc.

zena
readUntil(needle: String): String | null
#

Reads a substring up to the next occurrence of needle. If needle is found, returns the substring before it and advances the cursor past needle. If needle is not found, returns null and does not advance the cursor.

zena
readToEnd(): String
#

Reads the remaining substring from current position to the end of the string, advancing the cursor to the end.

Interfaces

Hashable

zena
interface Hashable
Re-exported from zena:core/hashable.zena

A type that can be used as a key in hash-based collections like HashMap and HashSet.

The contract: if two values are equal (per ==, which is a virtual call to operator == when the class defines one, and reference equality otherwise), they must return the same hashCode. The reverse is not required — unequal values may share a hash code, though fewer collisions means better performance.

A class that uses reference equality (no operator ==) should return an identity hash: a value that is unique per instance and stable for the lifetime of the instance, e.g. a counter assigned in the constructor.

Case classes automatically satisfy Hashable: the compiler generates a structural hashCode() (and operator ==) from their parameters. Primitives (i32, boolean, enums, and distinct types over them) also satisfy the Hashable constraint; they hash to their own value. Strings hash with FNV-1a, cached after the first computation.

Methods
zena
hashCode(): i32
#

Disposable

zena
interface Disposable
Re-exported from zena:core/ownership.zena

A value holding something the garbage collector cannot reclaim.

dispose is symbol-keyed rather than name-keyed. dispose is a common enough method name that a class may already have one meaning something unrelated, and this is a protocol the language itself invokes implicitly — a silent collision would be a resource released at the wrong time. Call it as value.[Disposable.dispose]().

zena
import { Disposable } from './ownership.zena';

class Descriptor implements Disposable {
  #handle: i32;
  new(this.#handle);
  [Disposable.dispose](): void { descriptorDrop(this.#handle); }
}

Disposal must be idempotent: dispose() may be called on an already disposed value and must not release the underlying resource twice. Until affine checking lands in O2, nothing statically prevents a double call, and a resource wrapper's state flag is what makes the second one a no-op.

Iterator

zena
interface Iterator<T>
Re-exported from zena:core/iterator.zena

A stateful iterator over elements of type T.

Usage pattern with let-pattern conditions:

text
let iter = collection.[Iterable.iterator]();
while (let (true, item) = iter.next()) {
  // use item
}

Design: Uses inline tuple returns for zero-allocation iteration.

  • next() returns inline (true, T) when there's an element
  • next() returns inline (false, _) when exhausted
Methods
zena
next(): inline (true, T) | inline (false, _)
#

Advances the iterator and returns the next element. Returns inline (true, element) if there is an element, inline (false, _) if exhausted.

Iterable

zena
interface Iterable<T>
Re-exported from zena:core/iterator.zena

A collection that can produce an Iterator.

Methods
zena
contains(value: T): boolean
#

Returns true if the collection contains the specified value.

zena
all(predicate: (item: T) => boolean): boolean
#

Returns true if all elements match the given predicate. Returns true if the collection is empty.

zena
some(predicate: (item: T) => boolean): boolean
#

Returns true if at least one element matches the given predicate. Returns false if the collection is empty.

zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#

Reduces the collection to a single value by accumulating state.

zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#

Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.

zena
filter(predicate: (item: T) => boolean): Iterable<T>
#

Returns a new iterable containing only the elements that match the predicate.

Array

zena
interface Array<T> extends Iterable<T>
Extends Iterable<T>
Re-exported from zena:core/array.zena

A sequence with a length and indexed reads.

This is the read-only view; MutableArray adds indexed writes. The constructors build the standard implementations — new Array() is a GrowableArray and new Array.fixed(n, value) a FixedArray — and are typed as those classes, so the result has the class's full API. (The modules declaring those classes import this one back; classes and interfaces may cross an import cycle.)

Constructors
zena
new(capacity: i32 = 8): GrowableArray<T>
#

An empty growable array, with room for capacity items before it grows.

zena
new growable(capacity: i32 = 8): GrowableArray<T>
#

The same as new Array(), named for symmetry with fixed.

zena
new fixed(length: i32, value: T): FixedArray<T>
#

A fixed-length array of length copies of value.

Properties
zena
length: i32 { get; }
#
Methods
zena
map<U>(f: (item: T, index: i32, seq: this) => U): Array<U>
#
Operators
zena
operator [](index: i32): T
#
6 inherited members
From Iterable
zena
contains(value: T): boolean
#

Returns true if the collection contains the specified value.

zena
all(predicate: (item: T) => boolean): boolean
#

Returns true if all elements match the given predicate. Returns true if the collection is empty.

zena
some(predicate: (item: T) => boolean): boolean
#

Returns true if at least one element matches the given predicate. Returns false if the collection is empty.

zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#

Reduces the collection to a single value by accumulating state.

zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#

Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.

zena
filter(predicate: (item: T) => boolean): Iterable<T>
#

Returns a new iterable containing only the elements that match the predicate.

MutableArray

zena
interface MutableArray<T> extends Array<T>
Extends Array<T>
Re-exported from zena:core/array.zena
Operators
zena
operator []=(index: i32, value: T): void
#
12 inherited members
From Array
Constructors
zena
new(capacity: i32 = 8): GrowableArray<T>
#

An empty growable array, with room for capacity items before it grows.

zena
new growable(capacity: i32 = 8): GrowableArray<T>
#

The same as new Array(), named for symmetry with fixed.

zena
new fixed(length: i32, value: T): FixedArray<T>
#

A fixed-length array of length copies of value.

Properties
zena
length: i32 { get; }
#
Methods
zena
map<U>(f: (item: T, index: i32, seq: this) => U): Array<U>
#
Operators
zena
operator [](index: i32): T
#
From Iterable
zena
contains(value: T): boolean
#

Returns true if the collection contains the specified value.

zena
all(predicate: (item: T) => boolean): boolean
#

Returns true if all elements match the given predicate. Returns true if the collection is empty.

zena
some(predicate: (item: T) => boolean): boolean
#

Returns true if at least one element matches the given predicate. Returns false if the collection is empty.

zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#

Reduces the collection to a single value by accumulating state.

zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#

Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.

zena
filter(predicate: (item: T) => boolean): Iterable<T>
#

Returns a new iterable containing only the elements that match the predicate.

Mixins

IterableUtils

zena
mixin IterableUtils<T> on Iterable<T>
Extends Iterable<T>
Re-exported from zena:core/iterable-utils.zena

Common iteration utilities for any collection that implements Iterable.

Methods
zena
filter(predicate: (item: T) => boolean): Iterable<T>
#

Returns a new iterable containing only the elements that match the predicate.

zena
contains(value: T): boolean
#

Checks if the collection contains the specified value using equality.

zena
all(predicate: (item: T) => boolean): boolean
#

Returns true if all elements match the given predicate. Returns true if the collection is empty.

zena
some(predicate: (item: T) => boolean): boolean
#

Returns true if at least one element matches the given predicate. Returns false if the collection is empty.

zena
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
#

Reduces the collection to a single value by accumulating state.

zena
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
#

Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.

Enums

Encoding

zena
enum Encoding
Re-exported from zena:core/string.zena
Members
zena
WTF8
#
zena
WTF16
#

Type aliases

StackRef

zena
type StackRef = anyref
Re-exported from zena:core/error/stack-host.zena

Opaque host-side stack-trace handle.

Option

zena
type Option<T> = Some<T> | None
Re-exported from zena:core/option.zena

A value that is either present (Some) or absent (None).

Result

zena
type Result<T, E> = inline (true, T, _) | inline (false, _, E)
Re-exported from zena:core/result.zena

Result<T, E> — a value that is either an ok payload or an error payload.

Unlike Option, this is an inline multi-value union, not a heap type: it compiles to WebAssembly multi-value returns, so returning an ok or an error costs no allocation. That is why it is a type alias rather than a class hierarchy — see docs/design/result-option.md.

There are three lanes, not two, so that each lane is type-homogeneous: the discriminant, the ok payload, and the error payload. The unused payload in each arm is a hole (_).

zena
import { Result } from './result.zena';

let checkedSub = (a: i32, b: i32): Result<i32, String> => {
  if (b > a) {
    return (false, _, "underflow");
  }
  return (true, a - b, _);
};

if (let (true, v, _) = checkedSub(10, 4)) {
  // v is 6
}

Inline tuples are return-position-only, so Result<T, E> may name a function's return type but cannot be stored in a variable, field, or collection. To keep a result around, store it as an Outcome below, or match it and store the payload.

Range

zena
type Range = BoundedRange | FromRange | ToRange | FullRange
Re-exported from zena:core/range.zena

Union type of all range types.

Own

zena
type Own<T> = T
Re-exported from zena:core/ownership.zena

The owning reference to a resource. Affine: it may be moved, returned or stored, but not duplicated, and it is released when it leaves scope unmoved.

Erased at codegen: a distinct type is nominally distinct for checking but shares its target's representation, so a handle costs no allocation and no indirection. The three differ in permissions, not data.

Own<T> is what declares affineness; resource class declares resource-ness. The two are separate on purpose — see ownership.md §"Resource-ness and affineness are different properties" — which is why Own<T> will also apply to ordinary classes (from a provably exclusive source) once layer 4 needs it.

Borrow

zena
type Borrow<T> = T
Re-exported from zena:core/ownership.zena

A borrowed reference. Freely copied, but second-class: it may not be returned (except derived from a single borrow parameter), stored in a field or array, or captured by a closure. Never releases what it points at.

At unrestricted instantiations Borrow<T> is the identity — Borrow<i32> is i32 — which is what keeps container APIs from forking.

Unmanaged

zena
type Unmanaged<T> = T
Re-exported from zena:core/ownership.zena

A disowned resource: aliasable like an ordinary reference, and never implicitly dropped. You must dispose() it yourself or adopt() it back into the affine world.

This is the population using was designed for. Entering it costs leak-freedom and compile-time use-after-dispose detection; it costs neither type soundness nor memory safety, because the state flag turns a bad adopt into a clean error rather than a double free.

Scoped

zena
type Scoped<T> = T
Re-exported from zena:core/ownership.zena

A value that may not be duplicated and may not outlive the extent it derives from — the corner of the universe table where both restrictions bind (ownership.md §"Scoped: the fourth corner"). The population is borrow-derived futures and iterators: an async function that holds a Borrow across await returns Scoped<Future<T>>, so the frame holding the borrow cannot escape the borrow's extent.

A scoped value must be consumed exactly once on every path: a scoped future by await or a move, a scoped iterator by for/in. It may not be stored in a field, container, record, or tuple, and may not be captured by a closure. A first-class Future<T> coerces to Scoped<Future<T>>; there is no way back.

ScopedFrom

zena
type ScopedFrom<T, R>
Re-exported from zena:core/ownership.zena

Scoped<R> when T carries a second-class type — a scoped value, a restricted borrow, or a scoped type parameter — and R otherwise (ownership.md §"Combinator audit", docs/design/type-operators.md). For a generic whose result must be scoped exactly when an input is: Future.allSettled<scoped T> returns ScopedFrom<T, Future<Array<Outcome<Awaited<T>, Error>>>>, so a call over scoped futures yields a scoped result the caller must consume, and a call over ordinary futures yields the ordinary future it always did. Inside the generic body the operator reads as Scoped<R>; substitution collapses it once T is known.

TemplateTag

zena
type TemplateTag<T> = (strings: TemplateStringsArray, values: FixedArray<anyref>) => T
Re-exported from zena:core/template-strings-array.zena

Type alias for template tag functions.

Example usage:

text
const html: TemplateTag<String> = (strings, values) => {
  // strings[0], strings[1], etc. are the literal parts
  // values[0], values[1], etc. are the interpolated expressions
  // strings.raw gives access to raw (unescaped) strings
  return '...';
};

const result = html`<div>${name}</div>`;

Functions

asciiLowerByte

zena
function asciiLowerByte(b: i32): i32
Re-exported from zena:core/string.zena

Returns the ASCII lowercase of b, leaving every other byte or code point unchanged.

asciiUpperByte

zena
function asciiUpperByte(b: i32): i32
Re-exported from zena:core/string.zena

Returns the ASCII uppercase of b.

unreachable

zena
declare function unreachable(): never
Re-exported from zena:core/error.zena

captureStackTrace

zena
declare function captureStackTrace(): StackRef | null
Re-exported from zena:core/error/stack-host.zena

formatStackTrace

zena
declare function formatStackTrace(stack: StackRef | null): String | null
Re-exported from zena:core/error/stack-host.zena

some

zena
function some<T>(value: T): Option<T>
Re-exported from zena:core/option.zena

Creates a Some containing the given value.

hash

zena
declare function hash<T>(value: T): i32
Re-exported from zena:core/hashable.zena

The hash code of a value, dispatched on its static type: primitives hash by value, Strings by content, and classes through hashCode().

This is what hash-based collections call. Prefer it over hashCode() — it works for primitives, which have no methods.

equals

zena
declare function equals<T>(a: T, b: T): boolean
Re-exported from zena:core/hashable.zena

Whether two values of the same type are equal, dispatched on their static type: primitives compare by value, Strings by content, and classes through operator == when the class defines one and by reference otherwise.

disown

zena
function disown<T extends Resource>(value: Own<T>): Unmanaged<T>
Re-exported from zena:core/ownership.zena

Leaves the affine regime: takes the owning handle and hands back an aliasable one that is never implicitly dropped.

zena
let raw: Unmanaged<Descriptor> = disown(f);   // f is consumed
// … alias it, store it in a field, put it in an ordinary Array …
let f2: Own<Descriptor> = adopt(raw);         // back under implicit drop

The handles are erased, so this re-types the object rather than allocating anything: Own<T> and Unmanaged<T> lower to the same wasm type, and the body compiles to an identity function returning its argument. The call itself is not yet inlined away.

Requires the resource to be owned and leaves it disowned, so disowning the same resource twice throws rather than handing out two unmanaged aliases with one disposal obligation between them.

disown consumes its argument. Otherwise an Own that will implicitly drop would coexist with an Unmanaged alias to the same resource, and the drop would run under an alias that outlives it. Move checking enforces the consumption for local bindings — a caller that keeps using the original Own after disowning it gets a compile error, through the ordinary rule that an argument to an Own parameter is a move. The flag still guards the routes the checker does not track, such as an Own read out of a field.

The cast is legal here and nowhere else: Own<T> and Unmanaged<T> are opaque types declared in this file, and both erase to T, so re-labelling one as the other mints nothing. See ownership.md §"Handles are not forgeable" — outside this file the same cast is a diagnostic, which is what makes disown and adopt the only doors between the two regimes.

adopt

zena
function adopt<T extends Resource>(value: Unmanaged<T>): Own<T>
Re-exported from zena:core/ownership.zena

Re-enters the affine regime: takes a disowned handle back under implicit drop, so it is released at scope exit again.

The inverse of disown, and the only way back — Unmanaged<R> has no user-callable dispose, since it is not an owner and cannot call the consuming form. A disowned resource is either scoped with using or adopted back.

Throws when the resource is not in the disowned state: owned means something else adopted it first, so two racing adopters do not both succeed — the loser gets a clear error rather than a second owner and, once implicit drop lands, a double free.

dropped throws too: every consuming dispose sets it, so adopting an already-released resource is reported as exactly that.

adopt cannot retract aliases. Aliasability is the point of the disowned state, so the flag is the only defence here, by design.

map

zena
function map<T, U>(it: Scoped<Iterator<T>>, f: (v: T) => U): Scoped<Iterator<U>>
Re-exported from zena:core/ownership.zena

The elements of a scoped iterator mapped through f. Driving the result drives it, inside the same extent — the input is consumed (a scoped iterator is driven exactly once), and the result derives from the same borrow, so it is scoped too.

filter

zena
function filter<T>(it: Scoped<Iterator<T>>, keep: (v: T) => boolean): Scoped<Iterator<T>>
Re-exported from zena:core/ownership.zena

The elements of a scoped iterator for which keep answers true.

take

zena
function take<T>(it: Scoped<Iterator<T>>, count: i32): Scoped<Iterator<T>>
Re-exported from zena:core/ownership.zena

At most the first count elements of a scoped iterator. The loop is always entered — every path out of this body must consume it — so with count <= 0 one element is still pulled from the source before the frame is disposed.

dedent

zena
function dedent(strings: TemplateStringsArray, values: FixedArray<String>): String
Re-exported from zena:core/template-strings-array.zena

A template tag that strips the source indentation from a multi-line template literal, so a block of text can be written at the indentation of the code around it and still come out flush left:

text
let usage = dedent`
  zena build <entry>
    -o <path>   where to write the module
`;
// "zena build <entry>\n  -o <path>   where to write the module"

The rules:

  • The opening line is dropped, along with its line break, when it is blank — which it is in the form above, where the content starts on the line after the backtick. The closing line is dropped the same way. Neither is dropped when it has content on it: a line with content is a line, and it takes part in the rule below like any other.
  • The indentation removed from every remaining line is the longest common prefix of the indentation of the lines that have content on them. It is compared byte for byte, so a file that mixes tabs and spaces dedents by what its lines actually share rather than by a count that assumes a tab width.
  • Blank lines are ignored when computing that prefix and come out empty, so a line of leftover trailing spaces is not what decides the result.
  • Interpolated values are inserted verbatim. A value containing newlines is not re-indented, and its newlines do not start lines that participate in the computation: only indentation written in the literal counts. A line that starts with a value is a content line, and the whitespace before the value is its indentation.

Interpolations must be Strings — a tag receives its values without the conversion ${} performs in an untagged template literal, so write dedent`count: ${`${n}`}` (or i32ToString(n)) for a number.

The text dedented is the cooked strings, so an escape is processed before the indentation is measured: a \n written as an escape breaks a line here exactly as a real newline does. Today that is theory rather than practice — a tagged template whose literal contains any escape sequence fails to compile, whatever the tag (see elematic/zena#84).

fixed

zena
function fixed<T>(items: FixedArray<T>): FixedArray<T>
Re-exported from zena:core/fixed-array.zena

Its argument, unchanged: fixed([1, 2, 3]).

The parameter supplies the mutable context, so a literal argument builds directly as a FixedArray — a mutable literal in expression position, where no annotation can say so. The identity body inlines away, leaving the bare allocation.

growable

zena
function growable<T>(items: FixedArray<T>): GrowableArray<T>
Re-exported from zena:core/growable-array.zena

A growable array from an array literal: growable([1, 2, 3]).

The parameter supplies the mutable context, so the literal builds directly as a FixedArray and is adopted as the backing storage — no copy, unlike GrowableArray.from over an interface-typed source. Until literal decorators land, this is the concise spelling for a growable array with initial contents.

newByteArray

zena
function newByteArray(size: i32): ByteArray
Re-exported from zena:core/byte-array.zena

Create a new ByteArray of the specified size, filled with zeros.

copyBytes

zena
function copyBytes(dest: ByteArray, destOffset: i32, src: ByteArray, srcOffset: i32, length: i32): void
Re-exported from zena:core/byte-array.zena

Copy bytes from source to destination.

dest

Destination array

destOffset

Starting index in destination

src

Source array

srcOffset

Starting index in source

length

Number of bytes to copy

writeI32

zena
function writeI32(value: i32, buffer: ByteArray, bufferEnd: i32): inline (i32, i32)
Re-exported from zena:core/string-convert.zena

Writes an i32 to a buffer. Buffer must have at least 11 bytes. Returns (startPos, endPos) where the digits are in buffer[startPos..endPos).

writeU32

zena
function writeU32(value: u32, buffer: ByteArray, bufferEnd: i32): inline (i32, i32)
Re-exported from zena:core/string-convert.zena

Writes a u32 to a buffer. Buffer must have at least 10 bytes. Returns (startPos, endPos).

writeI64

zena
function writeI64(value: i64, buffer: ByteArray, bufferEnd: i32): inline (i32, i32)
Re-exported from zena:core/string-convert.zena

Writes an i64 to a buffer. Buffer must have at least 20 bytes. Returns (startPos, endPos).

writeU64

zena
function writeU64(value: u64, buffer: ByteArray, bufferEnd: i32): inline (i32, i32)
Re-exported from zena:core/string-convert.zena

Writes a u64 to a buffer. Buffer must have at least 20 bytes. Returns (startPos, endPos).

i32ToString

zena
function i32ToString(value: i32): String
Re-exported from zena:core/string-convert.zena

Converts an i32 to its decimal string representation.

u32ToString

zena
function u32ToString(value: u32): String
Re-exported from zena:core/string-convert.zena

Converts a u32 to its decimal string representation.

i64ToString

zena
function i64ToString(value: i64): String
Re-exported from zena:core/string-convert.zena

Converts an i64 to its decimal string representation.

u64ToString

zena
function u64ToString(value: u64): String
Re-exported from zena:core/string-convert.zena

Converts a u64 to its decimal string representation.

boolToString

zena
function boolToString(value: boolean): String
Re-exported from zena:core/string-convert.zena

Converts a bool to "true" or "false".

parseI32

zena
function parseI32(s: String): inline (true, i32) | inline (false, _)
Re-exported from zena:core/string-convert.zena

Parse a decimal integer from a string, with optional leading sign. Returns inline (true, value) on success, inline (false, _) on failure. Fails if the string is empty or contains non-digit characters (after optional sign).

decimalToF64

zena
function decimalToF64(d: u64, p: i32, negative: boolean, inexact: boolean, tail: u64): f64
Re-exported from zena:core/string-convert.zena

The f64 nearest to d * 10^p, correctly rounded. d is the decimal significand as an integer below 2^64 and p its decimal exponent. inexact says the true value lies strictly between d and d + 1 — the caller had more digits than it could keep — and tail is that leftover fraction scaled by 2^11.

With 19 or fewer significant digits inexact is false and the result is the correctly rounded one, always. Beyond that the significand no longer fits: normalizing d to 64 bits leaves only 64 - bits(d) low bits for the remainder, so the value is placed to within half of the last of them and can land on the wrong side of a rounding boundary that falls inside that gap. Measured against a correctly-rounded implementation this is about one input in five thousand of more than 19 significant digits, always by one ulp (dev/fp-difftest.js measures it). Closing it needs an exact-arithmetic fallback, which the algorithm this comes from also leaves to its caller.

f32ToString

zena
function f32ToString(value: f32): String
Re-exported from zena:core/string-convert.zena

The shortest decimal string that reads back as this f32. The f32 interval is used, not the f64 one the promoted value would have, so 0.1 as f32 prints "0.1" rather than "0.10000000149011612".

f64ToString

zena
function f64ToString(value: f64): String
Re-exported from zena:core/string-convert.zena

The shortest decimal string that reads back as this f64.

f64ToPrecision

zena
function f64ToPrecision(value: f64, sigDigits: i32): String
Re-exported from zena:core/string-convert.zena

value rounded to sigDigits significant decimal digits, in the same format f64ToString uses. sigDigits is clamped to [1, 17].

parseF64

zena
function parseF64(s: String): f64
Re-exported from zena:core/string-convert.zena

Parses a decimal (or hexadecimal) number string to the NEAREST f64, correctly rounded.

The significand is accumulated as an integer and the exponent tracked alongside, so no rounding happens until the single decimalToF64 at the end. Digits beyond the nineteenth cannot change the result except through the tie they might break, so they are folded into a sticky low digit rather than dropped.

parseI64

zena
function parseI64(s: String): inline (true, i64) | inline (false, _)
Re-exported from zena:core/string-convert.zena

Parse an i64 integer from a string, supporting optional leading sign, optional hex prefix (0x or 0X), and optional underscores (_). Returns inline (true, value) on success, inline (false, _) on failure.

Variables

none

zena
let none: None
Re-exported from zena:core/option.zena

The singleton None instance.