diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 3ec419f..147b43f 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -6,6 +6,7 @@ using Upsilon.BaseTypes; using Upsilon.BaseTypes.Number; using Upsilon.Binder.VariableSymbols; using Upsilon.BoundTypes; +using Upsilon.Evaluator; using Upsilon.Parser; using Type = Upsilon.BaseTypes.Type; @@ -15,21 +16,26 @@ namespace Upsilon.Binder { private Diagnostics _diagnostics; public BoundScope Scope { get; private set; } + private readonly Script _script; private Dictionary _unboundFunctions = new Dictionary(); - public Binder(Diagnostics diagnostics, Dictionary variables) + public Binder(Diagnostics diagnostics, Dictionary variables, Script script) { _diagnostics = diagnostics; + _script = script; Scope = new BoundScope(variables, null); } - private Binder(){} - - internal static Binder CreateWithSetScope(Diagnostics diagnostics, BoundScope scope) + private Binder(Script script) { - return new Binder {_diagnostics = diagnostics, Scope = scope}; + _script = script; + } + + internal static Binder CreateWithSetScope(Diagnostics diagnostics, BoundScope scope, Script script) + { + return new Binder(script) {_diagnostics = diagnostics, Scope = scope}; } public void Dispose() @@ -233,6 +239,24 @@ namespace Upsilon.Binder _unboundFunctions.Remove(scriptFunction.Name); } } + else + { + if (string.Equals(function.Name, "require") && parameters.Count > 0) + { + var parameter = parameters[0]; + if (parameter is BoundLiteralExpression be && be.Value.Type == Type.String) + { + var moduleName = be.Value.ToString(); + var module = _script.Options.ModuleHandler.GetModule(_script, moduleName); + foreach (var moduleVariable in module.Scope.Variables) + { + if (moduleVariable.Value.Local) + continue; + Scope.Variables.Add(moduleVariable.Key, moduleVariable.Value); + } + } + } + } returnType = function.ResultType; diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index 83be4b3..78c7593 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -31,7 +31,7 @@ namespace Upsilon.Evaluator var staticBoundScope = options.OverrideStaticBoundScope ?? StaticScope.BoundScope; var boundScope = BoundScope.WithReadOnlyScope(staticBoundScope); - Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, boundScope); + Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, boundScope, this); var staticScope = options.OverrideStaticScope ?? StaticScope.Scope; Scope = EvaluationScope.CreateWithGetOnlyParent(staticScope); @@ -45,7 +45,7 @@ namespace Upsilon.Evaluator _scriptString = scriptString; Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError); - Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, binder.Scope); + Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, binder.Scope, this); Evaluator = Evaluator.CreateWithSetScope(Diagnostics, evaluator.Scope, this); Scope = Evaluator.Scope; } @@ -56,7 +56,7 @@ namespace Upsilon.Evaluator _bound = boundScript; Diagnostics = new Diagnostics(ScriptString, options.ThrowExceptionOnError); - Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, binder.Scope); + Binder = Upsilon.Binder.Binder.CreateWithSetScope(Diagnostics, binder.Scope, this); Evaluator = Evaluator.CreateWithSetScope(Diagnostics, evaluator.Scope, this); Scope = Evaluator.Scope; } diff --git a/Upsilon/ModuleHandler.cs b/Upsilon/ModuleHandler.cs new file mode 100644 index 0000000..be6da39 --- /dev/null +++ b/Upsilon/ModuleHandler.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Upsilon.Binder; +using Upsilon.Evaluator; + +namespace Upsilon +{ + public class ModuleHandler + { + private readonly Dictionary _cachedModules = new Dictionary(); + + public virtual BoundScript GetModule(Script script, string name) + { + if (_cachedModules.TryGetValue(name, out var module)) + return module; + + var moduleScript = script.Options.ScriptLoader.LoadModule(name); + var parsed = Executor.ContinueWith(script, moduleScript); + module = parsed.Bind(); + _cachedModules.Add(name, module); + return module; + } + } +} \ No newline at end of file diff --git a/Upsilon/ScriptOptions.cs b/Upsilon/ScriptOptions.cs index fa9b05c..ab7ec83 100644 --- a/Upsilon/ScriptOptions.cs +++ b/Upsilon/ScriptOptions.cs @@ -20,6 +20,7 @@ namespace Upsilon public BoundScope OverrideStaticBoundScope { get; set; } = null; public EvaluationScope OverrideStaticScope { get; set; } = null; - public ScriptLoader ScriptLoader { get; set; } = null; + public ScriptLoader ScriptLoader { get; set; } = new ScriptLoader(); + public ModuleHandler ModuleHandler { get; set; } = new ModuleHandler(); } } \ No newline at end of file diff --git a/Upsilon/StandardLibraries/BasicFunctions.cs b/Upsilon/StandardLibraries/BasicFunctions.cs index 960dd2e..9c8c2a6 100644 --- a/Upsilon/StandardLibraries/BasicFunctions.cs +++ b/Upsilon/StandardLibraries/BasicFunctions.cs @@ -41,30 +41,15 @@ namespace Upsilon.StandardLibraries return new PairsScriptIterator(table); } - private static readonly Dictionary CachedBoundModules = new Dictionary(); - [StandardLibraryScriptFunction("require", "Loads a module from the module path, using the given script loader.", true)] public ScriptType Require(Script script, ScriptString fileName) { var file = fileName.Value; - var loader = script.Options.ScriptLoader; - if (loader != null) - { - if (!CachedBoundModules.TryGetValue(file, out var boundScript)) - { - var loadedScript = loader.LoadModule(file); - boundScript = Executor.ParseInput(loadedScript).Bind(); - CachedBoundModules.Add(file, boundScript); - } - var s = Executor.ContinueWith(script, boundScript); - var val = s.Evaluate(); - if (val != null) - { - return val.ToScriptType(); - } - } - return new ScriptNull(); + var module = script.Options.ModuleHandler.GetModule(script, file); + var s = Executor.ContinueWith(script, module); + var val = s.Evaluate(); + return val != null ? val.ToScriptType() : new ScriptNull(); }