Regions Overview
What are regions?
A .tape file can contain multiple regions, each with its own parser and purpose. The region splitter divides the file at #region markers, then each region is processed separately.
#code
import ui from "ui";
import widgets from "widgets";
var count: i64 = 0;
fn increment() { count = count + 1; }
#view
component Counter {
view {
widgets.Label { text: "{count}"; }
widgets.Button { label: "+"; on_click: increment; }
}
}
#test
test "increment works" {
count = 0;
increment();
@assert(count == 1);
}Available regions
| Region | Purpose | Status |
|---|---|---|
#code | Standard tape logic (default) | Implemented |
#view | Component declarations | Implemented |
#test | Inline test cases | Implemented |
#style | Component styling: props set by rule | Implemented |
#shader | Vertex, pixel and compute shaders in tape, for the gpu module | Implemented (Metal on macOS, OpenGL 4.3 on Windows and Linux) |
#bytecode | x86-64 instructions in functions (t0, native) | Implemented |
#localization | Translatable strings for @t("...") | Implemented |
#resource | Embedded assets | Planned (splitter recognizes, not processed) |
Default region
If no region marker appears, the entire file is #code. Most programs don’t need explicit region markers.
Region ordering
Regions must appear in a fixed order. The splitter rejects out-of-order or duplicate regions:
#code → #view → #style → #shader → #localization → #resource → #test → #bytecodeNot all regions need to be present — only the ordering of those that appear is enforced.
Preamble
Content before the first explicit region marker (if any) is treated as preamble and prepended to #code. This allows imports and declarations at the top of a multi-region file to be visible in #code:
import io from "io";
import str from "str";
#code
fn greet(name: string) { io.println("hello " + name); }
#view
component App { ... }How each region is processed
#code
Parsed by the standard tape parser. Produces the module AST (functions, structs, enums, components, constants, imports).
#view
Parsed by tape_parse_view — a component-focused parser. Components declared in #view are merged into the module’s component list alongside any components in #code.
#test
Parsed by tape_parse_tests. Each test "name" { ... } block becomes a function. The test region supports:
test "description" { ... }— test cases, and table-driven ones (with [...] as (...))setup { ... }/teardown { ... }— run before / after each test@assert,@assert_err,@assert_trap,@failand@skip, and@error_of(expr), an expression’s error as a?E- helper
fns,consts, module variables (var/let) and fixture types, compiled only fortape test
See #test.
Tests are compiled and run via tape test <file>.
#style
Rules that set component props by component name, nested for the instances inside another component, with constants and other modules’ styles imported as "module#style". The compiler checks every rule against the props’ types and compiles a styled prop as if it were written at the instantiation. See #style.
#shader
Vertex, pixel and compute shaders written in tape: each stage is checked
with the program and compiled to the GPU’s languages (GLSL, Metal) when
the program is, and is a gpu.Shader value in tape code that the
gpu module makes pipelines from. See
#shader.
#localization
Translations of the strings marked with @t("...") in #code and #view,
checked at compile time and built into the program; the
locale module chooses the language. See
#localization.
#bytecode
Functions whose bodies are x86-64 instructions, for t0 kernel code (port I/O, control registers, descriptor tables). Native only. See #bytecode.
#resource
Cross-region references
#viewcomponents can reference functions and variables from#code#testcan call functions from#codeand instantiate#viewcomponents#codecan define and use components directly (no#viewrequired)
Last modified: