AspectedRouting/AspectedRouting/Program.cs

356 lines
12 KiB
C#
Raw Normal View History

2020-04-30 17:23:44 +02:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AspectedRouting.IO;
2020-05-02 13:09:49 +02:00
using AspectedRouting.IO.itinero1;
using AspectedRouting.IO.itinero2;
2020-05-02 13:09:49 +02:00
using AspectedRouting.IO.jsonParser;
using AspectedRouting.Language;
using AspectedRouting.Language.Expression;
using AspectedRouting.Tests;
2020-04-30 17:23:44 +02:00
namespace AspectedRouting
{
public static class Program
2020-04-30 17:23:44 +02:00
{
public static List<(AspectMetadata aspect, AspectTestSuite tests)> ParseAspects(
this IEnumerable<string> jsonFileNames, List<string> testFileNames, Context context)
2020-04-30 17:23:44 +02:00
{
var aspects = new List<(AspectMetadata aspect, AspectTestSuite tests)>();
2020-05-02 13:09:49 +02:00
foreach (var file in jsonFileNames)
2020-04-30 17:23:44 +02:00
{
var fi = new FileInfo(file);
2020-04-30 17:23:44 +02:00
var aspect = JsonParser.AspectFromJson(context, File.ReadAllText(file), fi.Name);
if (aspect == null) continue;
2020-05-02 13:09:49 +02:00
var testName = aspect.Name + ".test.csv";
var testPath = testFileNames.FindTest(testName);
AspectTestSuite tests = null;
if (!string.IsNullOrEmpty(testPath) && File.Exists(testPath))
{
tests = AspectTestSuite.FromString(aspect, File.ReadAllText(testPath));
2020-04-30 17:23:44 +02:00
}
aspects.Add((aspect, tests));
2020-04-30 17:23:44 +02:00
}
2020-05-02 13:09:49 +02:00
return aspects;
}
private static string FindTest(this IEnumerable<string> testFileNames, string testName)
{
var testPaths = testFileNames.Where(nm => nm.EndsWith(testName)).ToList();
if (testPaths.Count > 1)
{
Console.WriteLine("[WARNING] Multiple tests found for " + testName + ", using only one arbitrarily");
}
if (testPaths.Count > 0)
{
return testPaths.First();
}
return null;
}
2020-05-02 13:09:49 +02:00
private static List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)> ParseProfiles(
IEnumerable<string> jsonFiles, IReadOnlyCollection<string> testFiles, Context context)
2020-05-02 13:09:49 +02:00
{
var result = new List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)>();
2020-05-04 17:41:48 +02:00
foreach (var jsonFile in jsonFiles)
2020-04-30 17:23:44 +02:00
{
2020-05-04 17:41:48 +02:00
try
2020-04-30 17:23:44 +02:00
{
2020-05-04 17:41:48 +02:00
var profile =
JsonParser.ProfileFromJson(context, File.ReadAllText(jsonFile), new FileInfo(jsonFile));
if (profile == null)
{
continue;
}
profile.SanityCheckProfile(context);
var profileTests = new List<BehaviourTestSuite>();
2020-05-04 17:41:48 +02:00
foreach (var behaviourName in profile.Behaviours.Keys)
{
var path = testFiles.FindTest($"{profile.Name}.{behaviourName}.behaviour_test.csv");
if (path != null && File.Exists(path))
2020-05-04 17:41:48 +02:00
{
var test = BehaviourTestSuite.FromString(context, profile, behaviourName,
2020-05-04 17:41:48 +02:00
File.ReadAllText(path));
profileTests.Add(test);
}
else
{
Console.WriteLine($"[{profile.Name}] WARNING: no test found for behaviour {behaviourName}");
}
}
result.Add((profile, profileTests));
2020-04-30 17:23:44 +02:00
}
2020-05-04 17:41:48 +02:00
catch (Exception e)
2020-05-02 13:09:49 +02:00
{
// PrintError(jsonFile, e);
throw new Exception("In the file " + jsonFile, e);
2020-05-02 13:09:49 +02:00
}
2020-04-30 17:23:44 +02:00
}
2020-05-04 17:41:48 +02:00
return result;
}
private static void Repl(Context c, Dictionary<string, ProfileMetaData> profiles)
2020-05-11 13:40:14 +02:00
{
var profile = profiles["bicycle"];
2020-05-11 13:40:14 +02:00
var behaviour = profile.Behaviours.Keys.First();
do
{
Console.Write(profile.Name + "." + behaviour + " > ");
2020-05-11 13:40:14 +02:00
var read = Console.ReadLine();
if (read == null)
{
return; // End of stream has been reached
}
2020-09-30 13:35:30 +02:00
if (read == "")
{
Console.WriteLine("looƆ sᴉ dɐWʇǝǝɹʇSuǝdO");
continue;
}
2020-05-11 13:40:14 +02:00
if (read.Equals("quit"))
{
return;
}
if (read.Equals("clear"))
{
for (int i = 0; i < 80; i++)
{
Console.WriteLine();
}
continue;
}
2020-05-11 13:40:14 +02:00
if (read.StartsWith("select"))
{
var beh = read.Substring("select".Length + 1).Trim();
if (beh.Contains("."))
{
var profileName = beh.Split(".")[0];
if (!profiles.TryGetValue(profileName, out profile))
{
Console.Error.WriteLine("Profile " + profileName + " not found, ignoring");
continue;
}
beh = beh.Substring(beh.IndexOf(".") + 1);
}
2020-05-11 13:40:14 +02:00
if (profile.Behaviours.ContainsKey(beh))
{
behaviour = beh;
Console.WriteLine("Switched to " + beh);
}
else
{
Console.WriteLine("Behaviour not found. Known behaviours are:\n " +
string.Join("\n ", profile.Behaviours.Keys));
2020-05-11 13:40:14 +02:00
}
2020-05-11 13:40:14 +02:00
continue;
}
var tagsRaw = read.Split(";").Select(s => s.Trim());
var tags = new Dictionary<string, string>();
foreach (var str in tagsRaw)
{
2020-09-30 13:35:30 +02:00
if (str == "")
{
continue;
}
2020-05-11 13:40:14 +02:00
var strSplit = str.Split("=");
var k = strSplit[0].Trim();
var v = strSplit[1].Trim();
tags[k] = v;
}
try
{
var result = profile.Run(c, behaviour, tags);
Console.WriteLine(result);
}
catch (Exception e)
{
Console.WriteLine(e);
2020-05-11 13:40:14 +02:00
Console.WriteLine(e.Message);
}
} while (true);
}
2020-05-04 17:41:48 +02:00
private static void PrintError(string file, Exception exception)
{
var msg = exception.Message;
while (exception.InnerException != null)
{
exception = exception.InnerException;
msg += "\n " + exception.Message;
}
Console.WriteLine($"Error in the file {file}:\n {msg}");
2020-05-02 13:09:49 +02:00
}
2020-04-30 17:23:44 +02:00
private static void PrintUsedTags(ProfileMetaData profile, Context context)
{
Console.WriteLine("\n\n\n---------- " + profile.Name + " --------------");
foreach (var (key, values) in profile.AllExpressions(context).PossibleTags())
{
var vs = "*";
if (values.Any())
{
vs = string.Join(", ", values);
}
Console.WriteLine(key + ": " + vs);
}
Console.WriteLine("\n\n\n------------------------");
}
static void Main(string[] args)
2020-05-02 13:09:49 +02:00
{
var errMessage = MainWithError(args);
if (errMessage != null)
{
Console.WriteLine(errMessage);
}
}
public static string MainWithError(string[] args){
if (args.Length < 2)
{
return "Usage: <directory where all aspects and profiles can be found> <outputdirectory>";
}
2020-05-02 13:09:49 +02:00
var inputDir = args[0];
var outputDir = args[1];
2020-05-11 13:40:14 +02:00
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
2020-05-11 13:40:14 +02:00
MdPrinter.GenerateHelpText(outputDir + "helpText.md");
2020-04-30 17:23:44 +02:00
var files = Directory.EnumerateFiles(inputDir, "*.json", SearchOption.AllDirectories)
.ToList();
2020-05-11 13:40:14 +02:00
2020-09-30 13:35:30 +02:00
var tests = Directory.EnumerateFiles(inputDir, "*.csv", SearchOption.AllDirectories)
.ToList();
2020-09-30 13:35:30 +02:00
foreach (var test in tests)
{
if (test.EndsWith(".test.csv") || test.EndsWith(".behaviour_test.csv"))
{
continue;
}
throw new ArgumentException(
$"Invalid name for csv file ${test}, should end with either '.behaviour_test.csv' or '.test.csv'");
}
2020-05-02 13:09:49 +02:00
var context = new Context();
2020-04-30 17:23:44 +02:00
var aspects = ParseAspects(files, tests, context);
2020-04-30 17:23:44 +02:00
2020-05-04 17:41:48 +02:00
foreach (var (aspect, _) in aspects)
{
context.AddFunction(aspect.Name, aspect);
}
var profiles = ParseProfiles(files, tests, context);
2020-05-04 17:41:48 +02:00
// With everything parsed and typechecked, time for tests
var testsOk = true;
2020-05-02 13:09:49 +02:00
foreach (var (aspect, t) in aspects)
2020-04-30 17:23:44 +02:00
{
2020-05-02 13:09:49 +02:00
if (t == null)
{
Console.WriteLine($"[{aspect.Name}] WARNING: no tests found: please add {aspect.Name}.test.csv");
}
else
{
testsOk &= t.Run();
2020-05-02 13:09:49 +02:00
}
2020-04-30 17:23:44 +02:00
}
2020-09-30 13:35:30 +02:00
2020-05-04 17:41:48 +02:00
foreach (var (profile, profileTests) in profiles)
2020-04-30 17:23:44 +02:00
{
2020-05-04 17:41:48 +02:00
foreach (var test in profileTests)
{
testsOk &= test.Run(context);
2020-05-04 17:41:48 +02:00
}
}
2020-05-02 13:09:49 +02:00
if (!testsOk)
{
return "Some tests failed, quitting now without generating output";
}
2020-05-28 19:00:15 +02:00
foreach (var (profile, profileTests) in profiles)
{
PrintUsedTags(profile, context);
2020-05-28 19:00:15 +02:00
var aspectTests = aspects.Select(a => a.tests).ToList();
var luaProfile = new LuaPrinter1(profile, context,
aspectTests,
profileTests
).ToLua();
File.WriteAllText(outputDir + "/" + profile.Name + ".lua", luaProfile);
2020-05-28 19:00:15 +02:00
foreach (var (behaviourName, _) in profile.Behaviours)
{
var lua2behaviour = new LuaPrinter2(
profile,
behaviourName,
context,
aspectTests,
profileTests.Where(testsSuite => testsSuite.BehaviourName == behaviourName)
).ToLua();
if(!Directory.Exists($"{outputDir}/itinero2/"))
{
Directory.CreateDirectory($"{outputDir}/itinero2/");
}
File.WriteAllText(
$"{outputDir}/itinero2/{profile.Name}.{behaviourName}.lua",
lua2behaviour);
}
2020-05-04 17:41:48 +02:00
}
2020-05-11 13:40:14 +02:00
File.WriteAllText($"{outputDir}/ProfileMetadata.json",
2020-09-30 13:35:30 +02:00
Utils.GenerateExplanationJson(profiles.Select(p => p.profile))
);
if (!args.Contains("--no-repl"))
{
Repl(context, profiles
.Select(p => p.profile)
.ToDictionary(p => p.Name, p => p));
2020-09-30 13:35:30 +02:00
}
else
{
Console.WriteLine("Not starting REPL as --no-repl is specified");
}
return null;
2020-04-30 17:23:44 +02:00
}
}
}