envlang-csharp/main.cs
2020-09-01 13:05:15 +00:00

113 lines
3.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using SearchOption = System.IO.SearchOption;
using Compiler = System.Func<Ast.AstNode, string>;
using static Global;
public static class MainClass {
public static readonly Dir tests = Dir("Tests/");
public static readonly Dir tests_results = Dir("tests_results/");
public static void CompileToFile (Compiler compile, File source, File dest) {
source
.Read()
.Pipe(Parser.Parse)
.Pipe(compile)
.Pipe(c => dest.Write(c));
}
public static bool RunTest(string toolchainName, Compiler compile, Exe runner, File source) {
var destPath = tests_results.Combine(source);
var sourcePath = tests.Combine(source);
var expected = sourcePath.DropExtension().Combine(Ext(".o"));
Console.Write($"\x1b[KRunning test {source} ({toolchainName}) ");
destPath.DirName().Create();
UserErrorException exception = null;
try {
CompileToFile(compile, sourcePath, destPath);
} catch (UserErrorException e) {
exception = e;
}
if (exception != null) {
Console.WriteLine("");
Console.WriteLine("\x1b[1;31mFail\x1b[m");
Console.WriteLine($"\x1b[1;33m{exception.Message}\x1b[m\n");
return false;
} else {
var actualStr = runner.Run(destPath);
var expectedStr = expected.Read();
if (actualStr != expectedStr) {
Console.WriteLine("\x1b[1;31mFail\x1b[m");
Console.WriteLine($"\x1b[1;33m{source}: expected {expectedStr} but got {actualStr}.\x1b[m\n");
return false;
} else {
Console.Write("\x1b[1;32mOK\x1b[m\n"); // \r at the end for quiet
return true;
}
}
}
public static void RunTests() {
// Circumvent bug with collection initializers, tuples and
// first-class functions by using repeated .Add()
// See https://repl.it/@suzannesoy/WarlikeWorstTraining#main.cs
var compilers = ImmutableList<Tuple<string, Compiler, Exe>>.Empty
.Add(" js ", Compilers.JS.Compile, Exe("node"))
.Add("eval", Evaluator.EvaluateWrap, Exe("cat"));
var total = 0;
var passed = 0;
var failed = 0;
foreach (var t in Dir("Tests/").GetFiles("*.e", SearchOption.AllDirectories).OrderBy(f => f.ToString())) {
foreach (var compiler in compilers) {
if (RunTest(compiler.Item1, compiler.Item2, compiler.Item3, t)) {
passed++;
} else {
failed++;
}
total++;
}
}
Console.WriteLine($"\x1b[K{passed}/{total} tests passed, {failed} failed.");
if (failed != 0) {
Environment.Exit(1);
}
}
public static void Main (string[] args) {
try {
if (args.Length != 1) {
Console.WriteLine("Usage: mono main.exe path/to/file.e");
Console.WriteLine("");
Console.WriteLine("Language syntax:");
Console.WriteLine("");
Console.WriteLine(" Expression =");
Console.WriteLine(" Int");
Console.WriteLine(" | String");
Console.WriteLine(" | true");
Console.WriteLine(" | false");
Console.WriteLine(" | Expression && Expression");
Console.WriteLine("");
Console.WriteLine("I'll run the tests for you in the meanwhile.");
Console.WriteLine("");
RunTests();
} else {
var source = args[0].File();
var destPrefix = source.DropExtension();
CompileToFile(Compilers.JS.Compile, source, destPrefix.Combine(Ext(".js")));
CompileToFile(Evaluator.EvaluateWrap, source, destPrefix.Combine(Ext(".txt")));
Console.Write(destPrefix.Combine(Ext(".txt")).Read());
}
} catch (UserErrorException e) {
Console.WriteLine("");
Console.WriteLine($"\x1b[1;33m{e.Message}\x1b[m\n");
Environment.Exit(1);
}
}
}