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.

tape
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

tape
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 #code region
  • 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:

  1. Separate scope — declarations inside the block are in their own module scope
  2. Import analysis — the compiler determines which of the host’s imports the refactored code actually uses
  3. Export analysis — the compiler determines which symbols from the block are referenced by the remaining host code
  4. Cross-reference validation — if code inside references a host-local symbol that isn’t available via imports, it’s a compile error
plaintext
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 import

Cross-block dependencies

When one refactor block references symbols from another, the compiler resolves this automatically:

tape
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

RuleBehavior
Normal compilationBlock is transparent — program runs identically
ScopeDeclarations are in their own virtual module scope
Host access to block symbolsAuto-synthesized selective import
Block access to host importsOnly imports actually used are available
Block access to host localsCompile error
@profileInherited from host file
Multiple blocks, same pathCombined into one virtual module
Circular dependencies between blocksCompile error

Last modified: