diff --git a/Ergo/Facade/ErgoFacade.cs b/Ergo/Facade/ErgoFacade.cs index 58970ca2..e55a769c 100644 --- a/Ergo/Facade/ErgoFacade.cs +++ b/Ergo/Facade/ErgoFacade.cs @@ -28,15 +28,30 @@ public readonly struct ErgoFacade .AddLibrariesByReflection(typeof(Library).Assembly) .AddCommandsByReflection(typeof(Save).Assembly) .AddParsersByReflection(typeof(DictParser).Assembly) + .AfterKnowledgeBaseCompile(kb => + { + kb.Trim(); + }) ; private readonly ImmutableHashSet> _libraries = ImmutableHashSet>.Empty; private readonly ImmutableHashSet _commands = ImmutableHashSet.Empty; private readonly ImmutableDictionary _parsers = ImmutableDictionary.Empty; + + public readonly Func ConfigureStdlibScopeHandler = s => s; + public readonly Func ConfigureInterpreterScopeHandler = (i, s) => s; + public readonly Action BeforeKbCompiledHandler = k => { }; + public readonly Action AfterKbCompiledHandler; + + public readonly bool TrimKnowledgeBase; + public readonly Maybe Input = default; public readonly Maybe Output = default; public readonly Maybe Error = default; public readonly Maybe InputReader = default; + public readonly InterpreterFlags InterpreterFlags = InterpreterFlags.Default; + public readonly CompilerFlags CompilerFlags = CompilerFlags.Default; + public readonly DecimalType DecimalType = DecimalType.CliDecimal; public ErgoFacade() { } @@ -47,31 +62,65 @@ private ErgoFacade( Maybe inStream, Maybe outStream, Maybe errStream, - Maybe inReader + Maybe inReader, + Func configureStdlibScope, + Func configureInterpreterScope, + Action beforeKbCompiled, + Action afterKbCompiled, + InterpreterFlags interpreterFlags, + CompilerFlags compilerFlags, + DecimalType decimalType, + bool trimKnowledgeBase ) { _libraries = libs; _commands = commands; _parsers = parsers; + ConfigureStdlibScopeHandler = configureStdlibScope; + ConfigureInterpreterScopeHandler = configureInterpreterScope; + BeforeKbCompiledHandler = beforeKbCompiled; + AfterKbCompiledHandler = afterKbCompiled; + InterpreterFlags = interpreterFlags; + CompilerFlags = compilerFlags; + DecimalType = decimalType; + TrimKnowledgeBase = trimKnowledgeBase; Input = inStream; Output = outStream; Error = errStream; InputReader = inReader; + AfterKbCompiledHandler = kb => + { + if (trimKnowledgeBase) + kb.Trim(); + }; } public ErgoFacade AddLibrary(Func lib) - => new(_libraries.Add(lib), _commands, _parsers, Input, Output, Error, InputReader); + => new(_libraries.Add(lib), _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); public ErgoFacade AddCommand(ShellCommand command) - => new(_libraries, _commands.Add(command), _parsers, Input, Output, Error, InputReader); + => new(_libraries, _commands.Add(command), _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); public ErgoFacade RemoveCommand(ShellCommand command) - => new(_libraries, _commands.Remove(command), _parsers, Input, Output, Error, InputReader); + => new(_libraries, _commands.Remove(command), _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); public ErgoFacade AddAbstractParser(IAbstractTermParser parser) where A : AbstractTerm - => new(_libraries, _commands, _parsers.SetItem(typeof(A), parser), Input, Output, Error, InputReader); + => new(_libraries, _commands, _parsers.SetItem(typeof(A), parser), Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); public ErgoFacade RemoveAbstractParser() where A : AbstractTerm - => new(_libraries, _commands, _parsers.Remove(typeof(A)), Input, Output, Error, InputReader); - public ErgoFacade SetInput(TextReader input, Maybe reader = default) => new(_libraries, _commands, _parsers, input, Output, Error, reader); - public ErgoFacade SetOutput(TextWriter output) => new(_libraries, _commands, _parsers, Input, output, Error, InputReader); - public ErgoFacade SetError(TextWriter err) => new(_libraries, _commands, _parsers, Input, Output, err, InputReader); + => new(_libraries, _commands, _parsers.Remove(typeof(A)), Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade SetInput(TextReader input, Maybe reader = default) => new(_libraries, _commands, _parsers, input, Output, Error, reader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade SetOutput(TextWriter output) => new(_libraries, _commands, _parsers, Input, output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade SetError(TextWriter err) => new(_libraries, _commands, _parsers, Input, Output, err, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade ConfigureStdlibScope(Func f) => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, f, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade ConfigureInterpreterScope(Func f) => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, f, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade BeforeKnowledgeBaseCompile(Action a) => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, a, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade AfterKnowledgeBaseCompile(Action a) => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, a, InterpreterFlags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade SetInterpreterFlags(InterpreterFlags flags) + => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, flags, CompilerFlags, DecimalType, TrimKnowledgeBase); + public ErgoFacade SetCompilerFlags(CompilerFlags flags) + => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, flags, DecimalType, TrimKnowledgeBase); + public ErgoFacade SetDecimalType(DecimalType type) + => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, type, TrimKnowledgeBase); + public ErgoFacade SetTrimKnowledgeBase(bool trimKnowledgeBase) + => new(_libraries, _commands, _parsers, Input, Output, Error, InputReader, ConfigureStdlibScopeHandler, ConfigureInterpreterScopeHandler, BeforeKbCompiledHandler, AfterKbCompiledHandler, InterpreterFlags, CompilerFlags, DecimalType, trimKnowledgeBase); + /// /// Adds all libraries with a public parameterless constructor in the target assembly. /// @@ -158,26 +207,15 @@ private ErgoParser ConfigureParser(ErgoParser parser) } public ErgoParser BuildParser(ErgoStream stream, IEnumerable operators = null) - => ConfigureParser(new(this, new(this, stream, operators ?? Enumerable.Empty()))); - public ErgoInterpreter BuildInterpreter(InterpreterFlags flags = InterpreterFlags.Default) - => ConfigureInterpreter(new(this, flags)); - public ErgoVM BuildVM(KnowledgeBase kb, DecimalType decimalType = DecimalType.BigDecimal) - => ConfigureVM(new(kb, decimalType)); - public ErgoVM BuildVM( - InterpreterFlags interpreterFlags = InterpreterFlags.Default, - CompilerFlags vmFlags = CompilerFlags.Default, - DecimalType decimalType = DecimalType.BigDecimal, - Func configureStdlibScope = null, - Func configureScope = null, - Action beforeKbCompile = null, - Action afterKbCompile = null, - bool trimKb = false - ) { - var interpreter = BuildInterpreter(interpreterFlags); - var scope = interpreter.CreateScope(configureStdlibScope); - if (configureScope != null) - scope = configureScope(interpreter, scope); - var kb = scope.BuildKnowledgeBase(vmFlags, beforeKbCompile, afterKbCompile, trimKb); + => ConfigureParser(new(this, new(this, stream, operators ?? []))); + public ErgoInterpreter BuildInterpreter() + => ConfigureInterpreter(new(this)); + public ErgoVM BuildVM(KnowledgeBase kb) + => ConfigureVM(new(kb)); + public ErgoVM BuildVM() { + var interpreter = BuildInterpreter(); + var scope = interpreter.CreateScope(); + var kb = scope.BuildKnowledgeBase(); return BuildVM(kb); } public ErgoShell BuildShell(Func formatter = null, Encoding encoding = null) diff --git a/Ergo/Interpreter/ErgoInterpreter.cs b/Ergo/Interpreter/ErgoInterpreter.cs index 71145197..1b03aa6c 100644 --- a/Ergo/Interpreter/ErgoInterpreter.cs +++ b/Ergo/Interpreter/ErgoInterpreter.cs @@ -11,8 +11,8 @@ namespace Ergo.Interpreter; public partial class ErgoInterpreter { public readonly ErgoFacade Facade; - public readonly InterpreterFlags Flags; - private readonly Dictionary ModuleCache = new(); + public InterpreterFlags Flags => Facade.InterpreterFlags; + private readonly Dictionary ModuleCache = []; protected readonly DiagnosticProbe Probe = new() { @@ -24,9 +24,8 @@ public partial class ErgoInterpreter private readonly Dictionary _libraries = new(); public Maybe GetLibrary(Atom module) => _libraries.TryGetValue(module, out var lib) ? Maybe.Some(lib) : default; - internal ErgoInterpreter(ErgoFacade facade, InterpreterFlags flags = InterpreterFlags.Default) + internal ErgoInterpreter(ErgoFacade facade) { - Flags = flags; Facade = facade; } @@ -240,11 +239,10 @@ public virtual Maybe Load(ref InterpreterScope scope, Atom moduleName, E return module; } - public InterpreterScope CreateScope(Func configureStdlibScope = null) + public InterpreterScope CreateScope() { - configureStdlibScope ??= s => s; var stdlibScope = new InterpreterScope(Facade, new Module(WellKnown.Modules.Stdlib, runtime: true)); - stdlibScope = configureStdlibScope(stdlibScope); + stdlibScope = Facade.ConfigureStdlibScopeHandler(stdlibScope); Load(ref stdlibScope, WellKnown.Modules.Stdlib); var scope = stdlibScope .WithRuntime(false) @@ -254,6 +252,6 @@ public InterpreterScope CreateScope(Func con #if ERGO_INTERPRETER_DIAGNOSTICS Console.WriteLine(Probe.GetDiagnostics()); #endif - return scope; + return Facade.ConfigureInterpreterScopeHandler(this, scope); } } diff --git a/Ergo/Interpreter/InterpreterScope.cs b/Ergo/Interpreter/InterpreterScope.cs index 40b1a38e..9addbc61 100644 --- a/Ergo/Interpreter/InterpreterScope.cs +++ b/Ergo/Interpreter/InterpreterScope.cs @@ -93,12 +93,7 @@ private InterpreterScope( VisibleOperators = GetOperators().ToImmutableArray(); } - public KnowledgeBase BuildKnowledgeBase( - CompilerFlags vmFlags = CompilerFlags.Default, - Action beforeCompile = null, - Action afterCompile = null, - bool trim = false - ) { + public KnowledgeBase BuildKnowledgeBase() { var kb = new KnowledgeBase(this); foreach (var builtIn in VisibleBuiltIns.Values) { @@ -120,11 +115,9 @@ public KnowledgeBase BuildKnowledgeBase( kb.AssertZ(newPred); } } - beforeCompile?.Invoke(kb); - ForwardEventToLibraries(new KnowledgeBaseCreatedEvent(kb, vmFlags)); - afterCompile?.Invoke(kb); - if (trim) - kb.Trim(); + Facade.BeforeKbCompiledHandler(kb); + ForwardEventToLibraries(new KnowledgeBaseCreatedEvent(kb, Facade.CompilerFlags)); + Facade.AfterKbCompiledHandler(kb); return kb; } diff --git a/Ergo/Runtime/ErgoVM.cs b/Ergo/Runtime/ErgoVM.cs index 40745614..9bfbcd42 100644 --- a/Ergo/Runtime/ErgoVM.cs +++ b/Ergo/Runtime/ErgoVM.cs @@ -78,11 +78,11 @@ public partial class ErgoVM /// Register for the current continuation. /// internal Op @continue; - public ErgoVM(KnowledgeBase kb, DecimalType decimalType = DecimalType.CliDecimal) + public ErgoVM(KnowledgeBase kb) { args = new ITerm[MAX_ARGUMENTS]; KB = kb; - DecimalType = decimalType; + DecimalType = kb.Scope.Facade.DecimalType; In = Console.In; Out = Console.Out; Err = Console.Error; @@ -143,7 +143,7 @@ public Op Query /// /// Creates a new ErgoVM instance that shares the same knowledge base as the current one. /// - public ErgoVM ScopedInstance() => new(KB, DecimalType) + public ErgoVM ScopedInstance() => new(KB) { In = In, Err = Err, Out = Out, /*args = [.. args], Arity = Arity*/ }; /// /// Executes and backtracks until all solutions are computed. See also and . diff --git a/Ergo/Shell/Shell.cs b/Ergo/Shell/Shell.cs index efe45f8b..b37a403f 100644 --- a/Ergo/Shell/Shell.cs +++ b/Ergo/Shell/Shell.cs @@ -35,9 +35,8 @@ public ShellScope CreateScope(Maybe interpreterScope, Func { - var newKb = interpreterScope.BuildKnowledgeBase(copy.CompilerFlags); + var newKb = interpreterScope.BuildKnowledgeBase(); copy = copy .WithInterpreterScope(interpreterScope) .WithKnowledgeBase(newKb) diff --git a/XUnitTests/_Shared/SolverTestFixture.cs b/XUnitTests/_Shared/SolverTestFixture.cs index d03591dc..56f38bee 100644 --- a/XUnitTests/_Shared/SolverTestFixture.cs +++ b/XUnitTests/_Shared/SolverTestFixture.cs @@ -11,11 +11,13 @@ namespace Tests; public class CompilerTestFixture : ErgoTestFixture { protected override string TestsModuleName => "inlining"; - protected override CompilerFlags CompilerFlags => base.CompilerFlags - | CompilerFlags.EnableInlining; - protected override bool TrimKnowledgeBase => false; + + protected override ErgoFacade Facade => base.Facade + .SetTrimKnowledgeBase(false) + .SetCompilerFlags(base.Facade.CompilerFlags | CompilerFlags.EnableInlining); } + public class ErgoTestFixture : IDisposable { public readonly ExceptionHandler NullExceptionHandler = default; @@ -26,51 +28,38 @@ public class ErgoTestFixture : IDisposable public readonly ErgoVM VM; protected virtual string TestsModuleName => "tests"; - protected virtual InterpreterFlags InterpreterFlags => InterpreterFlags.Default; - protected virtual CompilerFlags CompilerFlags => CompilerFlags.Default; - protected virtual DecimalType DecimalType => DecimalType.BigDecimal; - protected virtual bool TrimKnowledgeBase => true; + + protected virtual ErgoFacade Facade { get; private set; } public ErgoTestFixture() { var basePath = Directory.GetCurrentDirectory(); var testsPath = Path.Combine(basePath, @"..\..\..\ergo"); - Interpreter = CreateInterpreter(); - InterpreterScope = CreateScope(testsPath); - LoadTestsModule(ref InterpreterScope); - KnowledgeBase = InterpreterScope.BuildKnowledgeBase(CompilerFlags); - if(TrimKnowledgeBase) - KnowledgeBase.Trim(); - VM = CreateVM(); - } - - protected virtual ErgoVM CreateVM() - { - return Interpreter.Facade.BuildVM(KnowledgeBase, DecimalType.BigDecimal); - } - - protected virtual ErgoInterpreter CreateInterpreter() - { - return ErgoFacade.Standard - .BuildInterpreter(InterpreterFlags); - } - - protected virtual InterpreterScope CreateScope(string testsPath) - { - return Interpreter.CreateScope(x => x - .WithExceptionHandler(ThrowingExceptionHandler) - .WithoutSearchDirectories() - .WithSearchDirectory(testsPath)) - .WithRuntime(true); - } - - protected virtual void LoadTestsModule(ref InterpreterScope scope) - { - var module = Interpreter - .Load(ref scope, new(TestsModuleName)) - .GetOrThrow(new InvalidOperationException()); - scope = scope.WithModule(scope.EntryModule.WithImport(module.Name)); + Facade = ErgoFacade.Standard + .SetDecimalType(DecimalType.BigDecimal) + .ConfigureStdlibScope(scope => + { + scope = scope + .WithExceptionHandler(ThrowingExceptionHandler) + .WithoutSearchDirectories() + .WithSearchDirectory(testsPath); + return ErgoFacade.Standard.ConfigureStdlibScopeHandler(scope); + }) + .ConfigureInterpreterScope((interpreter, scope) => + { + var module = interpreter + .Load(ref scope, new(TestsModuleName)) + .GetOrThrow(new InvalidOperationException()); + scope = scope.WithModule(scope.EntryModule.WithImport(module.Name)); + scope = scope.WithRuntime(true); + return ErgoFacade.Standard.ConfigureInterpreterScopeHandler(interpreter, scope); + }) + ; + Interpreter = Facade.BuildInterpreter(); + InterpreterScope = Interpreter.CreateScope(); + KnowledgeBase = InterpreterScope.BuildKnowledgeBase(); + VM = Facade.BuildVM(); } ~ErgoTestFixture()