vyrn

std/von

13 exports, from std/von.vyrn.

VON, Vyrn Object Notation, Vyrn's literal grammar saved to a file.

import { parseVon, toVon, Von, VonDoc } from "std/von"

A .von document is one or more import type { T } from "..." lines and one literal value, with no operators, calls, bindings or interpolation. parseVon reads it with the compiler's lex(), which only a gen fn can call, so a config error is a build error. The strictness rules: a bare word is a variant name, never a boolean or a string; duplicate fields and map keys are errors naming both lines; numbers keep their source text and refuse a leading zero; \{ in a string, a tab in indentation and a byte-order mark are errors. Errors read line N, col M: <reason>.

Dependencies

The import graph shows the whole library.

Imported by
type VonField = { name: String, value: Von, line: Int64 }

One name: value field of a record literal. line is the field name's 1-based source line, which duplicate-field errors and origin maps use.

type Von = enum {
    VRecord(String, Array<VonField>),
    VVariant(String, Array<Von>),
    VArray(Array<Von>),
    VMap(Array<VonEntry>),
    VStr(String),
    VInt(String),
    VFloat(String),
    VBool(Bool) }

A VON value. Numbers hold their raw, validated source text, so 18446744073709551615 survives and emit -> parse -> emit is byte-stable.

type VonImport = { names: Array<String>, module: String }

One import type { A, B } from "spec" line of a document header.

type VonTok = { kind: String, text: String, line: Int64, col: Int64 }

One lexed token. lex()'s Token can be named only inside a gen fn, so vonLex copies each row into this type and only vonLex needs a generation context.

gen fn parseVon(src: String) -> Result<VonDoc, String>

Reads a whole VON document. A gen fn because lex() is generation-only. Errors are positioned in src.

fn emitVon(v: Von) -> String

One value as canonical VON text, with no header. It recurses per level; parseVon bounds depth, so only a tree a program builds deeper can reach the call cap.

fn toVon(doc: VonDoc) -> String

A whole document as canonical VON text: the header, a blank line, the value, and a closing newline. Comments do not survive a read and write, so use it to write a document, not to rewrite one.

fn jsonToVon(json: Json, typeName: String, module: String) -> Result<String, String>

Converts a JSON tree to VON text, headed by import type { <typeName> } from "<module>". Every nested object becomes a map for the author to promote; null has no VON spelling and is refused.

Tests

18 test blocks in std/von.vyrn. CI runs all of them.

Test names
  • a document is a header and one value, and the canonical text is a fixed point
  • a bare word is a variant, never a boolean and never a string
  • numbers keep their verbatim digits
  • a leading zero is an error, not an octal guess
  • a number is decimal digits and nothing else
  • duplicates name both lines
  • interpolation and expressions are refused
  • a Vyrn keyword is not a field name, and the error says which word
  • the header is required and the document holds one value
  • a tab in indentation is an error
  • a container breaks a line only where a part is not flat
  • a variant payload keeps its own layout
  • a string escape survives the round trip
  • a control byte without a short escape writes two hex digits
  • a JSON document converts to a VON starting point
  • the conversion refuses what VON has no spelling for
  • nesting past vonMaxDepth is an Err, not a trap
  • several numbers on one line each keep their own verbatim text

Examples

1 program in examples/ import this module. Each runs as WebAssembly and as a native binary.