refactor() Blocks
What is a refactor block?
A refactor("path") { ... } block declares a virtual module boundary inside your file. The compiler treats the code inside as if it already lives in a separate module — validating imports, exports, and cross-references on every build.
import io from "io";
import math from "math";
fn main() {
io.println("{distance(3.0, 4.0)}");
}
refactor("./geom.tape") {
fn distance(x: f64, y: f64) -> f64 {
return math.sqrt(x*x + y*y);
}
}The program compiles and runs normally. But the compiler enforces that distance could live in ./geom.tape — if it references something it shouldn’t, you get an error immediately.
Syntax
refactor("./target_path.tape") {
// declarations that will become the new module
}- The path string follows the same rules as import paths (relative or bare)
- Only declarations are allowed inside (fn, var, let, const, struct, enum, tagged, component)
- Only valid at module top level in
#coderegion - Multiple blocks with the same path are combined into one virtual module
- Multiple blocks with different paths create separate virtual modules
- Nested refactor blocks are not allowed
What the compiler checks
On every tape build, tape run, or tape check:
- Separate scope — declarations inside the block are in their own module scope
- Import analysis — the compiler determines which of the host’s imports the refactored code actually uses
- Export analysis — the compiler determines which symbols from the block are referenced by the remaining host code
- Cross-reference validation — if code inside references a host-local symbol that isn’t available via imports, it’s a compile error
error[E042]: refactor block references `helper` which is not included
--> app.tape:15:9
|
15 | helper();
| ^^^^^^ not available in virtual module "./utils.tape"
|
= help: move `helper` into this refactor block, or extract it to a
shared module that both can importCross-block dependencies
When one refactor block references symbols from another, the compiler resolves this automatically:
refactor("./veclib.tape") {
struct Vec3 { x: f64; y: f64; z: f64; }
fn make_vec(x: f64, y: f64, z: f64) -> Vec3 {
return Vec3 { x: x; y: y; z: z; };
}
}
refactor("./display.tape") {
fn print_vec(v: Vec3) {
io.println("{v.x}, {v.y}, {v.z}");
}
}The compiler knows display needs Vec3 from veclib and validates there’s no circular dependency.
Materialization
When you’re satisfied the split is clean, run tape refactor to write the actual files. See tape refactor CLI docs for the command reference.
Rules summary
| Rule | Behavior |
|---|---|
| Normal compilation | Block is transparent — program runs identically |
| Scope | Declarations are in their own virtual module scope |
| Host access to block symbols | Auto-synthesized selective import |
| Block access to host imports | Only imports actually used are available |
| Block access to host locals | Compile error |
@profile | Inherited from host file |
| Multiple blocks, same path | Combined into one virtual module |
| Circular dependencies between blocks | Compile error |
Last modified: