Summary
load module from "..." loads and runs another file at runtime, but the static analyzer does not register the symbols that module defines. As a result, referencing an action (or container) defined in a loaded module fails semantic analysis with a fatal Variable '<name>' is not defined, and the program never runs (exit 3) — even though the call would succeed at runtime.
Minimal reproduction
lib_mod.wfl:
define action called mod_double with parameters n:
return n plus n
end action
main_mod.wfl:
load module from "lib_mod.wfl"
display mod_double of 5
Run wfl main_mod.wfl:
error[ANALYZE-SEMANTIC]: Variable 'mod_double' is not defined
(exit code 3; the program does not execute.)
Loading a module that only defines/assigns top-level variables and uses them itself works fine — the problem is specifically sharing actions/containers across files, because the analyzer can't see them.
Root cause
In src/analyzer/mod.rs, Statement::LoadModuleStatement only analyzes the path expression; it does not parse the referenced module and register its declarations in the current scope:
Statement::LoadModuleStatement { path, .. } => {
self.analyze_expression(path);
}
Impact
It's effectively impossible to split a WFL program into a shared library file plus caller files when the library exposes actions — the standard way to organize a larger codebase. My workaround for a multi-file WFL project was to keep the whole library in one file and concatenate it with each caller via a build step, which defeats the purpose of load module.
Environment
wfl built from source at current main
- rustc 1.94.1, cargo 1.94.1, Linux
Suggested fix
When analyzing LoadModuleStatement, resolve and parse the referenced module (as the interpreter does) and register its top-level action/container/variable declarations into the analyzer scope, so callers pass semantic analysis. Circular includes would need the same guard the runtime already uses.
Summary
load module from "..."loads and runs another file at runtime, but the static analyzer does not register the symbols that module defines. As a result, referencing an action (or container) defined in a loaded module fails semantic analysis with a fatalVariable '<name>' is not defined, and the program never runs (exit 3) — even though the call would succeed at runtime.Minimal reproduction
lib_mod.wfl:main_mod.wfl:Run
wfl main_mod.wfl:(exit code 3; the program does not execute.)
Loading a module that only defines/assigns top-level variables and uses them itself works fine — the problem is specifically sharing actions/containers across files, because the analyzer can't see them.
Root cause
In
src/analyzer/mod.rs,Statement::LoadModuleStatementonly analyzes the path expression; it does not parse the referenced module and register its declarations in the current scope:Impact
It's effectively impossible to split a WFL program into a shared library file plus caller files when the library exposes actions — the standard way to organize a larger codebase. My workaround for a multi-file WFL project was to keep the whole library in one file and concatenate it with each caller via a build step, which defeats the purpose of
load module.Environment
wflbuilt from source at currentmainSuggested fix
When analyzing
LoadModuleStatement, resolve and parse the referenced module (as the interpreter does) and register its top-level action/container/variable declarations into the analyzer scope, so callers pass semantic analysis. Circular includes would need the same guard the runtime already uses.