Expand description
Super-global environment — the bottom of the scope chain.
This environment sits below the global scope and lazily resolves built-in and plugin-provided objects on first access. Objects are cached after first resolution so each name is materialized at most once.
§How It Works
When JavaScript code references a name that isn’t found in the lexical environment chain or global scope, the super-global environment is consulted:
JavaScript: Math.abs(-5)
↓
1. Check local scope → not found
2. Check outer scopes → not found
3. Check global scope → not found
4. Check super-global → "Math" found!
↓
5. Query resolvers: Does anyone provide "Math"?
6. CorePluginResolver says "yes"
7. Cache the result
8. Dispatch Math.abs() via resolver§Caching Strategy
- First lookup: Query all resolvers in order, cache which one owns the name
- Subsequent lookups: Use cached resolver index directly
- Method calls: Can bypass object materialization entirely
§Example
use just::runner::plugin::super_global::SuperGlobalEnvironment;
use just::runner::plugin::resolver::PluginResolver;
use just::runner::plugin::types::EvalContext;
use just::runner::ds::value::{JsValue, JsNumberType};
use just::runner::ds::error::JErrorType;
struct MyPlugin;
impl PluginResolver for MyPlugin {
fn has_binding(&self, name: &str) -> bool {
name == "MyObject"
}
fn resolve(&self, _name: &str, _ctx: &mut EvalContext) -> Result<JsValue, JErrorType> {
Ok(JsValue::Number(JsNumberType::Integer(42)))
}
fn call_method(&self, _obj: &str, _method: &str, _ctx: &mut EvalContext,
_this: JsValue, _args: Vec<JsValue>) -> Option<Result<JsValue, JErrorType>> {
None
}
fn name(&self) -> &str { "my_plugin" }
}
let mut sg = SuperGlobalEnvironment::new();
sg.add_resolver(Box::new(MyPlugin));
// Now "MyObject" is available in the super-global scopeStructs§
- Super
Global Environment - The super-global environment for lazy resolution of built-in objects.