v5 Semantics: import/export resolution
Work through examples, try the reasoning yourself, then put it into practice.
View SlidesBefore you start
- Build v5 module ASTs and retain declared-before-use/loop rules.
What you will practice
- Validate dependency order, aliases, and export visibility.
- Distinguish v5 name/module checking from v6 static typing.
- Predict diagnostic order at module and expression boundaries.
In this lesson
Lesson
3 min readv5 Semantics: import/export resolution
v5 checks module structure and names while retaining dynamic values. It has
no static parameter types, return types, or type inference. Examples containing
x:number or ->number belong to v6 and cannot serve as valid v5 test inputs.
Worked reconstruction
module util {
export fn id(x){ return x; }
fn hidden(){ return 7; }
}
module main {
import util as u;
let a=u.id(3);
let b=u.hidden();
}
Build the module-name index: util→0, main→1. Gather util's exported name id. In main, import util is valid because 0<1 and binds alias u. For u.id, resolve u→util then check id in util's export set. u.hidden fails with unknown export even though hidden has a valid internal declaration. No numeric type property of id's argument has been established.
Order and first failure
Unique module names and main-last are checked as module-level constraints. Imports must refer to earlier modules: distinguish unknown module from known future module. Then analyze statements in source order using per-module scopes. A capstone returns the first diagnostic produced, so moving main before util can produce main-last before the future-import message. Do not promise a later specific message without considering earlier structural errors.
Imported aliases occupy the module scope and must not collide. Member access
requires an identifier naming a known module alias and an exported member.
An expression with a non-identifier base, such as (1+2).x, is invalid module
access. Ordinary local declarations still obey source order, const rules, and
function/loop context.
What remains dynamic
Direct identifier calls to a known local function declaration permit arity checking. An imported-member call in this v5 implementation is checked for module/member visibility, but exported function argument types and even its arity are not propagated as static contracts. The VM checks actual closure callability and arity. v6 deliberately adds that information. Avoid changing v5 examples into typed syntax to make the analyzer appear stronger than it is.
Debugging lab
A lesson predicts a static number/bool error for u.id(true) in v5, and a test places main before util while demanding only unknown-export. What unstated assumptions caused both errors?
Compare your diagnosis after attempting the lab
v5 has no static argument types, so id may accept a boolean and return it. A misordered main triggers a module-order error before the later member check. Isolate the intended failure and use syntax valid for this version.
Transfer task
Construct three otherwise valid programs that separately fail for unknown import, future import with main still last, and missing export. Record the earliest diagnostic and identify which table lookup produces it.
Carry forward
Carry an accepted module graph into CompileModules. Acceptance proves the stated name/order rules, not type correctness or runtime success.
Build semantic-analysis-v5. Keep a before/after trace of one failing test. Use the checkpoint to diagnose specific skills; passing it does not replace implementing and testing the artifact.
Practice sequence
Use the order below for a guided path, or choose an item to revisit. A pass records a successful attempt; try a fresh example later to check what you can reconstruct.