Something went wrong. Try again.
A small configuration language for Zig: ZON with let, if and templates over a context, evaluated to a struct, always finishing.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! A parsed program: a tree of nodes, every one of them carrying where it//! was written.//!//! Names are resolved while parsing, so the tree holds no identifiers: a//! reference to a `let` or to an `if` capture is a slot number, and a call//! names its built-in or host function by index. A program that parses has//! no unknown names left in it.
const std = @import("std");
pub const Builtin = @import("builtins.zig").Builtin;
pub const Node = struct { /// Byte offset of the node in the source. pos: u32, data: Data,};
pub const Data = union(enum) { null, bool: bool, int: i64, float: f64, /// A string with no interpolation in it, escapes already decoded. string: []const u8, /// A string with at least one `${ }` in it. template: []const Part, enum_literal: []const u8, /// `ctx`, the caller's context. ctx, /// A `let` or an `if` capture. slot: u32, record: []const Field, list: []const Item, field: struct { object: *const Node, name: []const u8 }, index: struct { object: *const Node, index: *const Node }, /// `x.?` unwrap: *const Node, unary: struct { op: UnaryOp, operand: *const Node }, binary: struct { op: BinaryOp, lhs: *const Node, rhs: *const Node }, @"if": If, @"switch": Switch, call: struct { func: Func, args: []const *const Node },};
pub const Part = union(enum) { text: []const u8, expr: *const Node,};
pub const Field = struct { name: []const u8, /// Where the name was written. pos: u32, value: *const Node,};
/// An item of a list literal, or the value of a field: where an `if` with no/// `else` is allowed, and leaves the item or the field out when it is false.pub const Item = *const Node;
pub const If = struct { cond: *const Node, /// The slot that `|name|` binds, for `if (optional) |name| ...`. capture: ?u32, then: *const Node, /// Null only where the `if` is a field's value or a list's item. @"else": ?*const Node,};
pub const Switch = struct { subject: *const Node, /// In the order written, which is the order they are tried in. prongs: []const Prong, /// The `else` prong, whose `cases` are empty, wherever it was written: /// it is taken only when no other prong matches. Null when there is /// none, and a switch that matches nothing is then an error -- or, as a /// struct field's value or a list's item, leaves it out. @"else": ?Prong,};
pub const Prong = struct { cases: []const Case, /// The slot that `|name|` binds: the payload of a tagged union matched /// by its tag, and the switched-on value otherwise. capture: ?u32, value: *const Node,};
pub const Case = union(enum) { /// Matches what is `==` to it. value: *const Node, /// `lo...hi`: matches what is between them, ends included. range: struct { lo: *const Node, hi: *const Node },};
pub const UnaryOp = enum { not, negate };
pub const BinaryOp = enum { add, sub, mul, div, rem, concat, eq, ne, lt, le, gt, ge, @"and", @"or", @"orelse",
pub fn symbol(op: BinaryOp) []const u8 { return switch (op) { .add => "+", .sub => "-", .mul => "*", .div => "/", .rem => "%", .concat => "++", .eq => "==", .ne => "!=", .lt => "<", .le => "<=", .gt => ">", .ge => ">=", .@"and" => "and", .@"or" => "or", .@"orelse" => "orelse", }; }};
pub const Func = union(enum) { builtin: Builtin, /// An index into the host functions the program was parsed with. host: u32,};