Preparing the ZBL download portal…
Preparing the ZBL download portal…
Versioned documentation from the actual SDK workspace.
Windows 11 x64, PowerShell 5.1/7 and Windows tar are the verified target. Rust/Cargo are only bootstrap development tools. Official portal: https://dev.zebvixchain.com/download. Nothing has been publicly deployed or published.
The versioned bootstrap CLI installs to %LOCALAPPDATA%\Zebvix\bootstrap\0.2.0\bin; managed SDK goes to sdks/0.2.0 with an atomic current pointer. Existing versions are preserved. New bootstrap PATH precedes older versions. Use ZEBVIX_HOME consistently to isolate review installs.
cd C:\path\to\zbl
$manifest = "$PWD\website\releases\manifest.json"
$cli = "$PWD\website\artifacts\zebvix-cli-0.2.0-foundation.2-windows-x64.exe"
$archive = "$PWD\website\artifacts\zbl-sdk-0.2.0-foundation.2-windows-x64.tar.gz"
$env:ZEBVIX_HOME = "$env:LOCALAPPDATA\Zebvix-v02-review"
./scripts/bootstrap.ps1 -Manifest $manifest -Artifact $cli
$env:Path = "$env:ZEBVIX_HOME\bootstrap\0.2.0\bin;" + $env:Path
zebvix install --manifest $manifest --artifact $archive
zebvix --version
zebvix doctor
zebvix new hello-zbl
cd hello-zbl
zebvix check
zebvix fmt
zebvix fmt --check
zebvix test
zebvix build
zebvix run
Offline review requires both local file arguments and explicitly trusts supplied unsigned metadata for integrity, not publisher identity. SHA-256/size, archive paths/link types, payload checksums and reported SDK version are validated before selection. There is no arbitrary network release URL option. Default online install requires available objects at the official HTTPS origin; it cannot work against an unpublished/staged release.
zebvix update --manifest $manifest --artifact $archive
# From outside the SDK directory, through bootstrap CLI:
zebvix uninstall
Uninstall preserves user projects and bootstrap, refuses modified known SDK files and never recursively deletes arbitrary directories. User files left in a version directory can prevent reinstall of that exact version until moved by their owner. Signed metadata is refused until compatible signature verification is implemented. Current release is unsigned, not certified. No MSI/ZIP is generated. Bundled zbl.exe is only a compatibility alias.
Packaging from source: load scripts/toolchain.ps1, run cargo test --locked, then scripts/package.ps1 with a fresh destination (default dist). Website preparation uses the exact package directory and creates deterministic tar.gz plus hashes. Follow the actual test report for the final destination; never overwrite an existing immutable artifact.
Compatibility alias note: the v0.2 bootstrap installer also places zbl.exe beside zebvix.exe using the same verified CLI bytes, so both names resolve through the bootstrap PATH. The SDK includes its independently built same-source zbl compatibility target as well. zebvix is the official name.
Status: implemented experimental foundation. One compiler, common AST, static checker, typed metadata and interpreter serve Easy and Advanced source. New spelling does not select a different runtime.
UTF-8 without BOM. Identifiers are case-sensitive ASCII [A-Za-z_][A-Za-z0-9_]*; text literals support Unicode scalar values. Source spans record UTF-8 byte start/end offsets (end exclusive) plus one-based line/scalar column. Tabs count as one column inside a line; tabs in leading indentation are rejected. CRLF and LF work. Blank/comment-only lines do not affect layout. # and // comments extend to end of line outside strings. Four-space indentation, exactly one level per block increase; dedent must match a previous level. Blocks require at least one statement. No multiline literals/expressions or implicit continuation. INDENT/DEDENT/NEWLINE tokens are explicit.
Text is double-quoted with escapes for n/r/t, quote and backslash only. Decimal i64 literal magnitudes range 0..9223372036854775807; negative numbers use unary minus. Minimum i64 can be expressed as -9223372036854775807 - 1. true, false and unit are literals.
program = { declaration | statement }, EOF ;
declaration = task | shape | "needs", identifier, NEWLINE ;
task = "task", identifier, "(", [ parameters ], ")", [ "gives", type ], block ;
parameters = identifier, ":", type, { ",", identifier, ":", type } ;
shape = "shape", identifier, ":", NEWLINE, INDENT, field, { field }, DEDENT ;
field = identifier, ":", type, NEWLINE ;
type = "i64" | "int" | "bool" | "text" | "string" | "unit" | "Error"
| "List", "[", type, "]" | "Map", "[", ("text" | "string"), ",", type, "]"
| shape-name ;
block = ":", NEWLINE, INDENT, statement, { statement }, DEDENT ;
statement = [ "fixed" ], identifier, [ ":", type ], "=", expression, NEWLINE
| "show", expression, NEWLINE
| "give", [ expression ], NEWLINE
| expression, NEWLINE
| "when", expression, block, [ "otherwise", block ]
| "repeat", identifier, "in", expression, block
| "attempt", block, "otherwise", identifier, block ;
expression = range ;
range = disjunction, { "..", disjunction } ;
disjunction = conjunction, { "or", conjunction } ;
conjunction = equality, { "and", equality } ;
equality = comparison, { ("==" | "!="), comparison } ;
comparison = sum, { ("<" | ">" | "<=" | ">="), sum } ;
sum = product, { ("+" | "-"), product } ;
product = unary, { ("*" | "/" | "%"), unary } ;
unary = ("-" | "!" | "not"), unary | postfix ;
postfix = primary, { "[", expression, "]" | ".", identifier } ;
primary = integer | text-literal | "true" | "false" | "unit"
| "(", expression, ")"
| identifier, [ "(", [ arguments ], ")" ]
| "[", [ arguments ], "]"
| "{", [ text-literal, ":", expression,
{ ",", text-literal, ":", expression } ], "}" ;
arguments = expression, { ",", expression } ;
name = "Zebvix"
task welcome(user: text):
show "Welcome " + user
welcome(name)
total = 0
repeat number in 1..5:
total = total + number
when total == 10:
show "ready"
otherwise:
show "check arithmetic"
Run the working examples/easy project using zebvix check, zebvix run and zebvix test. No main task is required. Each block indents exactly four spaces. Function inputs are explicitly typed; local assignments infer a stable type. Pass script values to tasks rather than assuming global capture. fixed makes a binding immutable. Lists use [1,2], Maps use {"count":2}; annotate empty collections with List[i64] or Map[text,i64]. See the specification for precise scopes and errors.
shape Account:
owner: text
balance: i64
task multiply(a: i64, b: i64) gives i64:
give a * b
fixed account = Account("Ada", 120)
values: List[i64] = []
values = append(values, multiply(3, 4))
show account.owner
show values[0]
attempt:
show values[99]
otherwise error:
show error.kind
Run examples/advanced for shapes, collections, branches, typed functions and recoverable errors. All these features use the same pipeline as Easy ZBL. Explicit parameter/result types are statically checked; every return path must match. No generics beyond builtin collection type constructors, ownership/borrowing/lifetimes, concurrency or advanced effect checking is implemented. needs console is a validated declaration, not a sandbox boundary.
Public commands perform real work without wrapping Cargo:
| Command | Implemented behavior |
|---|---|
| zebvix --version | CLI, embedded SDK and selected installed SDK versions |
| zebvix new <project> | New complete project, inferred script plus typed test task |
| zebvix check | Compile/type-check current src/main.zbl without writing an artifact |
| zebvix fmt | Compile first, normalize LF/trailing whitespace/final newline, preserve text contents |
| zebvix fmt --check | Validate formatting without writing; nonzero if changes needed |
| zebvix test | Execute actual test_ tasks/functions; zero tests/failures return nonzero |
| zebvix build | Real compile to canonical versioned checked-source .zbc |
| zebvix run | Build then execute current checked AST |
| zebvix doctor | Active SDK/home, host, PowerShell/tar presence, actual backend |
| zebvix install | Verified versioned SDK selection; public online availability still gated |
| zebvix update | Verified no-op/new version design; rejects downgrade/overwrite/corrupt bytes |
| zebvix uninstall | Known SDK files only, preflight checks, preserve projects/bootstrap |
zbl.exe is a same-implementation compatibility alias; zebvix remains official. Current-directory zbl.toml accepts sdk="0.2.0" and legacy sdk="0.1.0". Source is src/main.zbl. Lifecycle options remain --version x.y.z, plus explicit paired --manifest/--artifact for offline review. fmt is intentionally a whitespace formatter, not a full pretty-printer. Invalid source is never rewritten. Filesystem writes can fail and return nonzero; no transaction guarantee across unrelated CLI commands is claimed.
Normal SDK use needs neither Rust nor Cargo. Bootstrap developers use cargo separately. Success is exit 0; invalid usage/config/syntax/types/runtime/tests/format checks/installation are exit 1. Compile diagnostics include file/line/column; runtime errors include a structured kind and location. Tests do not run top-level scripts or capture their locals. Public releases are not invented; online install/update remain unavailable while manifests are staged.
Incremental extension of baseline 389769c, not a replacement repository. One Rust package/library; no placeholder crates. lib.rs retains the original scalar lexer and legacy parser, now with byte spans and limits. frontend.rs emits indentation tokens and parses modern declarations/blocks. expression.rs is a shared expression parser. Both frontends produce model.rs AST/types/values. checker.rs performs shape/function resolution, lexical scope/type checking, inference and return analysis. Its TypedProgram contains the validated AST, resolved function signatures and a ledger of expression source tokens/types (minimal typed IR, not SSA). runtime.rs consumes signatures and the verified AST. lib.rs compile drives the pipeline and formats diagnostics. main.rs provides actual public CLI commands; manager.rs plus the embedded Windows script handle version selection/lifecycle.
Pipeline: source -> mode/layout lexing -> common AST -> name resolution -> static checks -> TypedProgram -> AST interpreter. Easy/Advanced are documentation styles in one modern grammar, not separate compilers. Legacy syntax is a compatibility surface sharing AST/types/runtime. Source/build artifacts remain canonical checked-source text with a version header. Bytecode/code generation are designs in ZBL_BYTECODE_DESIGN.md; no bytecode or native backend is advertised.
Runtime uses value semantics, lexical scope stacks, checked arithmetic, structured errors and resource guards. A regression during extension exposed stack pressure at the existing 128-frame recursion guard; compiler/runtime worker threads now reserve 16 MiB stacks and the old/new recursion tests return a typed Depth error rather than aborting. This does not make the runtime a security sandbox.
Packaging scripts copy the CLI, compatibility alias, embedded runtime/stdlib, docs, examples and editor sources. Old installations and immutable v0.1 artifacts remain intact. The inherited MIT file is preserved without making a new license selection; publication is disabled pending owner approval. The website remains local/staged.
Real-upgrade regression note: Windows PowerShell 5.1 converts a null string argument incompatibly for File.Replace's backup path. The first v0.2 candidate failed activation while preserving the prior version. It is withdrawn locally. The final manager uses a unique explicit backup pathname, atomically replaces current, and removes only its generated backup. The lifecycle suite now exercises replacement of an existing prior-version pointer; genuine v0.1-to-v0.2 archive upgrade is independently checked.
Concrete types: i64/int, bool, text/string, unit, nominal shapes, Error, List[T], Map[text,T]. Internal Range supports iteration; an internal Unknown bottom is used only to constrain empty literals, never as an inferred stored binding type. Empty collection annotations/signature contexts or append/put provide element types. Heterogeneous collection values are rejected. Nominal shape fields and positional constructor arguments are resolved before checking bodies. Shape names may be forward referenced.
Local inference is expression-based; function parameters and nonunit results require annotations. No implicit coercion. Assignment updates the nearest existing mutable lexical binding, otherwise infers a new local. Annotated/fixed bindings declare locally and can shadow outer scopes; duplicates in one scope fail. fixed prevents rebinding; collection operations return clones/new values. No index/field mutation exists. Loop variables/caught Error are readonly.
All function bodies, even unused ones, are checked. Calls resolve before execution; unknown variables, functions, shapes, fields, invalid operators and arity/type mismatches fail compile. Nonunit return analysis covers both branches and both attempt outcomes; loops do not guarantee execution. Error.kind/message are text; catchable/fatal kinds are documented in the spec. No full type inference, polymorphic user generics, nullable values, union types, ownership/lifetimes or static effect isolation is claimed.
Not implemented in v0.2. Current .zbc is checked-source text, not the format below. General ZBL bytecode is separate from any future blockchain ZBVM.
Proposed little-endian binary header: 8 bytes ASCII ZBLBC followed by three zero bytes; u16 format=1; u16 flags=0; u32 total byte length; u32 constant count; u32 function count; u32 entry function index. Sections follow in order: constants, shapes, function descriptors, instruction arrays. Every variable-sized section begins with u32 byte length; loaders reject truncation, trailing bytes, unknown flags/tags, count overflow and lengths beyond configured limits. All indices are u32. No host addresses or native pointers.
Constant records: u8 tag (1 i64, 2 bool, 3 UTF-8 text, 4 unit), u32 payload length, payload. i64 payload is 8 bytes; bool 1 byte 0/1; unit zero bytes; text must be valid UTF-8. Types encode primitive tags and bounded recursive List/Map/shape-index references. Shape section: u32 count then field-name constant indices and field type records per shape. Cycles are nominal index references, not infinitely expanded types.
Function descriptor: name text-constant index, parameter count/types, result type, local count/types, maximum operand-stack depth, instruction count and code byte offset. Instructions are typed stack operations: CONST(index), LOCAL_GET/SET(index), ADD_I64/SUB_I64/MUL_I64/DIV_I64/REM_I64, EQ(type), LT_I64, NOT_BOOL, CONCAT_TEXT, CALL(function), RETURN, PRINT(type), LIST_NEW(type,count), MAP_NEW(type,count), INDEX(type), SHAPE_NEW(index), FIELD_GET(shape,field), JUMP(target), JUMP_IF_FALSE(target), TRY_BEGIN(handler), TRY_END. Opcode u8 followed by fixed-width operands described by a future normative opcode table; source maps in a separate bounded optional section would require a new flag definition before implementation. There is deliberately no executable prototype or invented opcode compatibility guarantee.
Verifier worklist: decode every instruction first and establish boundaries; validate indices, local/field/type references, function signatures and jump targets; propagate exact typed operand stacks/local initialization across CFG edges; require identical merge stacks and balanced handlers; check all returns and declared stack maxima; reject fallthrough, unreachable malformed instructions and invalid entry signatures. Runtime must re-check arithmetic, bounds, missing keys, fuel, call depth and memory quotas. Loading and execution APIs will not be exposed until malformed-bytecode tests and interpreter differential tests pass.
Milestones: finalize opcode encodings/shape section and memory quotas; verified scalar VM POC; differential legacy/modern AST tests; structured data and recovery opcodes; portable artifact fixtures. None is required to claim the current AST foundation works; none is marked complete.
Self-hosting means writing ZBLC in ZBL, not cloud hosting. Rust Stage 0 remains the implementation and must not be replaced on a claim alone.
Stage 0 (implemented): Rust lexer/parser/name resolution/types/typed metadata/interpreter and tested CLI/SDK. Stage 1 (future): implement a ZBL-written compiler and compile/execute it using Stage 0. Stage 2 (future): use that resulting compiler to compile its own sources. Stage 3 (future): repeat independently, compare canonical artifacts and behavior, and investigate every mismatch. Require clean builds, fixed tool versions, diverse test corpora and reproducibility evidence before replacing Stage 0.
Prerequisite gaps: modules/import resolution; enums/tagged unions; pattern matching; richer typed collections and safe persistent/mutable APIs; byte/UTF-8 processing beyond scalar text indexing; filesystem input/output and actual enforcement for declared capabilities; binary artifact output; structured compiler diagnostic APIs; memory quotas; AST/IR transformation libraries; portable verified backend. v0.2 shapes, lists/maps, typed tasks and errors help but are insufficient for a self-hosted compiler.
Acceptance gates: lex/parse entire compiler source in ZBL; run compiler unit/integration suites; bootstrap compiler with Rust; self-compile twice; compare deterministic artifacts and semantic outputs; independent review/second environment. No compiler written in ZBL, Stage 1 artifact, native backend or self-hosting success is delivered or claimed here.
New indentation-based task/give/show syntax shares the legacy compiler/type checker/runtime. Adds inferred locals, lexical scopes/fixed bindings, when/otherwise, repeat ranges/lists, typed Lists/Maps/shapes/fields, Unicode scalar text operations and typed recoverable errors. Function annotations stay explicit. needs console is static declaration validation only. Legacy braces and the zbl executable alias remain supported.
zebvix check and whitespace fmt/fmt --check perform real work. New project templates use modern source and actual tests. Windows packaging includes current examples, docs, compatibility executable and editor sources. The download portal integrates actual candidate manifests, checksums and versioned documentation without public availability claims.
Bytecode is a precise future format design; self-hosting remains a roadmap. No native/web/blockchain backend, ownership model, LSP/debugger or public release is claimed. Current release status is staged/unsigned until hosting, signing and owner approvals are independently satisfied. See test evidence and known limitations.
Implemented experimental foundation, not production readiness. AST interpreter and checked-source artifacts only; bytecode is a design document. No native codegen, .zbc loader, general modules, enums/matching, user generics, ownership/borrowing/lifetimes, concurrency, files/network APIs, web compiler, smart contracts or ZBVM. No self-hosted compiler exists.
Indentation is exactly four spaces, no tabs/multiline expressions/trailing commas/empty blocks. Parameters need types; nonunit results need gives annotations. No globals captured by tasks, break/continue, field/index mutation, nullable types or arbitrary map key types. Shapes use positional constructors. Empty collections need type context. Text indexing counts scalars, not grapheme clusters. Error recovery is bounded top-level newline synchronization, not IDE-grade parser recovery.
fixed is immutable rebinding with value semantics, not an ownership checker. needs console validates declaration spelling only, without actual capability isolation. Fuel/depth limits are fatal and cannot be caught. Source and stack guards are bounded but heap/output growth is not; not an untrusted-code sandbox. Formatter does not reflow operators or comments.
Windows is locally verified; fresh second-machine and public HTTPS releases/signing remain unverified/unconfigured. Lifecycle installers refuse signed metadata. CLI self-update remains future work. A newer-version update cannot be claimed from nonexistent public releases; local verified version selection/no-op/failure paths are tested. CI files are prepared, not executed on GitHub. Existing license text is preserved pending owner confirmation; no remote publishing or licensing decision is made. VS Code grammar/snippets/tasks only, no LSP/autocomplete/debugger/formatting provider/VSIX.
Baseline audit: ZBL_v0.2_BASELINE_AUDIT.md. Verified source checks: 37 Rust tests passed (11 legacy language, 23 modern language, 3 CLI tests). Final counts and exact archive installation evidence are maintained in website/TEST_EVIDENCE.md to avoid self-referential archive checksums. Test results must be refreshed after later changes; this bundled report does not claim GitHub CI or public hosting success.
Actual verified behavior: inferred Easy scripts, explicit Advanced tasks, scopes/fixed, return paths, ranges/Lists/Maps/shapes, text scalars, structured errors, static declarations, checked operations, fuel/depth failures, UTF-8 spans, parser recovery, legacy naming compatibility, formatter semantics and idempotence, zbl executable alias and all public command paths. Existing baseline tests were retained.
A development regression caused debug runtime stack overflow before the depth guard; bounded worker stacks fixed it and the original recursion test passes. This initial failure is not hidden. Compiler/runtime remain an AST interpreter; bytecode/self-hosting are design milestones only. No ZBX repository modifications or public publication occurred.
Reproduce: scripts/toolchain.ps1; cargo fmt --check; cargo clippy --all-targets --locked -- -D warnings; cargo test --locked; cargo build --release --locked. Public installed CLI: zebvix --version, doctor, new, check, fmt, fmt --check, test, build, run. Run examples/easy and examples/advanced. scripts/verify-zebvix.ps1 verifies actual archive bootstrap/lifecycle/PATH/project safety; transport fixtures are controlled and make no public connections.
Prepared locally: .github/workflows/windows-ci.yml and release-package.yml, issue/PR templates, CONTRIBUTING.md, SECURITY.md and LICENSE_PENDING.md. No remote repository was created, deleted, pushed or published; no workflow run on GitHub is claimed.
Windows CI pins Rust 1.98.1 MSVC, installs the locked Node version, runs fmt/clippy/tests/release build, prepares real SDK/checksums, then website validation/build. Checkout and setup-node action commits were resolved from their official v7.0.1 and v7.1.0 tags; references are immutable full SHAs. Actions read source only, persist no Git credentials, use contents:read, and contain no publishing credentials. Owner must validate runner compatibility on the actual repository; local MSVC linking is unavailable and local evidence uses GNU/WinLibs.
The manual packaging workflow uses release-review environment, which must have required reviewers configured by the owner before use. Workflow text alone does not enforce reviewer settings. It generates candidate tar.gz and checksums but has no release creation, public object upload, ZIP/artifact-upload action, Git push or deployment step. No credentials or signing keys are included. Actual publication remains a separate explicit owner decision with domain/CDN configuration, immutable object retention, reviewed manifest promotion and independent validation.
Existing MIT text is preserved, not newly selected. LICENSE_PENDING.md records pending owner confirmation and Cargo publish is false. Required future gates: approve license, configure repository permissions/branch protection/private reporting/environments, run CI on Windows, independently verify release artifacts, configure signing verification, then approve hosting/publication. Public availability must remain staged until actual HTTPS objects and installation checks pass.
No trailing commas. Type parsing accepts forward shape names, validated after declarations. Reserved modern spellings include task/give/show/when/otherwise/repeat/in/fixed/shape/attempt/needs/and/or/not and builtin type names; gives is consumed as a result-type separator. Function parameter annotations are mandatory. Result defaults to unit; there is no unrestricted signature inference.
Declarations are hoisted. Top-level statements execute in order in a synthetic main task. Tasks do not capture script locals; pass values explicitly. If an explicit main task exists it must be zero-argument/unit and cannot be combined with script statements. A declarations-only file has an empty implicit entry. test_ tasks must be zero-argument/unit and are invoked independently without executing script statements.
Assignment introduces a mutable binding only if the name is unresolved; otherwise it updates the nearest lexical binding without changing its type. Annotated assignments and fixed declarations introduce a new binding in the current scope, rejecting current-scope duplicates and allowing outer-name shadowing. Parameters are local mutable values. Each conditional branch, loop iteration and attempt body/handler has a lexical scope. Loop variables and caught Error bindings are immutable. Names introduced in nested scopes do not leak. fixed prevents rebinding; values have clone/value semantics, not shared mutable collection references. Field/index assignment is unsupported; replace a whole value or use pure append/put.
Both when/otherwise paths must return for a non-unit task, or a later give must cover the remaining path. A loop alone cannot prove a required return. Attempt is returning only when both its body and handler return. Unreachable statements after a definitely returning statement are rejected.
Ranges a..b are ascending, end-exclusive; equal endpoints produce no iterations, descending ranges raise InvalidRange. Bounds must be i64. repeat also accepts a typed List and iterates a value snapshot. No break/continue/while exists.
int aliases i64; string aliases text. No implicit numeric/text conversions. Checked i64 +,-,*,/,%, unary minus; division truncates toward zero. Same-type equality/inequality on concrete nonunit values; ordering on i64; text + text. and/or short circuit; !/not require bool. Other binary operators evaluate left-to-right eagerly.
Lists are homogeneous List[T]; Maps are homogeneous Map[text,T] with deterministic sorted text keys. Empty literals require enough context: an explicit binding/parameter annotation, or append/put inference. A standalone empty inferred binding is rejected. Map literal keys are text literals and duplicate literal keys fail checking. Dynamic keys work through put and indexing. Indexes use nonnegative i64 for Lists/text; text indexing and len count Unicode scalars, not UTF-8 bytes or grapheme clusters. Bounds and missing keys produce typed runtime errors. Shapes are nominal, positional constructors use declared field order, and field reads are statically checked. No field mutation/methods/subtyping/destructuring.
Builtins: print(value)/show expression (nonunit output + LF), assert(bool), len(text|List|Map), text(i64|bool|text), append(List[T],T)->List[T], put(Map[text,T],text,T)->Map[text,T]. append/put return new values. Collection/shape printing is deterministic human-readable output, not a serialization format.
attempt/otherwise binds Error with readonly kind:text and message:text. Recoverable kinds: Overflow, DivisionByZero, Bounds, MissingKey, Assertion, InvalidRange. Side effects completed before an error persist; this is not transaction rollback. Fatal Fuel, Depth and internal failures propagate. Runtime API exposes RuntimeFault with kind/message/source token; CLI includes filename and source locations. Output is buffered per execution; an unhandled failure discards its output. Caught failures retain prior buffered output.
Only needs console is recognized; unknown/duplicate declarations fail. Declaration checks do not enforce capabilities or provide isolation; console output works without an explicit needs declaration for compatibility. No filesystem/network capability or sandbox is implemented.
Limits: 64 KiB source, 4096 tokens, 64 indent levels, 128 expression construction/parser depth, 128 call frames, 100,000 runtime fuel. Compiler/runtime workers use bounded 16 MiB stack reservations. These guards do not bound string/collection/output heap growth; untrusted-code sandboxing is not claimed. Modern parser synchronizes failed top-level parsing at newline and reports up to 16 diagnostics; lexical errors stop immediately. Recovery may include follow-on diagnostics in malformed nested blocks.
A file whose first significant declaration token is fn uses the legacy brace/semicolon parser; its expressions and AST feed the same checker/runtime. Exact v0.1 grammar remains in ../ZBL_LANGUAGE_SPEC_v0.1.md. Legacy files retain original reserved words and may use function names that became modern builtins. Modern and legacy statement syntaxes cannot be freely mixed in one file. Old sdk="0.1.0" project configurations remain accepted. zebvix is official; zbl is a same-implementation executable compatibility alias.
Header length is 28 bytes. After it are four u32-length-prefixed sections: constants, shapes, functions, code; each prefix excludes its own four bytes. Constant/function counts must equal header counts. Shape payload begins u32 shape_count. No optional sections exist while flags=0. Header total length includes all prefixes. Type tags: 0x00 unit, 0x01 i64, 0x02 bool, 0x03 text, 0x10 List followed by one type, 0x11 Map[text,T] followed by T, 0x12 Shape followed by u32 shape index, 0x13 Error. Type nesting max 64; Unknown and Range are never serialized.
Each shape: u32 name text-constant index, u16 field_count, repeated u32 field-name text-constant index and type. Field names must be unique. Function descriptor: u32 name index, u16 parameter_count, parameter types, result type, u16 local_count, local types (parameters occupy first local slots), u16 max_stack, u32 instruction_count, u32 code_offset, u32 code_length. Offsets are relative to code payload. Function byte regions must be disjoint and cover exactly the code payload in descriptor order. No padding. Branch targets are function-local instruction indices, not arbitrary bytes.
| Opcode | Operands | Stack effect |
|---|---|---|
| 01 CONST | u32 constant | -> value |
| 02 LOCAL_GET | u16 slot | -> local |
| 03 LOCAL_SET | u16 slot | value -> |
| 04 ADD_I64 | none | i64,i64 -> i64 |
| 05 SUB_I64 | none | i64,i64 -> i64 |
| 06 MUL_I64 | none | i64,i64 -> i64 |
| 07 DIV_I64 | none | i64,i64 -> i64 |
| 08 REM_I64 | none | i64,i64 -> i64 |
| 09 NEG_I64 | none | i64 -> i64 |
| 0A EQ | type | T,T -> bool (nonunit) |
| 0B CMP_I64 | u8 predicate: 0 lt,1 le,2 gt,3 ge | i64,i64 -> bool |
| 0C NOT_BOOL | none | bool -> bool |
| 0D CONCAT_TEXT | none | text,text -> text |
| 0E CALL | u32 function | params in declaration order -> result (unit is a value) |
| 0F RETURN | none | declared result -> caller |
| 10 PRINT | type | nonunit T -> unit |
| 11 LIST_NEW | type T,u32 count | count T -> List[T] |
| 12 MAP_NEW | type T,u32 count | count pairs text,T -> Map[text,T] |
| 13 INDEX | container type | List[T],i64 or Map[text,T],text or text,i64 -> T/text |
| 14 SHAPE_NEW | u32 shape | fields in declaration order -> shape |
| 15 FIELD_GET | u32 shape,u16 field | matching shape -> field |
| 16 JUMP | u32 instruction | unchanged |
| 17 JUMP_IF_FALSE | u32 instruction | bool -> |
| 18 TRY_BEGIN | u32 handler instruction | unchanged; record handler/base stack |
| 19 TRY_END | none | unchanged; remove current handler |
| 1A LEN | container type | text/List/Map -> i64 |
| 1B ASSERT | none | bool -> unit or Assertion |
| 1C TEXT | primitive source type | i64/bool/text -> text |
| 1D APPEND | type T | List[T],T -> List[T] |
| 1E PUT | type T | Map[text,T],text,T -> Map[text,T] |
| 1F ERROR_FIELD | u8 0 kind,1 message | Error -> text |
Stack order is bottom-to-top in table order; consume rightmost last-pushed operand first internally, while source operands are evaluated left-to-right before push. Local slots begin uninitialized except parameters. LOCAL_SET initializes; verifier forbids reads without initialization on every incoming path. Handlers restore TRY_BEGIN base stack and push one Error; only documented recoverable errors transfer, fatal limits bypass handlers. Handler state must match on CFG merges. RETURN requires exactly one result and balanced active handlers; compiler lowers early returns through TRY_END cleanup. Void calls still push unit, so unused results require a future explicit DROP opcode; reserve opcode 20 as DROP (one typed stack value -> empty). Unknown opcodes are errors.
Range loops lower to initialized i64 locals, CMP/JUMP and checked increments with end-exclusive semantics; empty and descending cases must match the AST interpreter. and/or lower to CFG short-circuit paths with equal stack states. Statement expression results lower through DROP. Limits proposed for loader/VM: artifact <=16 MiB, constants <=16384 / aggregate payload <=8 MiB, functions <=4096, locals/parameters/max stack <=256, instructions <=100000 per function, live heap/output quota <=16 MiB, 128 frames and 100000 fuel. All arithmetic in size/count checks uses checked host arithmetic. Exact quota accounting and malformed-binary/differential corpus must be implemented and tested before this proposal becomes an available executable format.