Skip to content

Commit

Permalink
Load: Add load function
Browse files Browse the repository at this point in the history
This is similar to `include`, but supports specifying an environment.

Also adds `current-environment` and `mutable-environment` methods to
(colibri base) for assistance in testing this feature, as well as a
lexer bug is fixed in the REPL.
  • Loading branch information
paulirwin committed Aug 24, 2023
1 parent fdb9959 commit 1e70ff4
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 16 deletions.
49 changes: 39 additions & 10 deletions Colibri.Core/Macros/CoreMacros.cs
Original file line number Diff line number Diff line change
Expand Up @@ -714,19 +714,22 @@ public static object DelayForce(ColibriRuntime runtime, Scope scope, object?[] a

foreach (var arg in args)
{
var fileName = arg?.ToString();

if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentException("File name given to include cannot be null or empty");
}
result = IncludeFileInternal(runtime, scope, arg);
}

var fileText = File.ReadAllText(fileName);
return result;
}

result = runtime.EvaluateProgram(scope, fileText);
private static object? IncludeFileInternal(ColibriRuntime runtime, Scope scope, object? arg)
{
if (runtime.Evaluate(scope, arg) is not string fileName || string.IsNullOrEmpty(fileName))
{
throw new ArgumentException("File name given to include cannot be null or empty");
}

return result;
var fileText = File.ReadAllText(fileName);

return runtime.EvaluateProgram(scope, fileText);
}

public static object? Eval(ColibriRuntime runtime, Scope scope, object?[] args)
Expand Down Expand Up @@ -1242,7 +1245,7 @@ public static object VectorMap(ColibriRuntime runtime, Scope scope, object?[] ar
return result;
}

public static object? Import(ColibriRuntime runtime, Scope scope, object?[] args)
public static object Import(ColibriRuntime runtime, Scope scope, object?[] args)
{
if (args.Length == 0)
{
Expand Down Expand Up @@ -1309,4 +1312,30 @@ private static bool RecursivelyParseCondExpandFeatureRequirement(Scope scope, ob
_ => throw new ArgumentException($"Unexpected cond-expand clause feature identifier: {pairCar}")
};
}

public static object? Load(ColibriRuntime runtime, Scope scope, object?[] args)
{
if (args.Length is 0 or > 2)
{
throw new ArgumentException("load requires one or two arguments");
}

// per spec, by default it's the same as (interaction-environment)
var destScope = runtime.UserScope;

if (args.Length == 2)
{
if (runtime.Evaluate(scope, args[1]) is not Scope argScope)
{
throw new ArgumentException("load's second argument must be a scope");
}

destScope = argScope;
}

// HACK.PI: since we don't yet support compilation, load is basically the same thing as include,
// but it may be different in the future. The only difference is the support for the optional
// environment argument.
return IncludeFileInternal(runtime, destScope, args[0]);
}
}
19 changes: 16 additions & 3 deletions Colibri.Core/Macros/EnvironmentMacros.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ public static object InteractionEnvironment(ColibriRuntime runtime, Scope scope,
=> runtime.UserScope;

public static object Environment(ColibriRuntime runtime, Scope scope, object?[] args)
{
var newScope = CreateNewEnvironment(runtime, scope, args);

newScope.Freeze();

return newScope;
}

private static Scope CreateNewEnvironment(ColibriRuntime runtime, Scope scope, object?[] args)
{
var newScope = new Scope(scope.MaxStackDepth);

Expand All @@ -17,12 +26,16 @@ public static object Environment(ColibriRuntime runtime, Scope scope, object?[]
}

var importSet = ImportSet.RecursivelyResolveImportSet(scope, argPair);

runtime.ImportLibrary(newScope, importSet);
}

newScope.Freeze();

return newScope;
}

public static object CurrentEnvironment(ColibriRuntime runtime, Scope scope, object?[] args)
=> scope;

public static object MutableEnvironment(ColibriRuntime runtime, Scope scope, object?[] args)
=> CreateNewEnvironment(runtime, scope, args);
}
11 changes: 8 additions & 3 deletions Colibri.Core/StandardLibraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ static StandardLibraries()
(new LibraryName("scheme", "file"), File),
(new LibraryName("scheme", "inexact"), Inexact),
(new LibraryName("scheme", "lazy"), Lazy),
// TODO: (scheme load) library
(new LibraryName("scheme", "load"), Load),
(new LibraryName("scheme", "process-context"), ProcessContext),
(new LibraryName("scheme", "read"), Read),
(new LibraryName("scheme", "repl"), Repl),
Expand Down Expand Up @@ -423,7 +423,10 @@ static StandardLibraries()
["promise?"] = TypeExpressions.IsPromise,
});

// TODO: (scheme load) library
public static readonly Library Load = new(new Dictionary<string, object?>
{
["load"] = (MacroExpression)CoreMacros.Load,
});

public static readonly Library ProcessContext = new(new Dictionary<string, object?>
{
Expand Down Expand Up @@ -463,7 +466,9 @@ static StandardLibraries()

public static readonly Library ColibriBase = new(new Dictionary<string, object?>
{
// in colibri-base.lisp
// in colibri-base.lisp: contains
["current-environment"] = (MacroExpression)EnvironmentMacros.CurrentEnvironment,
["mutable-environment"] = (MacroExpression)EnvironmentMacros.MutableEnvironment,
}, additionalExports: new List<string>
{
"contains"
Expand Down
52 changes: 52 additions & 0 deletions Colibri.Tests/LoadTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Colibri.Core;

namespace Colibri.Tests;

public class LoadTests
{
[Fact]
public void LoadDefaultEnvironmentTest()
{
const string program = @"
(with-output-to-file ""test.txt""
(lambda ()
(display ""(define xyz 42)"")
(newline)))
(load ""test.txt"")
(define result xyz)
(delete-file ""test.txt"")
result
";

var runtime = new ColibriRuntime();

var result = runtime.EvaluateProgram(program);

Assert.Equal(42, result);
}

[Fact]
public void LoadSpecifiedEnvironment()
{
// HACK.PI: uses (colibri base) method (mutable-environment)
const string program = @"
(with-output-to-file ""test.txt""
(lambda ()
(display ""(define xyz 42)"")
(newline)))
(define e (mutable-environment '(scheme base)))
(load ""test.txt"" e)
(define result (eval 'xyz e))
(delete-file ""test.txt"")
result
";

var runtime = new ColibriRuntime();

var result = runtime.EvaluateProgram(program);

Assert.Equal(42, result);
}
}
2 changes: 2 additions & 0 deletions Colibri/PromptConfig/PromptCompletions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public static IReadOnlyList<CompletionItem> GetCompletionItems(
// HACK.PI: this code is _highly_ inefficient
var keys = runtime.UserScope.FlattenAllKeys();
var lexer = new ColibriLexer(new AntlrInputStream(text));

lexer.RemoveErrorListeners();

var tokens = lexer.GetAllTokens();

Expand Down

0 comments on commit 1e70ff4

Please sign in to comment.