Prexonite, a .NET hosted scripting language with a focus on meta-programming and embedded DSLs
0

Configure Feed

Select the types of activity you want to include in your feed.

PRX-30: Add pxs tests for v2 psr

Add a `psr-tests\_2` directory for a v2-specific copy of the PSR tests.
I've decided to copy the test suite because the v2 version of the PSR looks sufficiently different for test code not to be compatible with just some symbol-shuffling.
The replacement for the "SI" struct is based on namespaces and consequently no longer supports the `call\member` trick to access its functions dynamically.

The v2 tests have their own `testconfig.txt` because they don't need an external mechanism for their dependencies. They instead rely on the self-assembling build plan mechanism (`references` and `name` meta entries). Consequently, the v2 `testconfig.txt` format is massively simplified, containing only the test suite file name and list of test cases.

The v2 `run_tests.pxs` is re-written from scratch because loading the test suite via the build plan works fundamentally differently than the hacked-together manual compilation of the v1 `run_tests.pxs`. The v2 variant scans the file system for ``*.test.pxs` and loads them in parallel.

Test execution of multiple test suites (isolated application compounds) could in theory be done in parallel as well, but for now, v2 tests are still executed serially.

TODO:
- migrate test suites for macro and prop

Also
* Use a pool of build engines in a build plan (instead of re-using the engine supplied in loader options). As part of this change, the `IBuildEnvironment` becomes `IDisposable`. This is a BREAKING change. Fixes PRX-42
* expose timer, console, self-assembling build plan, benchmark commands under the new `prx.cli.{timer,host,benchmark}` namespaces.
* expose Prx-specific commands to the compilation engine of the self-assembling build plan. This means you can compile applications that access `prx.cli.host.self_assembling_build_plan`
* Add `flat_map` command (to both Prexonite v1 and v2, under `sys.seq.flat_map`.
* Add `test\diagnostics` / `psr.test.diagnostics` flag for debug output from the test framework
* Add `psr.test.run_tests_in_app` function (v2 only) to run tests in a particular application compound (not necessarily the current one)
* Fix mistyped namespace in `macro.pxs`
* Extend `psr\test.pxs` to run all tests in the entire compound, not just the application that contains the `test.pxs` code. This is irrelevant to v1 code, but essential to use `psr::test` in v2 code.
* Include module name in Prexonite exception stack traces
* Add `Prexonite.Compiler.Cil.Compiler.CompileModulesAsync` method family to perform CIL compilation for a set of modules and all of their dependencies.
* Make `ITargetDescription` implement `IDependent<ModuleName>` (not breaking for languages that support default implementations of interface members).
* Extend `IPlan` with a single module overload of `BuildAsync` and a multi-module overload for `LoadAsync` to complete the symmetry.

Christian Klauser (Dec 28, 2020, 9:54 PM +0100) 9b91a322 d728d1b2

+1196 -394
+92
Prexonite/Commands/List/FlatMap.cs
··· 1 + using System; 2 + using System.Collections.Generic; 3 + using System.Linq; 4 + using JetBrains.Annotations; 5 + using Prexonite.Compiler.Cil; 6 + 7 + namespace Prexonite.Commands.List 8 + { 9 + public class FlatMap : CoroutineCommand, ICilCompilerAware 10 + { 11 + #region Singleton pattern 12 + 13 + public static FlatMap Instance { get; } = new FlatMap(); 14 + 15 + private FlatMap() 16 + { 17 + } 18 + 19 + public const string Alias = "flat_map"; 20 + 21 + #endregion 22 + 23 + protected override IEnumerable<PValue> CoroutineRun(ContextCarrier sctxCarrier, PValue[] args) 24 + { 25 + return CoroutineRunStatically(sctxCarrier, args); 26 + } 27 + 28 + protected static IEnumerable<PValue> CoroutineRunStatically(ContextCarrier sctxCarrier, PValue[] args) 29 + { 30 + if (sctxCarrier == null) 31 + throw new ArgumentNullException(nameof(sctxCarrier)); 32 + if (args == null) 33 + throw new ArgumentNullException(nameof(args)); 34 + 35 + var sctx = sctxCarrier.StackContext; 36 + 37 + //Get f 38 + IIndirectCall f = args.Length < 1 ? null : args[0]; 39 + 40 + foreach (var arg in args.Skip(1)) 41 + { 42 + if (arg == null) 43 + continue; 44 + var xs = Map._ToEnumerable(sctx, arg); 45 + if (xs == null) 46 + continue; 47 + foreach (var x in xs) 48 + { 49 + var rawYs = f != null ? f.IndirectCall(sctx, new[] {x}) : x; 50 + var ys = Map._ToEnumerable(sctx, rawYs); 51 + foreach (var y in ys) 52 + { 53 + yield return y; 54 + } 55 + } 56 + } 57 + } 58 + 59 + [PublicAPI] 60 + public static PValue RunStatically(StackContext sctx, PValue[] args) 61 + { 62 + var carrier = new ContextCarrier(); 63 + var corctx = new CoroutineContext(sctx, CoroutineRunStatically(carrier, args)); 64 + carrier.StackContext = corctx; 65 + return sctx.CreateNativePValue(new Coroutine(corctx)); 66 + } 67 + 68 + #region ICilCompilerAware Members 69 + 70 + /// <summary> 71 + /// Asses qualification and preferences for a certain instruction. 72 + /// </summary> 73 + /// <param name = "ins">The instruction that is about to be compiled.</param> 74 + /// <returns>A set of <see cref = "CompilationFlags" />.</returns> 75 + CompilationFlags ICilCompilerAware.CheckQualification(Instruction ins) 76 + { 77 + return CompilationFlags.PrefersRunStatically; 78 + } 79 + 80 + /// <summary> 81 + /// Provides a custom compiler routine for emitting CIL byte code for a specific instruction. 82 + /// </summary> 83 + /// <param name = "state">The compiler state.</param> 84 + /// <param name = "ins">The instruction to compile.</param> 85 + void ICilCompilerAware.ImplementInCil(CompilerState state, Instruction ins) 86 + { 87 + throw new NotSupportedException(); 88 + } 89 + 90 + #endregion 91 + } 92 + }
+1 -8
Prexonite/Compiler/Build/BuildExtensions.cs
··· 43 43 44 44 public static Task<ITarget> BuildAsync(this IPlan plan, ModuleName name) 45 45 { 46 - return BuildAsync(plan, name, CancellationToken.None); 47 - } 48 - 49 - public static Task<ITarget> BuildAsync(this IPlan plan, ModuleName name, CancellationToken token) 50 - { 51 - var buildTasks = plan.BuildAsync(name.Singleton(), token); 52 - Debug.Assert(buildTasks.Count == 1,"Expected build task dictionary for a single module to only contain a single task."); 53 - return buildTasks[name]; 46 + return plan.BuildAsync(name, CancellationToken.None); 54 47 } 55 48 56 49 public static Tuple<Application,ITarget> Load(this IPlan plan, ModuleName name)
+3 -1
Prexonite/Compiler/Build/IBuildEnvironment.cs
··· 23 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 24 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 25 // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 + 27 + using System; 26 28 using Prexonite.Compiler.Symbolic; 27 29 using Prexonite.Modular; 28 30 29 31 namespace Prexonite.Compiler.Build 30 32 { 31 - public interface IBuildEnvironment 33 + public interface IBuildEnvironment : IDisposable 32 34 { 33 35 34 36 SymbolStore ExternalSymbols
+9 -1
Prexonite/Compiler/Build/IPlan.cs
··· 53 53 IDictionary<ModuleName,Task<ITarget>> BuildAsync([NotNull] IEnumerable<ModuleName> names, CancellationToken token); 54 54 55 55 [NotNull] 56 - Task<Tuple<Application,ITarget>> LoadAsync([NotNull] ModuleName name, CancellationToken token); 56 + Task<ITarget> BuildAsync([NotNull] ModuleName name, CancellationToken token) => 57 + BuildAsync(name.Singleton(), token)[name]; 58 + 59 + [NotNull] 60 + Task<Tuple<Application, ITarget>> LoadAsync([NotNull] ModuleName name, CancellationToken token) => 61 + LoadAsync(name.Singleton(), token)[name]; 62 + 63 + [NotNull] 64 + IDictionary<ModuleName, Task<Tuple<Application,ITarget>>> LoadAsync([NotNull] IEnumerable<ModuleName> names, CancellationToken token); 57 65 58 66 [CanBeNull] 59 67 LoaderOptions Options { get; set; }
+3 -7
Prexonite/Compiler/Build/ITargetDescription.cs
··· 35 35 36 36 namespace Prexonite.Compiler.Build 37 37 { 38 - public interface ITargetDescription 38 + public interface ITargetDescription : IDependent<ModuleName> 39 39 { 40 40 [NotNull] 41 41 IReadOnlyCollection<ModuleName> Dependencies { get; } 42 42 43 43 [NotNull] 44 - ModuleName Name 45 - { 46 - get; 47 - } 48 - 49 - [NotNull] 50 44 IReadOnlyList<Message> BuildMessages { get; } 51 45 52 46 Task<ITarget> BuildAsync([NotNull] IBuildEnvironment build, [NotNull] IDictionary<ModuleName, Task<ITarget>> dependencies, CancellationToken token); 47 + 48 + IEnumerable<ModuleName> IDependent<ModuleName>.GetDependencies() => Dependencies; 53 49 } 54 50 }
+40 -62
Prexonite/Compiler/Build/Internal/DefaultBuildEnvironment.cs
··· 1 - // Prexonite 2 - // 3 - // Copyright (c) 2014, Christian Klauser 4 - // All rights reserved. 5 - // 6 - // Redistribution and use in source and binary forms, with or without modification, 7 - // are permitted provided that the following conditions are met: 8 - // 9 - // Redistributions of source code must retain the above copyright notice, 10 - // this list of conditions and the following disclaimer. 11 - // Redistributions in binary form must reproduce the above copyright notice, 12 - // this list of conditions and the following disclaimer in the 13 - // documentation and/or other materials provided with the distribution. 14 - // The names of the contributors may be used to endorse or 15 - // promote products derived from this software without specific prior written permission. 16 - // 17 - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 - // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 - // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 - // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 - // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 - // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 - // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 - // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 - // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 - using System.Collections.Concurrent; 1 + #nullable enable 2 + 3 + using System; 27 4 using System.Collections.Generic; 28 5 using System.Diagnostics; 6 + using System.Diagnostics.CodeAnalysis; 29 7 using System.Linq; 30 8 using System.Threading; 31 - using System.Threading.Tasks; 9 + using JetBrains.Annotations; 32 10 using Prexonite.Compiler.Symbolic; 33 11 using Prexonite.Modular; 34 12 ··· 38 16 { 39 17 private readonly CancellationToken _token; 40 18 private readonly TaskMap<ModuleName, ITarget> _taskMap; 41 - private readonly IPlan _plan; 42 - private readonly SymbolStore _externalSymbols; 19 + private readonly ManualPlan _plan; 43 20 private readonly ITargetDescription _description; 44 21 private readonly Engine _compilationEngine; 45 - private readonly Module _module; 46 22 47 - public bool TryGetModule(ModuleName moduleName, out Module module) 23 + public bool TryGetModule(ModuleName moduleName, [NotNullWhen(true)] out Module? module) 48 24 { 49 - Task<ITarget> target; 50 - if(_taskMap.TryGetValue(moduleName, out target)) 25 + if(_taskMap.TryGetValue(moduleName, out var target)) 51 26 { 52 27 module = target.Result.Module; 53 28 return true; ··· 59 34 } 60 35 } 61 36 62 - public DefaultBuildEnvironment(IPlan plan, ITargetDescription description, TaskMap<ModuleName, ITarget> taskMap, CancellationToken token) 37 + public DefaultBuildEnvironment(ManualPlan plan, ITargetDescription description, TaskMap<ModuleName, ITarget> taskMap, CancellationToken token) 63 38 { 64 - if (taskMap == null) 65 - throw new System.ArgumentNullException(nameof(taskMap)); 66 - if (description == null) 67 - throw new System.ArgumentNullException(nameof(description)); 68 - if ((object) plan == null) 69 - throw new System.ArgumentNullException(nameof(plan)); 70 - 71 39 _token = token; 72 - _plan = plan; 73 - _taskMap = taskMap; 74 - _description = description; 40 + _plan = plan ?? throw new ArgumentNullException(nameof(plan)); 41 + _taskMap = taskMap ?? throw new ArgumentNullException(nameof(taskMap)); 42 + _description = description ?? throw new ArgumentNullException(nameof(description)); 75 43 var externals = new List<SymbolInfo>(); 76 44 foreach (var name in description.Dependencies) 77 45 { ··· 81 49 externals.AddRange(from decl in d.Symbols 82 50 select new SymbolInfo(decl.Value, origin, decl.Key)); 83 51 } 84 - _externalSymbols = SymbolStore.Create(conflictUnionSource: externals); 85 - _compilationEngine = new Engine(); 86 - _module = Module.Create(description.Name); 52 + ExternalSymbols = SymbolStore.Create(conflictUnionSource: externals); 53 + _compilationEngine = plan.LeaseBuildEngine(); 54 + Module = Module.Create(description.Name); 87 55 } 88 56 89 - public SymbolStore ExternalSymbols 90 - { 91 - get { return _externalSymbols; } 92 - } 57 + public SymbolStore ExternalSymbols { get; } 93 58 94 - public Module Module 95 - { 96 - get 97 - { 98 - return _module; 99 - } 100 - } 59 + public Module Module { get; } 101 60 102 61 public Application InstantiateForBuild() 103 62 { ··· 106 65 return instance; 107 66 } 108 67 109 - public Loader CreateLoader(LoaderOptions defaults = null, Application compilationTarget = null) 68 + public Loader CreateLoader(LoaderOptions? defaults = null, Application? compilationTarget = null) 110 69 { 111 - defaults = defaults ?? new LoaderOptions(null, null); 70 + defaults ??= new LoaderOptions(null, null); 112 71 var planOptions = _plan.Options; 113 72 if(planOptions != null) 114 73 defaults.InheritFrom(planOptions); 115 - compilationTarget = compilationTarget ?? InstantiateForBuild(); 116 - Debug.Assert(compilationTarget.Module.Name == _module.Name); 74 + compilationTarget ??= InstantiateForBuild(); 75 + Debug.Assert(compilationTarget.Module.Name == Module.Name); 117 76 var lowPrioritySymbols = defaults.ExternalSymbols; 118 77 SymbolStore predef; 119 78 if(lowPrioritySymbols.IsEmpty) ··· 135 94 {ReconstructSymbols = false, RegisterCommands = false}; 136 95 finalOptions.InheritFrom(defaults); 137 96 return new Loader(finalOptions); 97 + } 98 + 99 + [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse")] 100 + [SuppressMessage("ReSharper", "ConstantConditionalAccessQualifier")] 101 + protected virtual void Dispose(bool disposing) 102 + { 103 + if (disposing) 104 + { 105 + if (_compilationEngine != null) 106 + { 107 + _plan?.ReturnBuildEngine(_compilationEngine); 108 + } 109 + } 110 + } 111 + 112 + public void Dispose() 113 + { 114 + Dispose(true); 115 + GC.SuppressFinalize(this); 138 116 } 139 117 } 140 118 }
+21 -6
Prexonite/Compiler/Build/Internal/SelfAssemblingPlan.cs
··· 190 190 token.ThrowIfCancellationRequested(); 191 191 192 192 // Perform preflight parse 193 - var eng = new Engine { ExecutionProhibited = true }; 193 + var eng = _createPreflightEngine(); 194 194 var app = new Application(); 195 195 var ldr = 196 196 new Loader(new LoaderOptions(eng, app) ··· 232 232 return result; 233 233 } 234 234 235 - private FileInfo? _getPath([NotNull] ISource source) 235 + private Engine _createPreflightEngine() 236 + { 237 + var compilationEngine = LeaseBuildEngine(); 238 + try 239 + { 240 + // We cannot modify a shared engine from the pool, but we can clone one (cloning is far cheaper than 241 + // instantiating a new one). 242 + return new Engine(compilationEngine) {ExecutionProhibited = true}; 243 + } 244 + finally 245 + { 246 + ReturnBuildEngine(compilationEngine); 247 + } 248 + } 249 + 250 + private static FileInfo? _getPath([NotNull] ISource source) 236 251 { 237 252 return source is FileSource fileSource ? fileSource.File : null; 238 253 } ··· 279 294 { 280 295 while (refSpec.ModuleName == null || !TargetDescriptions.Contains(refSpec.ModuleName)) 281 296 { 282 - if (candidateSequence == null) 283 - candidateSequence = _pathCandidates(refSpec).GetEnumerator(); 297 + candidateSequence ??= _pathCandidates(refSpec).GetEnumerator(); 284 298 285 299 if (!candidateSequence.MoveNext()) 286 300 { ··· 384 398 }); 385 399 386 400 // Assemble dependencies, including standard library (unless suppressed) 387 - var deps = refSpecs.Where(r => r.ModuleName != null).Select(r => r.ModuleName); 401 + var deps = refSpecs.Where(r => r.ModuleName != null).Select(r => r.ModuleName!); 388 402 if (!result.SuppressStandardLibrary) 389 403 deps = deps.Append(StandardLibrary); 390 404 ··· 406 420 private RefSpec _forbidFileRefSpec(RefSpec refSpec) 407 421 { 408 422 if (refSpec.ModuleName == null) 409 - refSpec.ErrorMessage ??= Resources.SelfAssemblingPlan__forbidFileRefSpec_notallowed; 423 + Interlocked.CompareExchange(ref refSpec.ErrorMessage, 424 + Resources.SelfAssemblingPlan__forbidFileRefSpec_notallowed, null); 410 425 return refSpec; 411 426 } 412 427
+60 -63
Prexonite/Compiler/Build/ManualPlan.cs
··· 1 - // Prexonite 2 - // 3 - // Copyright (c) 2014, Christian Klauser 4 - // All rights reserved. 5 - // 6 - // Redistribution and use in source and binary forms, with or without modification, 7 - // are permitted provided that the following conditions are met: 8 - // 9 - // Redistributions of source code must retain the above copyright notice, 10 - // this list of conditions and the following disclaimer. 11 - // Redistributions in binary form must reproduce the above copyright notice, 12 - // this list of conditions and the following disclaimer in the 13 - // documentation and/or other materials provided with the distribution. 14 - // The names of the contributors may be used to endorse or 15 - // promote products derived from this software without specific prior written permission. 16 - // 17 - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 - // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 - // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 - // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 - // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 - // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 - // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 - // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 - // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1 + #nullable enable 2 + 26 3 using System; 27 4 using System.Collections.Generic; 28 5 using System.Diagnostics; 29 6 using System.Linq; 30 7 using System.Threading; 31 8 using System.Threading.Tasks; 32 - using JetBrains.Annotations; 9 + using Microsoft.Extensions.ObjectPool; 33 10 using Prexonite.Compiler.Build.Internal; 34 11 using Prexonite.Modular; 12 + using Debug = System.Diagnostics.Debug; 35 13 36 14 namespace Prexonite.Compiler.Build 37 15 { 38 16 public class ManualPlan : IPlan 39 17 { 40 - private readonly HashSet<IBuildWatcher> _buildWatchers = new HashSet<IBuildWatcher>(); 41 - private readonly TargetDescriptionSet _targetDescriptions = TargetDescriptionSet.Create(); 42 - 43 - public ISet<IBuildWatcher> BuildWatchers 18 + private readonly DefaultObjectPool<Engine> _enginePool; 19 + private class EnginePoolPolicy : IPooledObjectPolicy<Engine> 44 20 { 45 - get { return _buildWatchers; } 46 - } 21 + private readonly ManualPlan _inner; 47 22 48 - public TargetDescriptionSet TargetDescriptions 49 - { 50 - get { return _targetDescriptions; } 23 + public EnginePoolPolicy(ManualPlan inner) 24 + { 25 + _inner = inner; 26 + } 27 + 28 + public Engine Create() => 29 + _inner.Options?.ParentEngine switch 30 + { 31 + { } x => new Engine(x), 32 + _ => new Engine() 33 + }; 34 + 35 + public bool Return(Engine obj) => true; 51 36 } 37 + 38 + public ISet<IBuildWatcher> BuildWatchers { get; } = new HashSet<IBuildWatcher>(); 39 + 40 + public TargetDescriptionSet TargetDescriptions { get; } = TargetDescriptionSet.Create(); 52 41 53 42 /// <summary> 54 43 /// Creates an <see cref="ITargetDescription"/> from an <see cref="ISource"/> with manually specified dependencies. ··· 61 50 /// <returns></returns> 62 51 /// <exception cref="ArgumentException">Dependencies must not contain multiple versions of the same module.</exception> 63 52 /// <remarks>You will have to make sure that this plan contains a target description for each dependency before this target description can be built.</remarks> 64 - public ITargetDescription CreateDescription([NotNull] ModuleName moduleName, [NotNull] ISource source, [CanBeNull] string fileName, [NotNull] IEnumerable<ModuleName> dependencies, [CanBeNull] IEnumerable<Message> buildMessages = null) 53 + public ITargetDescription CreateDescription(ModuleName moduleName, ISource source, string? fileName, IEnumerable<ModuleName> dependencies, IEnumerable<Message>? buildMessages = null) 65 54 { 66 55 return new ManualTargetDescription(moduleName, source, fileName, dependencies, buildMessages); 67 56 } ··· 113 102 return new TaskMap<ModuleName, ITarget>(5, TargetDescriptions.Count); 114 103 } 115 104 116 - public Task<Tuple<Application, ITarget>> LoadAsync(ModuleName name, CancellationToken token) 105 + public IDictionary<ModuleName, Task<Tuple<Application, ITarget>>> LoadAsync(IEnumerable<ModuleName> names, CancellationToken token) 117 106 { 107 + if (names == null) 108 + throw new ArgumentNullException(nameof(names)); 118 109 var taskMap = CreateTaskMap(); 119 - var description = _prepareBuild(name); 120 - return BuildWithMapAsync(description, taskMap, token).ContinueWith(buildTask => 110 + return names.ToDictionary(name => name, name => 111 + { 112 + var description = _prepareBuild(name); 113 + return BuildWithMapAsync(description, taskMap, token).ContinueWith(buildTask => 121 114 { 122 115 var target = buildTask.Result; 123 116 var app = new Application(target.Module); 124 117 _linkDependencies(taskMap, app, description, token); 125 118 return Tuple.Create(app, target); 126 119 }, token); 120 + }); 127 121 } 128 122 129 - [CanBeNull] private LoaderOptions _options; 130 - public LoaderOptions Options 123 + protected ManualPlan() 131 124 { 132 - get { return _options; } 133 - set { _options = value; } 125 + _enginePool = new DefaultObjectPool<Engine>(new EnginePoolPolicy(this), Environment.ProcessorCount); 134 126 } 127 + 128 + public LoaderOptions? Options { get; set; } 129 + 130 + internal Engine LeaseBuildEngine() => _enginePool.Get(); 131 + internal void ReturnBuildEngine(Engine buildEngine) => _enginePool.Return(buildEngine); 135 132 136 133 private void _linkDependencies(TaskMap<ModuleName, ITarget> taskMap, Application instance, ITargetDescription instanceDescription, CancellationToken token) 137 134 { ··· 206 203 depMap.AddRange(deps); 207 204 208 205 token.ThrowIfCancellationRequested(); 209 - 206 + 210 207 var buildTask = GetBuildEnvironmentAsync(taskMap, desc, 211 208 token) 212 - .ContinueWith(bet => 213 - { 214 - var instance = 215 - new Application( 216 - bet.Result.Module); 217 - Plan.Trace.TraceEvent( 218 - TraceEventType.Verbose, 0, 219 - "Linking compile-time dependencies for module {0}.", 220 - bet.Result.Module.Name); 221 - _linkDependencies(taskMap, 222 - instance, targetDescription, 223 - token); 224 - token 225 - .ThrowIfCancellationRequested 226 - (); 227 - return BuildTargetAsync(bet, desc, 228 - depMap, token); 229 - }, token); 209 + .ContinueWith(async bet => 210 + { 211 + try 212 + { 213 + var instance = new Application(bet.Result.Module); 214 + Plan.Trace.TraceEvent(TraceEventType.Verbose, 0, 215 + "Linking compile-time dependencies for module {0}.", bet.Result.Module.Name); 216 + _linkDependencies(taskMap, instance, targetDescription, token); 217 + token.ThrowIfCancellationRequested(); 218 + var target = await BuildTargetAsync(bet, desc, depMap, token); 219 + return target; 220 + } 221 + finally 222 + { 223 + bet.Dispose(); 224 + } 225 + }, token); 230 226 return buildTask.Unwrap(); 231 227 } 232 228 233 229 protected virtual Task<ITarget> BuildTargetAsync(Task<IBuildEnvironment> buildEnvironment, ITargetDescription description, Dictionary<ModuleName, Task<ITarget>> dependencies, CancellationToken token) 234 230 { 235 231 var buildTask = description.BuildAsync(buildEnvironment.Result, dependencies, token); 236 - Debug.Assert(buildTask != null, "Task for building target is null.", string.Format("{0}.BuildAsync returned null instead of a Task.", description.GetType().Name)); 232 + Debug.Assert(buildTask != null, "Task for building target is null.", 233 + $"{description.GetType().Name}.BuildAsync returned null instead of a Task."); 237 234 return buildTask; 238 235 } 239 236 }
+39
Prexonite/Compiler/Cil/Compiler.cs
··· 34 34 using System.Reflection; 35 35 using System.Reflection.Emit; 36 36 using System.Threading; 37 + using System.Threading.Tasks; 38 + using JetBrains.Annotations; 37 39 using Lokad.ILPack; 38 40 using Prexonite.Commands; 41 + using Prexonite.Compiler.Build; 39 42 using Prexonite.Modular; 40 43 using Prexonite.Types; 41 44 using CilException = Prexonite.PrexoniteException; 45 + using Module = Prexonite.Modular.Module; 42 46 43 47 #endregion 44 48 ··· 162 166 func.Declaration.CilImplementation = pass.GetDelegate(func.Id); 163 167 pass.LinkMetadata(func); 164 168 } 169 + } 170 + 171 + [PublicAPI] 172 + public static async Task<IDictionary<ModuleName, Tuple<Application, ITarget>>> CompileModulesAsync(IPlan plan, IEnumerable<ModuleName> moduleNames, 173 + Engine engine, FunctionLinking linking = FunctionLinking.JustStatic, CancellationToken ct = default) 174 + { 175 + var dependencyClosure = new DependencyAnalysis<ModuleName, ITargetDescription>( 176 + moduleNames.Select(m => plan.TargetDescriptions[m]), 177 + false); 178 + var compiledApplications = new Dictionary<ModuleName, Tuple<Application, ITarget>>(); 179 + 180 + foreach (var group in dependencyClosure.GetMutuallyRecursiveGroups()) 181 + { 182 + var groupTargets = await Task.WhenAll(group.Select(t => plan.LoadAsync(t.Name, ct))); 183 + foreach(var (_, groupTarget) in groupTargets) 184 + { 185 + groupTarget.ThrowIfFailed(plan.TargetDescriptions[groupTarget.Name]); 186 + } 187 + 188 + Compile(groupTargets.SelectMany(t => t.Item1.Functions), engine, linking); 189 + 190 + foreach (var groupTarget in groupTargets) 191 + { 192 + compiledApplications[groupTarget.Item2.Name] = groupTarget; 193 + } 194 + } 195 + 196 + return compiledApplications; 197 + } 198 + 199 + [PublicAPI] 200 + public static Task<IDictionary<ModuleName, Tuple<Application, ITarget>>> CompileModulesAsync(StackContext sctx, IPlan plan, IEnumerable<ModuleName> moduleNames, 201 + FunctionLinking linking = FunctionLinking.JustStatic, CancellationToken ct = default) 202 + { 203 + return CompileModulesAsync(plan, moduleNames, sctx.ParentEngine, linking, ct); 165 204 } 166 205 167 206 public static bool TryCompile(PFunction func, Engine targetEngine)
+2 -1
Prexonite/Compiler/Symbolic/Internal/ConflictUnionFallbackStore.cs
··· 26 26 using System; 27 27 using System.Collections.Generic; 28 28 using System.Diagnostics; 29 + using System.Diagnostics.CodeAnalysis; 29 30 using System.Linq; 30 31 using System.Threading; 31 32 using Prexonite.Properties; ··· 376 377 }; 377 378 } 378 379 379 - public override bool TryGet(string id, out Symbol? value) 380 + public override bool TryGet(string id, [NotNullWhen(true)] out Symbol? value) 380 381 { 381 382 _lock.EnterReadLock(); 382 383 try
+6 -10
Prexonite/Compiler/Symbolic/Internal/ModuleLevelView.cs
··· 2 2 using System.Collections.Concurrent; 3 3 using System.Collections.Generic; 4 4 using System.Diagnostics; 5 - using JetBrains.Annotations; 5 + using System.Diagnostics.CodeAnalysis; 6 6 7 7 #nullable enable 8 8 ··· 13 13 /// <summary> 14 14 /// The scope that this filter wraps. 15 15 /// </summary> 16 - [NotNull] 17 16 private SymbolStore _backingStore; 18 17 19 18 internal SymbolStore BackingStore => _backingStore; ··· 24 23 /// <remarks> 25 24 /// This dictionary is shared between all child-<see cref="ModuleLevelView"/>s. 26 25 /// </remarks> 27 - [NotNull] 28 26 private readonly ConcurrentDictionary<Namespace, LocalNamespaceImpl> _localProxies; 29 27 30 - private ModuleLevelView([NotNull] SymbolStore backingStore, [NotNull] ConcurrentDictionary<Namespace, LocalNamespaceImpl> localProxies) 28 + private ModuleLevelView(SymbolStore backingStore, ConcurrentDictionary<Namespace, LocalNamespaceImpl> localProxies) 31 29 { 32 30 _backingStore = backingStore ?? throw new ArgumentNullException(nameof(backingStore)); 33 31 _localProxies = localProxies ?? throw new ArgumentNullException(nameof(localProxies)); 34 32 } 35 33 36 - public static ModuleLevelView Create([NotNull] SymbolStore externalScope) 34 + public static ModuleLevelView Create(SymbolStore externalScope) 37 35 { 38 36 return new ModuleLevelView(externalScope, new ConcurrentDictionary<Namespace, LocalNamespaceImpl>()); 39 37 } ··· 43 41 /// <summary> 44 42 /// Wrapper around the symbols of this namespace coming from external sources. 45 43 /// </summary> 46 - [NotNull] 47 44 private readonly ModuleLevelView _localView; 48 45 49 46 /// <summary> 50 47 /// Holds module-local exports. Uses <see cref="_localView"/> as its external scope. 51 48 /// </summary> 52 - [NotNull] 53 49 private readonly SymbolStore _exportScope; 54 50 55 51 /// <summary> ··· 64 60 /// </remarks> 65 61 private string? _prefix; 66 62 67 - internal LocalNamespaceImpl([NotNull] ISymbolView<Symbol> externalScope, [NotNull] ConcurrentDictionary<Namespace, LocalNamespaceImpl> localProxies) 63 + internal LocalNamespaceImpl(ISymbolView<Symbol> externalScope, ConcurrentDictionary<Namespace, LocalNamespaceImpl> localProxies) 68 64 { 69 65 _exportScope = Create(externalScope); 70 66 _localView = new ModuleLevelView(_exportScope, localProxies); ··· 119 115 } 120 116 121 117 122 - public override bool TryGet(string id, out Symbol? value) 118 + public override bool TryGet(string id, [NotNullWhen(true)] out Symbol? value) 123 119 { 124 120 return _localView.TryGet(id, out value); 125 121 } ··· 205 201 } 206 202 } 207 203 208 - public override bool TryGet(string id, out Symbol? value) 204 + public override bool TryGet(string id, [NotNullWhen(true)] out Symbol? value) 209 205 { 210 206 if (_backingStore.TryGet(id, out value)) 211 207 {
+9 -18
Prexonite/Compiler/Symbolic/NamespaceSymbol.cs
··· 10 10 [DebuggerDisplay("{ToString()}")] 11 11 public sealed class NamespaceSymbol : Symbol, IEquatable<NamespaceSymbol> 12 12 { 13 - private readonly Namespace _namespace; 14 - private readonly ISourcePosition _position; 15 - 16 - public Namespace Namespace 17 - { 18 - get { return _namespace; } 19 - } 13 + public Namespace Namespace { get; } 20 14 21 15 public override string ToString() 22 16 { 23 - return String.Format("namespace"); 17 + return "namespace"; 24 18 } 25 19 26 20 private NamespaceSymbol([NotNull] ISourcePosition position, [NotNull] Namespace @namespace) 27 21 { 28 - _position = position; 29 - _namespace = @namespace; 22 + Position = position; 23 + Namespace = @namespace; 30 24 } 31 25 32 26 public override TResult HandleWith<TArg, TResult>(ISymbolHandler<TArg, TResult> handler, TArg argument) ··· 34 28 return handler.HandleNamespace(this, argument); 35 29 } 36 30 37 - public override ISourcePosition Position 38 - { 39 - get { return _position; } 40 - } 31 + public override ISourcePosition Position { get; } 41 32 42 - public override bool Equals(Symbol other) 33 + public override bool Equals(Symbol? other) 43 34 { 44 35 if (ReferenceEquals(other, this)) return true; 45 36 if (ReferenceEquals(other, null)) return false; 46 - return (other is NamespaceSymbol) && _equalsNonNull((NamespaceSymbol)other); 37 + return other is NamespaceSymbol nsSymbol && _equalsNonNull(nsSymbol); 47 38 } 48 39 49 - public bool Equals(NamespaceSymbol other) 40 + public bool Equals(NamespaceSymbol? other) 50 41 { 51 42 if (ReferenceEquals(other, this)) return true; 52 43 return !ReferenceEquals(other, null) && _equalsNonNull(other); ··· 59 50 60 51 public override int GetHashCode() 61 52 { 62 - return _namespace.GetHashCode(); 53 + return Namespace.GetHashCode(); 63 54 } 64 55 65 56 internal static NamespaceSymbol _Create([NotNull] Namespace @namespace, [NotNull] ISourcePosition position)
+37 -41
Prexonite/Engine.cs
··· 119 119 #region PType map 120 120 121 121 private readonly Dictionary<Type, PType> _pTypeMap; 122 - private readonly PTypeMapIterator _ptypemapiterator; 123 122 124 123 /// <summary> 125 124 /// Provides access to the PType to CLR <see cref = "System.Type">Type</see> mapping. ··· 128 127 /// The property uses a proxy type to hide implementation details. 129 128 /// </remarks> 130 129 /// <seealso cref = "PTypeMapIterator" /> 131 - public PTypeMapIterator PTypeMap 132 - { 133 - [DebuggerStepThrough] 134 - get { return _ptypemapiterator; } 135 - } 130 + public PTypeMapIterator PTypeMap { get; } 136 131 137 132 /// <summary> 138 133 /// Proxy type that is used to provide access to the <see cref = "PType" /> to CLR <see cref = "System.Type">Type</see> mapping. ··· 234 229 #region PType registry 235 230 236 231 private readonly SymbolTable<Type> _pTypeRegistry; 237 - private readonly PTypeRegistryIterator _pTypeRegistryIterator; 238 232 239 233 /// <summary> 240 234 /// Provides access to the dictionary of <see cref = "PType">PTypes</see> registered 241 235 /// for recognition in type expressions. 242 236 /// </summary> 243 237 /// <seealso cref = "PTypeRegistryIterator" /> 244 - public PTypeRegistryIterator PTypeRegistry 245 - { 246 - [DebuggerStepThrough] 247 - get { return _pTypeRegistryIterator; } 248 - } 238 + public PTypeRegistryIterator PTypeRegistry { get; } 249 239 250 240 /// <summary> 251 241 /// The proxy class that is used to provide access to the <see cref = "Prexonite.Engine.PTypeRegistry" /> ··· 398 388 if (value == null) 399 389 return PType.Null.CreatePValue(); 400 390 else 401 - return _ptypemapiterator[value.GetType()].CreatePValue(value); 391 + return PTypeMap[value.GetType()].CreatePValue(value); 402 392 } 403 393 404 394 #region CreatePType ··· 583 573 584 574 #region Command management 585 575 586 - private readonly CommandTable _commandTable; 587 - 588 576 /// <summary> 589 577 /// A proxy to list commands provided by the engine. 590 578 /// </summary> 591 - public CommandTable Commands 592 - { 593 - [DebuggerStepThrough] 594 - get { return _commandTable; } 595 - } 579 + public CommandTable Commands { [DebuggerStepThrough] get; } 596 580 597 581 #endregion 598 582 ··· 601 585 /// <summary> 602 586 /// Provides access to the search paths used by this particular engine. 603 587 /// </summary> 604 - public List<String> Paths 605 - { 606 - [DebuggerStepThrough] 607 - get { return _paths; } 608 - } 609 - 610 - private readonly List<String> _paths = new List<string>(); 588 + public List<string> Paths { get; } = new List<string>(); 611 589 612 590 #endregion 613 591 ··· 628 606 629 607 //PTypes 630 608 _pTypeMap = new Dictionary<Type, PType>(); 631 - _ptypemapiterator = new PTypeMapIterator(this); 609 + PTypeMap = new PTypeMapIterator(this); 632 610 //int 633 611 PTypeMap[typeof (int)] = PType.Int; 634 612 PTypeMap[typeof (long)] = PType.Int; ··· 661 639 662 640 //Registry 663 641 _pTypeRegistry = new SymbolTable<Type>(); 664 - _pTypeRegistryIterator = new PTypeRegistryIterator(this); 665 - PTypeRegistry[IntPType.Literal] = typeof (IntPType); 666 - PTypeRegistry[BoolPType.Literal] = typeof (BoolPType); 667 - PTypeRegistry[RealPType.Literal] = typeof (RealPType); 668 - PTypeRegistry[CharPType.Literal] = typeof (CharPType); 669 - PTypeRegistry[StringPType.Literal] = typeof (StringPType); 670 - PTypeRegistry[NullPType.Literal] = typeof (NullPType); 671 - PTypeRegistry[ObjectPType.Literal] = typeof (ObjectPType); 672 - PTypeRegistry[ListPType.Literal] = typeof (ListPType); 673 - PTypeRegistry[StructurePType.Literal] = typeof (StructurePType); 674 - PTypeRegistry[HashPType.Literal] = typeof (HashPType); 675 - PTypeRegistry[StructurePType.Literal] = typeof (StructurePType); 642 + PTypeRegistry = new PTypeRegistryIterator(this) 643 + { 644 + [IntPType.Literal] = typeof(IntPType), 645 + [BoolPType.Literal] = typeof(BoolPType), 646 + [RealPType.Literal] = typeof(RealPType), 647 + [CharPType.Literal] = typeof(CharPType), 648 + [StringPType.Literal] = typeof(StringPType), 649 + [NullPType.Literal] = typeof(NullPType), 650 + [ObjectPType.Literal] = typeof(ObjectPType), 651 + [ListPType.Literal] = typeof(ListPType), 652 + [StructurePType.Literal] = typeof(StructurePType), 653 + [HashPType.Literal] = typeof(HashPType), 654 + [StructurePType.Literal] = typeof(StructurePType) 655 + }; 676 656 677 657 //Assembly registry 678 658 _registeredAssemblies = new List<Assembly>(); ··· 681 661 _registeredAssemblies.Add(Assembly.Load(assName.FullName)); 682 662 683 663 //Commands 684 - _commandTable = new CommandTable(); 664 + Commands = new CommandTable(); 685 665 PCommand cmd; 686 666 687 667 Commands.AddEngineCommand(PrintAlias, ConsolePrint.Instance); ··· 698 678 699 679 Commands.AddEngineCommand(MapAlias, cmd = Map.Instance); 700 680 Commands.AddEngineCommand(SelectAlias, cmd); 681 + Commands.AddEngineCommand(FlatMap.Alias, FlatMap.Instance); 701 682 702 683 Commands.AddEngineCommand(FoldLAlias, FoldL.Instance); 703 684 ··· 864 845 Commands.AddEngineCommand(CreateSourcePosition.Alias, CreateSourcePosition.Instance); 865 846 866 847 Commands.AddEngineCommand(SeqConcat.Alias, SeqConcat.Instance); 848 + } 849 + 850 + internal Engine(Engine prototype) 851 + { 852 + _stackSlot = Thread.AllocateDataSlot(); 853 + _meta = prototype.Meta.Clone(); 854 + _pTypeMap = new Dictionary<Type, PType>(prototype._pTypeMap); 855 + PTypeMap = new PTypeMapIterator(this); 856 + _pTypeRegistry = new SymbolTable<Type>(prototype._pTypeRegistry.Count); 857 + _pTypeRegistry.AddRange(prototype._pTypeRegistry); 858 + PTypeRegistry = new PTypeRegistryIterator(this); 859 + _registeredAssemblies = new List<Assembly>(prototype._registeredAssemblies); 860 + Commands = new CommandTable(); 861 + Commands.AddRange(prototype.Commands); 862 + 867 863 } 868 864 869 865 /// <summary>
+3
Prexonite/Exceptions.cs
··· 220 220 221 221 builder.Append(func.Meta.GetDefault(PFunction.LogicalIdKey, func.Id).Text); 222 222 223 + builder.Append(" module "); 224 + builder.Append(func.ParentApplication.Module.Name); 225 + 223 226 if (0 <= pointer && pointer < code.Count) 224 227 { 225 228 builder.Append(" around instruction ");
+2 -2
Prexonite/Helper/DependencyAnalysis.cs
··· 36 36 { 37 37 /// <summary> 38 38 /// </summary> 39 - /// <typeparam name = "TKey"></typeparam> 40 - /// <typeparam name = "TValue"></typeparam> 39 + /// <typeparam name = "TKey">Identifier for nodes.</typeparam> 40 + /// <typeparam name = "TValue">Nodes of the dependency graph.</typeparam> 41 41 public class DependencyAnalysis<TKey, TValue> where 42 42 TValue : class, IDependent<TKey> 43 43 {
+1
Prexonite/Helper/MetaEntry.cs
··· 367 367 368 368 #endregion 369 369 370 + [PublicAPI] 370 371 public static MetaEntry[] CreateArray(StackContext sctx, List<PValue> elements) 371 372 { 372 373 var proto = new List<MetaEntry>(elements.Count);
+25 -52
Prexonite/Modular/ModuleName.cs
··· 1 - // Prexonite 2 - // 3 - // Copyright (c) 2014, Christian Klauser 4 - // All rights reserved. 5 - // 6 - // Redistribution and use in source and binary forms, with or without modification, 7 - // are permitted provided that the following conditions are met: 8 - // 9 - // Redistributions of source code must retain the above copyright notice, 10 - // this list of conditions and the following disclaimer. 11 - // Redistributions in binary form must reproduce the above copyright notice, 12 - // this list of conditions and the following disclaimer in the 13 - // documentation and/or other materials provided with the distribution. 14 - // The names of the contributors may be used to endorse or 15 - // promote products derived from this software without specific prior written permission. 16 - // 17 - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 - // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 - // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 - // IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 21 - // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 - // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 - // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 - // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 - // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1 + #nullable enable 26 2 using System; 27 3 using System.Diagnostics; 4 + using System.Diagnostics.CodeAnalysis; 28 5 using System.Linq; 29 6 using Prexonite.Properties; 30 7 using Prexonite.Types; ··· 38 15 [DebuggerDisplay("{Id},{Version}")] 39 16 public sealed class ModuleName : IEquatable<ModuleName> 40 17 { 41 - private readonly string _id; 42 - 43 18 /// <summary> 44 19 /// The name of the named module. Should be a dotted identifier. Must not contain a comma (U+002C ',') or white space (Unicode category Zs). 45 20 /// </summary> 46 - public string Id 47 - { 48 - get { return _id; } 49 - } 21 + public string Id { get; } 50 22 51 - private readonly Version _version; 52 23 public static readonly PType PType = PType.Object[typeof(ModuleName)]; 24 + private static readonly Version ZeroVersion = new Version(); 53 25 54 26 /// <summary> 55 27 /// The version of the named module. Consists of four 32bit integers (signed, but non-negative). 56 28 /// </summary> 57 - public Version Version 58 - { 59 - get { return _version; } 60 - } 29 + public Version Version { get; } 61 30 62 31 public ModuleName(string id, Version version) 63 32 { 64 - if (String.IsNullOrEmpty(id)) 33 + if (string.IsNullOrEmpty(id)) 65 34 throw new ArgumentException(Resources.ModuleName_Module_id_cannot_be_null_or_empty_,nameof(id)); 66 35 67 36 if (version == null) ··· 74 43 // ReSharper restore PossibleNullReferenceException 75 44 #endif 76 45 77 - _id = id; 78 - _version = version; 46 + Id = id; 47 + Version = version; 79 48 } 80 49 81 50 /// <summary> ··· 85 54 /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false. 86 55 /// </returns> 87 56 /// <param name="other">An object to compare with this object.</param> 88 - public bool Equals(ModuleName other) 57 + public bool Equals(ModuleName? other) 89 58 { 90 59 if (ReferenceEquals(null, other)) return false; 91 60 if (ReferenceEquals(this, other)) return true; 92 - return Engine.StringsAreEqual(other._id, _id) && Equals(other._version, _version); 61 + return Engine.StringsAreEqual(other.Id, Id) && Equals(other.Version, Version); 93 62 } 94 63 95 64 /// <summary> ··· 99 68 /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false. 100 69 /// </returns> 101 70 /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>. </param><filterpriority>2</filterpriority> 102 - public override bool Equals(object obj) 71 + public override bool Equals(object? obj) 103 72 { 104 73 if (ReferenceEquals(null, obj)) return false; 105 74 if (ReferenceEquals(this, obj)) return true; ··· 118 87 { 119 88 unchecked 120 89 { 121 - return (_id.GetHashCode()*397) ^ _version.GetHashCode(); 90 + return (Id.GetHashCode()*397) ^ Version.GetHashCode(); 122 91 } 123 92 } 124 93 125 - public static bool operator ==(ModuleName left, ModuleName right) 94 + public static bool operator ==(ModuleName? left, ModuleName? right) 126 95 { 127 96 return Equals(left, right); 128 97 } 129 98 130 - public static bool operator !=(ModuleName left, ModuleName right) 99 + public static bool operator !=(ModuleName? left, ModuleName? right) 131 100 { 132 101 return !Equals(left, right); 133 102 } ··· 149 118 /// <para>"Name, 1.0"</para> 150 119 /// <para>"Name.Dots, 1.2.4"</para> 151 120 /// </remarks> 152 - public static bool TryParse(string rawName, out ModuleName name) 121 + public static bool TryParse(string rawName, [NotNullWhen(true)] out ModuleName? name) 153 122 { 154 123 return TryParse(new MetaEntry(rawName), out name); 155 124 } ··· 168 137 /// <para>{Name,"1.0.0"}</para> 169 138 /// <para>{Name,{"1","2","3","4"}}</para> 170 139 /// </remarks> 171 - public static bool TryParse(MetaEntry entry, out ModuleName name) 140 + public static bool TryParse(MetaEntry entry, [NotNullWhen(true)] out ModuleName? name) 172 141 { 173 142 name = null; 174 143 if(entry == null) ··· 178 147 return false; 179 148 180 149 string id; 181 - string rawVersion = null; 150 + string? rawVersion = null; 182 151 if(entry.IsText) 183 152 { 184 153 id = entry.Text; ··· 237 206 || rawVersion != null && rawVersion.Length == 0) 238 207 return false; 239 208 240 - Version v; 209 + Version? v; 241 210 if (rawVersion == null) 242 - v = new Version(); 211 + v = ZeroVersion; 243 212 else 244 213 if (!Version.TryParse(rawVersion, out v)) 245 214 return false; ··· 254 223 255 224 public override string ToString() 256 225 { 257 - return _id + "," + _version; 226 + if (Version == ZeroVersion) 227 + { 228 + return Id; 229 + } 230 + return Id + "," + Version; 258 231 } 259 232 260 233 public MetaEntry ToMetaEntry() 261 234 { 262 - return new MetaEntry(new MetaEntry[] {_id, _version.ToString()}); 235 + return new MetaEntry(new MetaEntry[] {Id, Version.ToString()}); 263 236 } 264 237 265 238 public static implicit operator MetaEntry(ModuleName name)
+1
Prexonite/Prexonite.csproj
··· 152 152 <PackageReference Include="Lokad.ILPack" Version="0.1.3" /> 153 153 <PackageReference Include="PxCoco" Version="1.91.2" /> 154 154 <PackageReference Include="System.Reflection.Emit" Version="4.7.0" /> 155 + <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="3.1.10" /> 155 156 </ItemGroup> 156 157 </Project>
+1 -1
Prexonite/prxlib/prx.core.pxs
··· 12 12 13 13 } 14 14 export(*),prx.prim( 15 - map,foldl,foldr,sort,all => to_list, where => filter, skip,take, 15 + map,flat_map,foldl,foldr,sort,all => to_list, where => filter, skip,take, 16 16 count,distinct,union,unique,frequency,groupby,intersect,each,exists,forall, 17 17 takewhile,except,range, reverse, headtail, append, sum, contains, 18 18 create_enumerator,seqconcat);
+1
Prexonite/prxlib/prx.prim.pxs
··· 11 11 boxed = ref command "boxed", 12 12 string_concat = ref command "string_concat", 13 13 map = ref command "map", 14 + flat_map = ref command "flat_map", 14 15 select = ref command "select", 15 16 foldl = ref command "foldl", 16 17 foldr = ref command "foldr",
+1
Prexonite/prxlib/prx.v1.prelude.pxs
··· 16 16 string_concat, 17 17 concat, 18 18 map, 19 + flat_map, 19 20 select, 20 21 foldl, 21 22 foldr,
+1
Prexonite/prxlib/prx.v1.pxs
··· 13 13 string_concat, 14 14 concat, 15 15 map, 16 + flat_map, 16 17 select, 17 18 foldl, 18 19 foldr,
+4
PrexoniteTests/PrexoniteTests.csproj
··· 35 35 <TextTemplate Include="**\*.tt" /> 36 36 </ItemGroup> 37 37 38 + <ItemGroup> 39 + <Folder Include="psr-tests\_2" /> 40 + </ItemGroup> 41 + 38 42 <!-- Text Template --> 39 43 <Target Name="TextTemplateTransform" BeforeTargets="BeforeBuild"> 40 44 <!-- https://notquitepure.info/2018/12/12/T4-Templates-at-Build-Time-With-Dotnet-Core/ -->
+16
PrexoniteTests/Tests/VMTests.Commands.cs
··· 84 84 } 85 85 86 86 [Test] 87 + public void FlatMapImplementation() 88 + { 89 + Compile(@" 90 + function main() { 91 + coroutine f(n) { 92 + for(var i = 1; i <= n; i++) 93 + yield i; 94 + } 95 + return var args >> flat_map(f(?), [1,0], []) >> foldl( (l,r) => l + "","" + r, """"); 96 + } 97 + "); 98 + 99 + Expect(",1,1,2,3,1,2,3,4", 3,4); 100 + } 101 + 102 + [Test] 87 103 public void FoldLCommandImplementation() 88 104 { 89 105 Compile(
+358
PrexoniteTests/psr-tests/_2/ast.test.pxs
··· 1 + name psr::ast::test/2.0; 2 + references { 3 + psr::test, 4 + psr::ast 5 + }; 6 + 7 + namespace import 8 + sys.*, 9 + sys.seq.*, 10 + psr.test.assertions.*, 11 + psr.ast, 12 + psr.ast(SI, unique_id, is_member_access, local_meta, sub_blocks); 13 + 14 + function ast3 = ast.simple3(sys.ct.get_unscoped_ast_factory, *var args); 15 + 16 + function compiler_is_loaded[test] 17 + { 18 + var found = null; 19 + foreach(var app in asm(ldr.app).Compound) 20 + { 21 + var mt = app.Meta; 22 + if(mt["compiler_loaded"].Switch){ 23 + if(found is Null) 24 + { 25 + assert(mt["psr_ast_pxs_open"].Switch, "The meta switch 'psr_ast_pxs_open' should be set."); 26 + found = app.Module.Name; 27 + } 28 + else 29 + { 30 + assert(false,"Found multiple modules that have ast.pxs loaded: $found and $(app.Module.Name)"); 31 + } 32 + } 33 + } 34 + 35 + assert(found is not Null, "After loading psr\\ast.pxs, one module in the compound should have 'compiler_loaded' enabled."); 36 + } 37 + 38 + // Such a function is usually defined by macro.pxs, but we'll provide a simplified version 39 + // here to make testing of ast.pxs easier. 40 + // Do not use this implementation in actual code as it does not use the correct factory and 41 + // will not encode the caller's source position. 42 + function dummy\ast\call(entityref) 43 + { 44 + return ast3("IndirectCall", ast3("Reference", entityref)); 45 + } 46 + declare dummy\ast\call as ast\call; 47 + 48 + function test_ast_withpos_null[test] 49 + { 50 + var nt = ast.with_pos("Null"); 51 + assert(nt is Prexonite::Compiler::Ast::AstNull, "ast\\withPos(\"Null\") is not an AstNull node."); 52 + assert(nt.File is not null, "File should not be null"); 53 + assert(nt.Line == -1, "Line should default to -1"); 54 + assert(nt.Column == -1, "Column should default to -1"); 55 + } 56 + 57 + function test_ast_withpos_memcall[test] 58 + { 59 + var cv = 4; 60 + var ct1 = ast.with_pos("Constant",null,null,null,cv); 61 + 62 + assert(ct1 is Prexonite::Compiler::Ast::AstConstant, 63 + "ast\\withPos(\"Constant\") is not an AstConstant node"); 64 + assert(ct1.Constant == cv, "Constant value should be $cv"); 65 + assert(ct1.File is not null, "File should not be null"); 66 + assert(ct1.Line == -1, "Line should default to -1"); 67 + assert(ct1.Column == -1, "Column should default to -1"); 68 + 69 + var bf = "bfile.pxs"; 70 + var bl = 5; 71 + var bc = 7; 72 + var bt = ast.with_pos("GetSetMemberAccess",bf,bl,bc,Prexonite::Types::PCall.set,ct1,"ToString"); 73 + assert(bt is Prexonite::Compiler::Ast::AstGetSetMemberAccess, 74 + "ast\\withPos(\"GetSetMemberAccess\") is not an AstGetSetMemberAccess node."); 75 + assert(bt.File == bf, "File should be $bf"); 76 + assert(bt.Line == bl, "Line should be $bl"); 77 + assert(bt.Column == bc, "Column should be $bc"); 78 + assert(bt.Subject == ct1, "Subject should be $ct1"); 79 + assert(bt.Id == "ToString", "Id should be ToString"); 80 + assert(bt.Call~Int == Prexonite::Types::PCall.Set~Int, "Call should be PCall.Set"); 81 + } 82 + 83 + function test_ast_simple_memcall[test] 84 + { 85 + var cv = 4; 86 + var ct1 = ast.simple("Constant",cv); 87 + 88 + assert(ct1 is Prexonite::Compiler::Ast::AstConstant, 89 + "ast\\simple(\"Constant\") is not an AstConstant node"); 90 + assert(ct1.Constant == cv, "Constant value should be $cv"); 91 + assert(ct1.File is not null, "File should not be null"); 92 + assert(ct1.Line == -1, "Line should default to -1"); 93 + assert(ct1.Column == -1, "Column should default to -1"); 94 + 95 + var bl = -1; 96 + var bc = -1; 97 + var bt = ast.simple("GetSetMemberAccess",Prexonite::Types::PCall.set,ct1,"ToString"); 98 + assert(bt is Prexonite::Compiler::Ast::AstGetSetMemberAccess, 99 + "ast\\simple(\"GetSetMemberAccess\") is not an AstGetSetMemberAccess node."); 100 + assert(bt.File is not null, "File should not be null"); 101 + assert(bt.Line == bl, "Line should be $bl"); 102 + assert(bt.Line == bc, "Column should be $bc"); 103 + assert(bt.Subject == ct1, "Subject should be $ct1"); 104 + assert(bt.Id == "ToString", "Id should be ToString"); 105 + assert(bt.Call~Int == Prexonite::Types::PCall.Set~Int, "Call should be PCall.Set"); 106 + } 107 + 108 + function test_ast_memcall[test] 109 + { 110 + var cv = 4; 111 + var ct1 = ast.simple("Constant",cv); 112 + 113 + assert(ct1 is Prexonite::Compiler::Ast::AstConstant, 114 + "ast.simple(\"Constant\") is not an AstConstant node"); 115 + assert(ct1.Constant == cv, "Constant value should be $cv"); 116 + assert(ct1.File is not null, "File should not be null"); 117 + 118 + var bt = ast.simple("GetSetMemberAccess",Prexonite::Types::PCall.set,ct1,"ToString"); 119 + assert(bt is Prexonite::Compiler::Ast::AstGetSetMemberAccess, 120 + "ast.simple(\"GetSetMemberAccess\") is not an AstGetSetMemberAccess node."); 121 + assert(bt.File is not null, "File should not be null"); 122 + assert(bt.Subject == ct1, "Subject should be $ct1"); 123 + assert(bt.Id == "ToString", "Id should be ToString"); 124 + assert(bt.Call~Int == Prexonite::Types::PCall.Set~Int, "Call should be PCall.Set"); 125 + } 126 + 127 + function test_unique_id_counter[test] 128 + { 129 + var h = {}; 130 + var verb = "vvrb"; 131 + for(var i = 0; i < 50; i++) 132 + { 133 + h[var id = unique_id(verb)] = true; 134 + assert(id.Contains(verb),"Generated id '$(id)' must contain verb '$(verb)'."); 135 + } 136 + assert(h.Count == 50, "There are duplicate id's"); 137 + } 138 + 139 + function test_h_thisModule as thisModule = asm(ldr.app).Module.Name; 140 + 141 + function test_is_member_access[ 142 + is test; 143 + Add Prexonite to Imports; 144 + Add Prexonite::Compiler to Imports; 145 + Add Prexonite::Compiler::Ast to Imports; 146 + Add Prexonite::Types to Imports; 147 + ] 148 + { 149 + var nt = ast.simple("Null"); 150 + var mem = "member"; 151 + var memacc = ast.simple("GetSetMemberAccess", nt, mem); 152 + var wrongmemacc = ast.simple("GetSetMemberAccess", nt, "otherMember"); 153 + var notMemacc = ast\call(sys.ct.entityref_to(test_is_member_access)); 154 + 155 + assert(is_member_access(mem, memacc), "Should recognize $memacc"); 156 + assert(not is_member_access(mem, wrongmemacc), "Should reject $wrongmemacc"); 157 + assert(not is_member_access(mem, notMemacc), "Should reject $notMemacc"); 158 + } 159 + 160 + test_glob glob1; 161 + test_glob2 glob2; 162 + 163 + function test_local_meta[ 164 + test; 165 + test_glob2 glob3; 166 + ] 167 + { 168 + var ctx = ->test_local_meta; 169 + var actual = local_meta("test_glob", ctx).Text; 170 + assert(actual == "glob1", "Expected \"glob1\", actual $actual"); 171 + 172 + actual = local_meta("test_glob2", ctx).Text; 173 + assert(actual == "glob3", "Expected \"glob3\", actual $actual"); 174 + } 175 + 176 + function assert_seq(actual,expected,msg) = assert_eq(actual~Int, expected~Int,msg); 177 + function assert_sneq(actual,expected,msg) = assert_neq(actual~Int, expected~Int,msg); 178 + 179 + function test_si_fields[ 180 + test; 181 + Add Prexonite to Imports; 182 + Add Prexonite::Types to Imports; 183 + Add Prexonite::Compiler to Imports; 184 + Add Prexonite::Compiler::Ast to Imports; 185 + ] 186 + { 187 + assert_seq(SI.lvar, ::SymbolInterpretations.LocalObjectVariable); 188 + assert_seq(SI.lref, ::SymbolInterpretations.LocalReferenceVariable); 189 + assert_seq(SI.gvar, ::SymbolInterpretations.GlobalObjectVariable); 190 + assert_seq(SI.gref, ::SymbolInterpretations.GlobalReferenceVariable); 191 + assert_seq(SI.func, ::SymbolInterpretations.Function); 192 + assert_seq(SI.cmd, ::SymbolInterpretations.Command); 193 + assert_seq(SI.mcmd, ::SymbolInterpretations.MacroCommand); 194 + assert_seq(SI.get, ::PCall.Get); 195 + assert_seq(SI.set, ::PCall.Set); 196 + assert_seq(SI.ret\exit, ::ReturnVariant.Exit); 197 + assert_seq(SI.ret\set, ::ReturnVariant.Set); 198 + assert_seq(SI.ret\continue, ::ReturnVariant.Continue); 199 + assert_seq(SI.ret\break, ::ReturnVariant.Break); 200 + 201 + var x = "x"; 202 + assert_eq(SI.lvar(x), new ::SymbolEntry(::SymbolInterpretations.LocalObjectVariable,x,null)); 203 + assert_eq(SI.lref(x), new ::SymbolEntry(::SymbolInterpretations.LocalReferenceVariable,x,null)); 204 + assert_eq(SI.cmd(x), new ::SymbolEntry(::SymbolInterpretations.Command,x,null)); 205 + assert_eq(SI.mcmd(x), new ::SymbolEntry(::SymbolInterpretations.MacroCommand,x,null)); 206 + 207 + //macro specific 208 + assert_seq(SI.m.func, ::SymbolInterpretations.Function); 209 + assert_seq(SI.m.cmd, ::SymbolInterpretations.MacroCommand); 210 + assert_eq(SI.m.cmd(x), new ::SymbolEntry(::SymbolInterpretations.MacroCommand,x,null)); 211 + } 212 + 213 + function create_si_check(ctor, check, should_match) { 214 + var s = new Structure; 215 + s.\\("check") = (self,x) => check.(x); 216 + s.\\("value") = (self) => ctor.(); 217 + s.\\("should_match") = (self,x) => should_match.(x.ToString); 218 + s.\\("ToString") = (self) => 219 + ctor.Meta[Prexonite::PFunction.LogicalIdKey].Text; 220 + return s; 221 + } 222 + 223 + function test_si_is_star[ 224 + test; 225 + Add Prexonite to Imports; 226 + Add Prexonite::Types to Imports; 227 + Add Prexonite::Compiler to Imports; 228 + Add Prexonite::Compiler::Ast to Imports; 229 + ] 230 + { 231 + //SI.eq 232 + assert(SI.eq(SI.lvar, SI.lvar), "SI.lvar must be the same as SI.lvar"); 233 + assert(not SI.eq(SI.lvar, SI.lref),"SI.lvar != SI.lref"); 234 + 235 + //SI.is_* 236 + var mms = [ 237 + [SI.lvar(?), SI.is_lvar(?)], 238 + [SI.lref(?), SI.is_lref(?)], 239 + [SI.gvar(?), SI.is_gvar(?)], 240 + [SI.gref(?), SI.is_gref(?)], 241 + [SI.func(?), SI.is_func(?)], 242 + [SI.cmd(?), SI.is_cmd(?)], 243 + [SI.mcmd(?), SI.is_mcmd(?)], 244 + ] >> map(new si_check(*?)) >> to_list; 245 + foreach(var x in mms) 246 + foreach(var y in mms) 247 + { 248 + var actual = x.check(y.value); 249 + var expected = x.value~int == y.value~int; 250 + assert_eq(actual,expected,"Evaluating SI.is_$x(SI.$y)"); 251 + } 252 + 253 + var cs = [ 254 + [SI.lvar(?), SI.is_obj(?), ?.EndsWith("var")], 255 + [SI.lref(?), SI.is_ref(?), ?.EndsWith("ref")], 256 + [SI.gvar(?), SI.is_global(?), ?.StartsWith("g")], 257 + [SI.lvar(?), SI.is_local(?), ?.StartsWith("l")], 258 + ] >> map(new si_check(*?)) >> to_list; 259 + foreach(var c in cs) 260 + foreach(var x in mms) 261 + { 262 + var actual = c.check(x.value); 263 + var expected = c.should_match(x); 264 + assert_eq(actual,expected,"Evaluating SI.is_$c(SI.$x)"); 265 + } 266 + } 267 + 268 + function create_si_make(check, convert) { 269 + var s = new Structure; 270 + s.\\("check") = (self,x) => check.(x); 271 + s.\\("convert") = (self,x) => convert.(x); 272 + s.\\("ToString") = (self) => 273 + check.Meta[Prexonite::PFunction.LogicalIdKey].Text.Substring("is_".Length); 274 + return s; 275 + } 276 + 277 + function test_si_make_star[ 278 + test; 279 + Add Prexonite to Imports; 280 + Add Prexonite::Types to Imports; 281 + Add Prexonite::Compiler to Imports; 282 + Add Prexonite::Compiler::Ast to Imports; 283 + ] 284 + { 285 + var mms = [ 286 + [SI.lvar(?), SI.is_lvar(?)], 287 + [SI.lref(?), SI.is_lref(?)], 288 + [SI.gvar(?), SI.is_gvar(?)], 289 + [SI.gref(?), SI.is_gref(?)], 290 + ] >> map(new si_check(*?)) >> to_list; 291 + 292 + var silocal = new si_make(SI.is_local(?), SI.make_local(?)); 293 + var siglobal = new si_make(SI.is_global(?), SI.make_global(?)); 294 + var siobj = new si_make(SI.is_obj(?), SI.make_obj(?)); 295 + var siref = new si_make(SI.is_ref(?), SI.make_ref(?)); 296 + var kind = [ 297 + silocal:siglobal, 298 + siglobal:silocal, 299 + siobj:siref, 300 + siref:siobj 301 + ]; 302 + 303 + foreach(var m in mms) 304 + foreach(var k in kind) 305 + { 306 + var x = m.value; 307 + var oldState = {}; 308 + foreach(var k' in kind) 309 + oldState[k'.Key] = k'.Key.check(x); 310 + oldState[k.Key] = true; 311 + oldState[k.Value] = false; 312 + 313 + var y = k.Key.convert(x); 314 + kind >> each(k' => assert_eq(k'.Key.check(y), oldState[k'.Key], 315 + "SI.is_$(k'.Key)($y) after make_$(k.Key)($x)")); 316 + } 317 + } 318 + 319 + function test_si_m_is_star[test] 320 + { 321 + var mms = [ 322 + [SI.lvar(?), SI.is_lvar(?)], 323 + [SI.lref(?), SI.is_lref(?)], 324 + [SI.gvar(?), SI.is_gvar(?)], 325 + [SI.gref(?), SI.is_gref(?)], 326 + [SI.func(?), SI.is_func(?)], 327 + [SI.cmd(?), SI.is_cmd(?)], 328 + [SI.mcmd(?), SI.is_mcmd(?)], 329 + ] >> map(new si_check(*?)) >> to_list; 330 + var sifunc = mms[4]; 331 + var simcmd = mms[6]; 332 + var pps = [ 333 + new si_check(SI.m.func(?), SI.m.is_func(?)):sifunc, 334 + new si_check(SI.m.cmd(?), SI.m.is_cmd(?)):simcmd 335 + ]; 336 + 337 + foreach(var p in pps) 338 + foreach(var m in mms) 339 + { 340 + var x = m.value; 341 + var actual = p.Key.check(x); 342 + var expected = p.Value.check(x); 343 + assert_eq(actual,expected,"is_$(p.Key) == is_$(p.Value)"); 344 + } 345 + } 346 + 347 + function test_sub_blocks[test] 348 + { 349 + var ss = Prexonite::Compiler::Symbolic::SymbolStore.Create(null,null); 350 + var root = Prexonite::Compiler::Ast::AstBlock.CreateRootBlock(new Prexonite::Compiler::SourcePosition("-",-1,-1),ss,null,null); 351 + var ifBlock = ast.simple2("Condition",root,ast.simple("Null"),false); 352 + var acs = sub_blocks(ifBlock); 353 + assert_eq(acs[0], ifBlock.IfBlock); 354 + assert_eq(acs[1], ifBlock.ElseBlock); 355 + 356 + var notIfBlock = ast.simple("Constant", 2); 357 + assert_eq(sub_blocks(notIfBlock).Count, 0); 358 + }
+130
PrexoniteTests/psr-tests/_2/make_test_configuration.pxs
··· 1 + name psr_tests::make_test_configuration/2.0; 2 + references { 3 + prx::cli 4 + }; 5 + 6 + namespace psr.test.make_test_configuration 7 + import sys.*, 8 + sys.seq, 9 + sys.seq(to_list,skip,map, filter), 10 + prx.cli.host 11 + { 12 + 13 + function get_test_file_names(path,pattern)[import System::IO] = 14 + ::Directory.EnumerateFiles(path ?? ".", pattern ?? "*.test.pxs", ::SearchOption.AllDirectories); 15 + 16 + function under_test = "under_test"; 17 + function test_dependencies = "test_dependencies"; 18 + function config_file_separator = "|"; 19 + function config_section_separator = ">"; 20 + function config_dependency_separator = "<"; 21 + 22 + function create_config(testCases) 23 + { 24 + var s = new Structure; 25 + s.\("test_cases") = testCases; // ~[String] 26 + return s; 27 + } 28 + 29 + var no_cancellation = System::Threading::CancellationToken.None; 30 + 31 + function create_source_file(file_path) = 32 + Prexonite::Compiler::Build::Source.FromFile(file_path, 33 + static var utf8 ??= System::Text::Encoding.UTF8); 34 + 35 + function read_metadata(file_name)[import {Prexonite, Prexonite::Compiler}] 36 + { 37 + print("Reading $file_name ..."); 38 + var src = new source_file(file_name); 39 + var targetDescription = host.self_assembling_build_plan.AssembleAsync(src, no_cancellation).Result; 40 + var target = host.self_assembling_build_plan.BuildAsync(targetDescription.Name, no_cancellation).Result; 41 + println("done. ", if(target.IsSuccessful) "" else " There were errors:"); 42 + if(not target.IsSuccessful) { 43 + target.Messages >> seq.each(println(?)); 44 + if(target.Exception is not null) { 45 + println(target.Exception); 46 + } 47 + } 48 + 49 + var testCases = target.Module.Functions >> filter(f => f.Meta["test"].Switch) >> map(?.Id) >> to_list; 50 + 51 + println("\t", file_name," ",testCases.Count," test cases"); 52 + 53 + return new config(testCases); 54 + } 55 + 56 + //write_config writes the configuration <config> to the supplied <textWriter>. 57 + // - textWriter, an object that behaves like a System.IO.TextWriter 58 + // - config, [test_file_name:{test_cases}] 59 + function write_config(textWriter, config) 60 + { 61 + foreach(var kvp in config) 62 + { 63 + textWriter.Write(kvp.Key); 64 + textWriter.Write(config_section_separator); 65 + foreach(var d in kvp.Value.test_cases) 66 + textWriter.Write("$(config_file_separator)$(d)"); 67 + textWriter.WriteLine; 68 + } 69 + } 70 + 71 + function write_config_file(file_name, config)[import {System::IO, System::Text}] 72 + { 73 + using(var tw = new ::StreamWriter( 74 + new ::FileStream(file_name,::FileMode.Create,::FileAccess.Write), 75 + ::Encoding.UTF8)) 76 + write_config(tw, config); 77 + } 78 + 79 + function to_config(config) 80 + { 81 + var s; 82 + using(var sw = new ::StringWriter) 83 + { 84 + write_config(sw,config); 85 + s = sw.ToString; 86 + } 87 + return s; 88 + } 89 + 90 + function get_config(path) = 91 + get_test_file_names(path) >> map(tfn => tfn: read_metadata(tfn)); 92 + 93 + function main(path) 94 + { 95 + write_config_file("testconfig.txt",get_config(path)); 96 + } 97 + 98 + function read_config(textReader) 99 + { 100 + var config = []; 101 + var line; 102 + for(; do line = textReader.ReadLine; while line is not null and line.Length > 0) 103 + { 104 + var fs = line.Split(config_section_separator); 105 + if(fs.Count != 2) 106 + throw "Unexpected number of sections (separated by '$(config_section_separator)'). Expected 2. Line: $line"; 107 + 108 + config[] = fs[0]: new config( 109 + (fs[1].Split(config_file_separator) >> skip(1) >> to_list), 110 + ); 111 + } 112 + return config; 113 + } 114 + 115 + function read_config_file(fileName)[import {System::IO, System::Text}] 116 + { 117 + var c; 118 + using(var tr = new ::StreamReader( 119 + new ::FileStream(fileName, ::FileMode.Open, ::FileAccess.Read), 120 + ::Encoding.UTF8)) 121 + c = read_config(tr); 122 + 123 + return c; 124 + } 125 + 126 + } export(main, write_config_file, get_config, read_config, read_config_file, to_config, write_config, 127 + create_config, get_test_file_names, create_source_file); 128 + 129 + Entry make_test_configuration\main; 130 + function make_test_configuration\main = psr.test.make_test_configuration.main(*var args);
+115
PrexoniteTests/psr-tests/_2/run_tests.pxs
··· 1 + name psr_tests::run_tests/2.0; 2 + references { 3 + prx::cli, 4 + psr::test, 5 + @".\make_test_configuration.pxs" 6 + }; 7 + 8 + namespace psr_tests.run_tests 9 + import 10 + sys(*), 11 + sys.seq(*), 12 + sys.text(*), 13 + sys.rt(compile_to_cil), 14 + prx.cli(timer, host), 15 + psr.test.make_test_configuration(get_test_file_names, create_source_file) 16 + { 17 + 18 + var no_cancellation = System::Threading::CancellationToken.None; 19 + 20 + // load_from_descriptions~Dictionary<ModuleName, Tuple<Application, ITarget>> 21 + function load_from_descriptions(targetDescriptionTasks, cil_enabled) { 22 + var names = (targetDescriptionTasks >> map(t => t.Result.Name) >> to_list) 23 + ~Object<"System.Collections.Generic.IEnumerable`1[Prexonite.Modular.ModuleName]">; 24 + if(cil_enabled) { 25 + return Prexonite::Compiler::Cil::Compiler.CompileModulesAsync( 26 + host.self_assembling_build_plan, 27 + names, 28 + Prexonite::Compiler::Cil::FunctionLinking.FullyStatic, 29 + no_cancellation).Result; 30 + } else { 31 + // taskMap~Dictionary<ModuleName, Task<Tuple<Application, ITarget>>> 32 + var taskMap = host.self_assembling_build_plan.LoadAsync(names, no_cancellation); 33 + System::Threading::Tasks::Task.WaitAll(taskMap.Values >> map(?~Object<"System.Threading.Tasks.Task`1[System.Tuple`2[Prexonite.Application,Prexonite.Compiler.Build.ITarget]]">) >> to_list); 34 + var resultMap = new Object<"System.Collections.Generic.Dictionary`2[Prexonite.Modular.ModuleName,System.Tuple`2[Prexonite.Application,Prexonite.Compiler.Build.ITarget]]">; 35 + foreach(var entry in taskMap) { 36 + resultMap[entry.Key] = entry.Value.Result; 37 + } 38 + return resultMap; 39 + } 40 + } 41 + 42 + function main 43 + { 44 + print("Deriving build plan..."); 45 + var targetDescriptionTasks = []; 46 + timer.start; 47 + foreach(var file_path in get_test_file_names) { 48 + var src = new source_file(file_path); 49 + targetDescriptionTasks[] = host.self_assembling_build_plan.AssembleAsync(src, no_cancellation); 50 + } 51 + System::Threading::Tasks::Task.WaitAll(targetDescriptionTasks~Object<"System.Threading.Tasks.Task[]">); 52 + timer.stop; 53 + var totalCompTime = timer.elapsed; 54 + println("done."); 55 + timer.reset; 56 + 57 + print("Compiling $(targetDescriptionTasks.Count) test modules (and their dependencies)..."); 58 + timer.start; 59 + var testSuiteMap = load_from_descriptions(targetDescriptionTasks, var args >> exists(?.Contains("cil"))); 60 + timer.stop; 61 + totalCompTime += timer.elapsed; 62 + println("done."); 63 + timer.reset; 64 + 65 + // Check for compile errors 66 + var success = true; 67 + foreach(var testSuite in testSuiteMap) { 68 + var target = testSuite.Value.Item2; 69 + if(target.IsSuccessful) { 70 + continue; 71 + } 72 + success = false; 73 + 74 + println("Failed to compile $(target.Name) or one of its dependencies:"); 75 + foreach(var m in target.Messages) { 76 + println(m); 77 + } 78 + if(target.Exception is not null) { 79 + println(target.Exception); 80 + } 81 + } 82 + if(not success) { 83 + throw "One or more test suites failed to compile."; 84 + } 85 + 86 + timer.start; 87 + foreach(var suite in testSuiteMap.Values) { 88 + psr.test.run_tests_in_app(suite.Item1); 89 + } 90 + timer.stop; 91 + var displayTotal = false; 92 + var total = 0; 93 + var fieldWidth = 6; 94 + 95 + if(totalCompTime is not null) 96 + { 97 + println("\tBuild : ",setright(fieldWidth,totalCompTime),"ms"); 98 + total += totalCompTime; 99 + displayTotal = true; 100 + } 101 + 102 + println("\tTests : ",setright(fieldWidth,timer.elapsed),"ms"); 103 + total += timer.elapsed; 104 + 105 + if(displayTotal) 106 + { 107 + println("\tOverall: ",setright(fieldWidth,total),"ms"); 108 + } 109 + 110 + timer.reset; 111 + } 112 + 113 + } export(main) 114 + 115 + function main does psr_tests.run_tests.main(*var args);
+1
PrexoniteTests/psr-tests/_2/testconfig.txt
··· 1 + .\ast.test.pxs>|compiler_is_loaded|test_ast_withpos_null|test_ast_withpos_memcall|test_ast_simple_memcall|test_ast_memcall|test_unique_id_counter|test_is_member_access|test_local_meta|test_si_fields|test_si_is_star|test_si_make_star|test_si_m_is_star|test_sub_blocks
+11 -3
PrexoniteTests/psr-tests/find-deficiencies.pxs
··· 1 + name psr_tests::find_deficiencies; 2 + references { 3 + prx::cli, 4 + prx/1.0 5 + }; 1 6 2 7 build does require("run_tests.pxs"); 3 8 4 - function main 9 + namespace import sys.*, sys.seq.*; 10 + 11 + Entry find_deficiencies\main; 12 + function find_deficiencies\main 5 13 { 6 14 println; 7 15 println("================= DEFICIENCIES ================"); 8 16 (asm(ldr.app).Functions) 9 - >> where(?.Meta then ?[Prexonite::PFunction.VolatileKey] then ?.Switch) 17 + >> filter(?.Meta then ?[Prexonite::PFunction.VolatileKey] then ?.Switch) 10 18 >> each(f => println(f,"\n\t",f.Meta[Prexonite::PFunction.DeficiencyKey].Text,"\n")); 11 19 } 12 20 13 - { CompileToCil; } 21 + { rt.compile_to_cil; }
+5 -3
PrexoniteTests/psr-tests/make_test_configuration.pxs
··· 6 6 { 7 7 8 8 function get_test_file_names(path,pattern)[import System::IO] = 9 - ::Directory.EnumerateFiles(path ?? ".", pattern ?? "*.test.pxs", ::SearchOption.AllDirectories); 9 + ::Directory.EnumerateFiles(path ?? ".", pattern ?? "*.test.pxs", ::SearchOption.AllDirectories) 10 + >> where(f => not (f.Contains(@"\\_2\\") or f.Contains("/_2/"))); 10 11 11 12 function under_test = "under_test"; 12 13 function test_dependencies = "test_dependencies"; ··· 163 164 return c; 164 165 } 165 166 166 - } export(main, write_config_file, get_config, read_config, read_config_file, to_config, write_config, create_config); 167 + } export(main, write_config_file, get_config, read_config, read_config_file, to_config, write_config, 168 + create_config, get_test_file_names); 167 169 168 - function main = sys.call(prx.test.make_test_configuration.main(?),var args); 170 + function main = prx.test.make_test_configuration.main(*var args);
+118 -85
PrexoniteTests/psr-tests/run_tests.pxs
··· 1 - var totalCompTime; 2 - 3 - build 4 - { 5 - function req_ex(path) 6 - { 7 - print("Begin compiling $path ..."); 8 - timer\start; 9 - require(path); 10 - timer\stop; 11 - println("done.\n\t",timer\elapsed,"ms"); 12 - totalCompTime += timer\elapsed; 13 - timer\reset; 14 - } 15 - 16 - ([ @"psr\ast.pxs", 17 - @"psr\test.pxs", 18 - @"ast.test.pxs", 19 - 20 - @"psr\macro.pxs", 21 - @"psr\test\meta_macro.pxs", 22 - @"macro.test.pxs", 23 - 24 - @"psr\struct.pxs", 25 - @"psr\stack.pxs", 26 - @"psr\queue.pxs", 27 - @"psr\set.pxs", 28 - @"struct.test.pxs", 29 - 30 - @"psr\prop.pxs", 31 - @"psr\pattern.pxs", 32 - @"lang-ext.test.pxs", 33 - 34 - @"psr\misc.pxs", 35 - @"misc.test.pxs", 36 - ]) >> each(req_ex(?)); 37 - 38 - println("Total compilation time: $(totalCompTime)ms"); 39 - 40 - (asm(ldr.app)).Functions.Remove(->req_ex); 41 - } 42 - 43 - function main 44 - { 45 - var cilTime = null; 46 - if(var args >> exists(?.Contains("cil"))) 47 - { 48 - print("Compiling to CIL..."); 49 - timer\start; 50 - CompileToCil; 51 - timer\stop; 52 - println("done.\n\t",cilTime = timer\elapsed,"ms"); 53 - timer\reset; 54 - } 55 - timer\start; 56 - run_tests; 57 - timer\stop; 58 - var displayTotal = false; 59 - var total = 0; 60 - var fieldWidth = 6; 61 - 62 - if(totalCompTime is not null) 63 - { 64 - println("\tBuild : ",setright(fieldWidth,totalCompTime),"ms"); 65 - total += totalCompTime; 66 - displayTotal = true; 67 - } 68 - 69 - if(cilTime is not null) 70 - { 71 - println("\tCil : ",setright(fieldWidth,cilTime),"ms"); 72 - total += cilTime; 73 - displayTotal = true; 74 - } 75 - 76 - println("\tTests : ",setright(fieldWidth,timer\elapsed),"ms"); 77 - total += timer\elapsed; 78 - 79 - if(displayTotal) 80 - { 81 - println("\tOverall: ",setright(fieldWidth,total),"ms"); 82 - } 83 - 84 - timer\reset; 85 - } 1 + name psr_tests::run_tests; 2 + references { 3 + prx::cli, 4 + prx/1.0 5 + }; 6 + 7 + namespace psr_tests.run_tests 8 + import 9 + sys(*), 10 + sys.seq(*), 11 + sys.text(*), 12 + sys.rt(compile_to_cil), 13 + prx.cli(timer) 14 + { 15 + 16 + var totalCompTime; 17 + 18 + namespace v1 19 + import prx.v1(*) 20 + { 21 + build 22 + { 23 + var eng = asm(ldr.eng); 24 + function req_ex(path) 25 + { 26 + print("Begin compiling $path ..."); 27 + timer.start; 28 + require(path); 29 + timer.stop; 30 + println("done.\n\t",timer.elapsed,"ms"); 31 + totalCompTime += timer.elapsed; 32 + timer.reset; 33 + } 34 + 35 + ([ @"psr\ast.pxs", 36 + @"psr\test.pxs", 37 + @"ast.test.pxs", 38 + 39 + @"psr\macro.pxs", 40 + @"psr\test\meta_macro.pxs", 41 + @"macro.test.pxs", 42 + 43 + @"psr\struct.pxs", 44 + @"psr\stack.pxs", 45 + @"psr\queue.pxs", 46 + @"psr\set.pxs", 47 + @"struct.test.pxs", 48 + 49 + @"psr\prop.pxs", 50 + @"psr\pattern.pxs", 51 + @"lang-ext.test.pxs", 52 + 53 + @"psr\misc.pxs", 54 + @"misc.test.pxs", 55 + ]) >> each(req_ex(?)); 56 + 57 + println("Total compilation time: $(totalCompTime)ms"); 58 + 59 + var app = asm(ldr.app); 60 + app.Functions.Remove(->req_ex); 61 + app.Meta["totalCompTime"] = totalCompTime.ToString~Prexonite::MetaEntry; 62 + } 63 + 64 + { 65 + var app = asm(ldr.app); 66 + if(app.Meta["totalCompTime"].Text.Length > 0) { 67 + totalCompTime = app.Meta["totalCompTime"].Text~Int; 68 + } 69 + } 70 + } 71 + 72 + function main 73 + { 74 + var cilTime = null; 75 + if(var args >> exists(?.Contains("cil"))) 76 + { 77 + print("Compiling to CIL..."); 78 + timer.start; 79 + compile_to_cil; 80 + timer.stop; 81 + println("done.\n\t",cilTime = timer.elapsed,"ms"); 82 + timer.reset; 83 + } 84 + timer.start; 85 + v1.run_tests; 86 + timer.stop; 87 + var displayTotal = false; 88 + var total = 0; 89 + var fieldWidth = 6; 90 + 91 + if(totalCompTime is not null) 92 + { 93 + println("\tBuild : ",setright(fieldWidth,totalCompTime),"ms"); 94 + total += totalCompTime; 95 + displayTotal = true; 96 + } 97 + 98 + if(cilTime is not null) 99 + { 100 + println("\tCil : ",setright(fieldWidth,cilTime),"ms"); 101 + total += cilTime; 102 + displayTotal = true; 103 + } 104 + 105 + println("\tTests : ",setright(fieldWidth,timer.elapsed),"ms"); 106 + total += timer.elapsed; 107 + 108 + if(displayTotal) 109 + { 110 + println("\tOverall: ",setright(fieldWidth,total),"ms"); 111 + } 112 + 113 + timer.reset; 114 + } 115 + 116 + } 117 + 118 + function main does psr_tests.run_tests.main(*var args);
+6
Prx/Program.cs
··· 109 109 private static Application _loadApplication(Engine engine, PrexoniteConsole prexoniteConsole) 110 110 { 111 111 var plan = Plan.CreateSelfAssembling(); 112 + var opts = new LoaderOptions(engine, null); 113 + if (plan.Options != null) 114 + { 115 + opts.InheritFrom(plan.Options); 116 + } 117 + plan.Options = opts; 112 118 113 119 #region Stopwatch commands 114 120
+18 -6
Prx/psr/_2/psr/test.pxs
··· 4 4 }; 5 5 test\version "0.2"; 6 6 7 - namespace psr.test.v1 { 7 + namespace psr.test.v1 8 + import prx.v1(*) 9 + { 8 10 // NOTE: test is not split up into impl and dependencies because it must not 9 11 // have any dependencies. 10 12 build does add("../../test.pxs"); 11 13 } 12 14 13 15 namespace psr.test {} export psr.test.v1( 14 - test\run_test => run_test, 15 - test\run_tests => run_tests, 16 - test\list_tests => list_tests, 17 - test\load_plugins => load_plugins 16 + run_test, 17 + run_tests, 18 + list_tests, 19 + load_plugins, 20 + test\diagnostics => diagnostics 18 21 ); 19 22 20 23 namespace psr.test 21 24 import sys(*) 22 25 { 23 - function test_filters = psr.test.v1.test\test_filters >> seq.to_list; 26 + function test_filters = psr.test.v1.test_filters >> seq.to_list; 27 + 28 + function run_tests_in_app(app) { 29 + var self_name = asm(ldr.app).Module.Name; 30 + var test_subsystem; 31 + if(not app.Compound.TryGetApplication(self_name, test_subsystem = ?)){ 32 + throw "The $(app.Module.Name) application is not linked to the $self_name module. Cannot run tests."; 33 + } 34 + return test_subsystem.Functions[psr.test.run_tests(?).Id].(); 35 + } 24 36 } 25 37 26 38 namespace psr.test.ui {} export psr.test.v1(
+1 -1
Prx/psr/impl/macro.pxs
··· 1343 1343 // This block will be the root block of a function. 1344 1344 // The AST factory API does not support construction of root blocks, 1345 1345 // since that is not something that an ordinary macro does. 1346 - var block = Prexonite::Compielr::Ast::AstBlock.CreateRootBlock( 1346 + var block = Prexonite::Compiler::Ast::AstBlock.CreateRootBlock( 1347 1347 expr.Position, 1348 1348 Prexonite::Compiler::Symbolic::SymbolStore.Create(loader.Symbols,null), 1349 1349 "Block",
+20 -10
Prx/psr/test.pxs
··· 50 50 declare function test\basic_ui; 51 51 declare test\basic_ui as basic_ui; 52 52 53 + var test\diagnostics = false; 54 + 53 55 function test\load_plugins 54 56 { 55 57 static var loaded ??= false; ··· 61 63 return coroutine () => { 62 64 foreach(var x in xs) 63 65 { 64 - println(f.(x)); 66 + if(test\diagnostics) { 67 + println(f.(x)); 68 + } 65 69 yield x; 66 70 } 67 71 }; ··· 69 73 70 74 var plugins_key = @"test\plugins"; 71 75 var app = asm(ldr.app); 72 - println("::>>TEST-PLUGINS (",app.Compound >> count,")"); 76 + if(test\diagnostics) { 77 + println("::>>TEST-PLUGINS (",app.Compound >> count,")"); 78 + } 73 79 74 80 app.Compound 75 81 >> trace(x => "comp: $(x.Module.Name)") ··· 84 90 >> seqconcat 85 91 >> trace(x => "init: $(x.Module.Name)") 86 92 >> each(?.EnsureInitialization(asm(ldr.eng))); 87 - println("::<<END TEST-PLUGINS"); 93 + if(test\diagnostics) { 94 + println("::<<END TEST-PLUGINS"); 95 + } 88 96 89 97 loaded = true; 90 98 } ··· 134 142 135 143 test\load_plugins; 136 144 137 - println("::>>TEST-FILTERS"); 138 - test_filters >> each(println("\t-> ",?)); 139 - println("::<<END TEST-FILTERS"); 145 + if(test\diagnostics) { 146 + println("::>>TEST-FILTERS"); 147 + test_filters >> each(println("\t-> ",?)); 148 + println("::<<END TEST-FILTERS"); 149 + } 140 150 function create_transparent_wrapper(inner, original, filter) { 141 151 var s = new Structure; 142 152 s.\\("Call") = (self,id) => call\member(original, id, var args >> skip(2)); ··· 159 169 { 160 170 var tags = append(["test"], var args >> map(?~String)) >> all; 161 171 162 - return asm(ldr.app).Functions 163 - >> where(f => tags >> forall(f.Meta[?] then ?.Switch)); 172 + return asm(ldr.app).Compound 173 + >> flat_map(?.Functions) >> where(f => tags >> forall(f.Meta[?] then ?.Switch)); 164 174 } 165 175 166 - /// run_tests(ui~Structure, testFunc~IIndirectCall) 176 + /// run_tests(ui~Structure, tags...~String) 167 177 /// ui: a structure like the one returned from basic_ui 168 178 /// testFunc: the test code 169 179 /// run_tests(testFunc~IIndirectCall) ··· 186 196 187 197 ui.search_tests(args); 188 198 189 - var tests = call(list_tests(?),args) >> all; 199 + var tests = list_tests(*args) >> all; 190 200 191 201 ui.begin_suite(tests); 192 202
+1 -1
Prx/src/prx_interactive.pxs
··· 102 102 function prx\interactive() 103 103 { 104 104 if(supportsTabs) 105 - __console.Tab = ->tabHook; 105 + host.console.Tab = ->tabHook; 106 106 107 107 print( 108 108 "Entering Prexonite INTERACTIVE MODE.\n",
+26 -5
Prx/src/prx_lib.pxs
··· 27 27 namespace prx.cli 28 28 import sys.* 29 29 { 30 - //Access to an experimental terminal 31 - declare command __console; 32 - //Access to build infrastructure of the host 33 - declare command host\self_assembling_build_plan, host\prx_path; 30 + // Declare commands that are only available in the prx host. 31 + namespace timer { 32 + declare( 33 + start = ref command @"timer\start", 34 + stop = ref command @"timer\stop", 35 + reset = ref command @"timer\reset", 36 + elapsed = ref command @"timer\elapsed", 37 + ); 38 + } 39 + 40 + namespace host { 41 + declare( 42 + //Access to an experimental terminal 43 + console = ref command "__console", 44 + //Access to build infrastructure of the host 45 + prx_path = ref command @"host\prx_path", 46 + self_assembling_build_plan = ref command @"host\self_assembling_build_plan" 47 + ); 48 + } 49 + 50 + namespace benchmark { 51 + declare( 52 + create_benchmark = ref command "createBenchmark" 53 + ) 54 + } 34 55 35 56 //Not all environments may support colors... 36 57 var supportsColors = (supportsColors ?? true)~Bool; ··· 84 105 85 106 function readline = 86 107 if(supportsTabs) 87 - __console.ReadLine 108 + host.console.ReadLine 88 109 else 89 110 System::Console.ReadLine; 90 111
+8 -7
Prx/src/prx_main.pxs
··· 33 33 namespace prx.cli 34 34 import sys.*, 35 35 sys.seq.*, 36 + prx.cli(host), 36 37 prx.cli.repl(ldr,prx\interactive) 37 38 { 38 39 var engine = new Prexonite::Engine; //<-- the engine that we will run in ··· 62 63 //Set up the console 63 64 if(supportsTabs) 64 65 { 65 - __console.OutColor = ::ConsoleColor.White; 66 - __console.PromptColor = ::ConsoleColor.Red; 67 - __console.ErrorColor = ::ConsoleColor.Green; 68 - __console.DoBeep = false; 66 + host.console.OutColor = ::ConsoleColor.White; 67 + host.console.PromptColor = ::ConsoleColor.Red; 68 + host.console.ErrorColor = ::ConsoleColor.Green; 69 + host.console.DoBeep = false; 69 70 } 70 71 } 71 72 ··· 235 236 )+ ".c.pxs"; 236 237 237 238 // Set up search path 238 - var plan = host\self_assembling_build_plan; 239 - var prx_path = host\prx_path; 239 + var plan = host.self_assembling_build_plan; 240 + var prx_path = host.prx_path; 240 241 plan.SearchPaths.Add(System::IO::Path.Combine(prx_path, "psr", "_2")); 241 242 plan.SearchPaths.Add(System::Environment.CurrentDirectory); 242 243 searchPaths >> each(plan.SearchPaths.Add(?)); ··· 471 472 // Additionally, programs could access prx.cli code at no additional cost, 472 473 // since it has also been assembled via that plan. 473 474 // The application would not have access to state of this instance of prx.cli, however. 474 - var plan = host\self_assembling_build_plan; 475 + var plan = host.self_assembling_build_plan; 475 476 var target; 476 477 function is_info(msg) = msg.Severity~Int == Prexonite::Compiler::MessageSeverity.Info; 477 478 function is_warning(msg) = msg.Severity~Int == Prexonite::Compiler::MessageSeverity.Warning;