On this page

zena:string-reader

zena
import {…} from 'zena:string-reader';

Classes

StringReader

zena
final class StringReader

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.