diff --git a/Colibri.Core/Macros/CoreMacros.cs b/Colibri.Core/Macros/CoreMacros.cs index f10f0dc..75780c6 100644 --- a/Colibri.Core/Macros/CoreMacros.cs +++ b/Colibri.Core/Macros/CoreMacros.cs @@ -731,9 +731,21 @@ public static object DelayForce(ColibriRuntime runtime, Scope scope, object?[] a public static object? Eval(ColibriRuntime runtime, Scope scope, object?[] args) { - if (args.Length != 1) + switch (args.Length) { - throw new ArgumentException("eval requires one argument"); + case 0 or > 2: + throw new ArgumentException("eval requires one or two arguments"); + case 2: + { + if (runtime.Evaluate(scope, args[1]) is not Scope argScope) + { + // ReSharper disable once StringLiteralTypo + throw new ArgumentException("eval's second argument must be a scope"); + } + + scope = argScope; + break; + } } return runtime.Evaluate(scope, runtime.Evaluate(scope, args[0])); diff --git a/Colibri.Core/Macros/EnvironmentMacros.cs b/Colibri.Core/Macros/EnvironmentMacros.cs new file mode 100644 index 0000000..e248bff --- /dev/null +++ b/Colibri.Core/Macros/EnvironmentMacros.cs @@ -0,0 +1,7 @@ +namespace Colibri.Core.Macros; + +public static class EnvironmentMacros +{ + public static object InteractionEnvironment(ColibriRuntime runtime, Scope scope, object?[] args) + => runtime.UserScope; +} \ No newline at end of file diff --git a/Colibri.Core/StandardLibraries.cs b/Colibri.Core/StandardLibraries.cs index 41012d3..55095c3 100644 --- a/Colibri.Core/StandardLibraries.cs +++ b/Colibri.Core/StandardLibraries.cs @@ -24,7 +24,7 @@ static StandardLibraries() // TODO: (scheme load) library (new LibraryName("scheme", "process-context"), ProcessContext), (new LibraryName("scheme", "read"), Read), - // TODO: (scheme repl) library + (new LibraryName("scheme", "repl"), Repl), (new LibraryName("scheme", "time"), Time), (new LibraryName("scheme", "write"), Write), // TODO: (scheme r5rs) library @@ -437,8 +437,11 @@ static StandardLibraries() { ["read"] = (MacroExpression)PortMacros.Read, }); - - // TODO: (scheme repl) library + + public static readonly Library Repl = new(new Dictionary + { + ["interaction-environment"] = (MacroExpression)EnvironmentMacros.InteractionEnvironment, + }); public static readonly Library Time = new(new Dictionary { diff --git a/Colibri.Tests/EnvironmentTests.cs b/Colibri.Tests/EnvironmentTests.cs new file mode 100644 index 0000000..e8ea9b1 --- /dev/null +++ b/Colibri.Tests/EnvironmentTests.cs @@ -0,0 +1,25 @@ +using Colibri.Core; + +namespace Colibri.Tests; + +public class EnvironmentTests +{ + [Fact] + public void InteractionEnvironmentTest() + { + const string program = @" +define x 42 +eval 'x (interaction-environment) +"; + + var runtime = new ColibriRuntime(); + + var result = runtime.EvaluateProgram(program); + + Assert.Equal(42, result); + + var env = runtime.EvaluateProgram("(interaction-environment)"); + + Assert.Same(env, runtime.UserScope); + } +} \ No newline at end of file