diff --git a/AspectedRouting.Test/Snippets/SnippetTests.cs b/AspectedRouting.Test/Snippets/SnippetTests.cs index cbfabe4..a54eaaf 100644 --- a/AspectedRouting.Test/Snippets/SnippetTests.cs +++ b/AspectedRouting.Test/Snippets/SnippetTests.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using AspectedRouting.IO.LuaSkeleton; using AspectedRouting.IO.LuaSnippets; @@ -94,4 +95,26 @@ public class SnippetTests } + [Fact] + public void ListDotWithHead_GeneratesLua() + { + // (dot head) (stringToTags (mapping speed $ parse)) + var eSub = Funcs.Dot.Apply(Funcs.Head, + new Constant(new[] + { + Funcs.Head.Apply(Funcs.StringStringToTags.Apply( + new Mapping(new List<string> { "_speed" }, new[] { Funcs.Parse }))), + Funcs.Const.Apply(new Constant(Typs.Double, 42)) + }) + ); + var condition = Funcs.Dot.Apply(Funcs.Head, Funcs.StringStringToTags.Apply( + new Mapping(new[] { "route" }, new[] { Funcs.Eq.Apply(new Constant("ferry")) }))); + var e = + Funcs.IfDotted.Apply(condition, eSub); + e = e.Apply(new LuaLiteral(Typs.Tags, "tags")).Finalize().Optimize(out _); + var ctx = new Context(); + var lua = new LuaSkeleton(ctx, true); + var code = IO.LuaSnippets.Snippets.Convert(lua, "varname", e); + Console.WriteLine(code); + } } \ No newline at end of file diff --git a/AspectedRouting/Printer.cs b/AspectedRouting/Printer.cs new file mode 100644 index 0000000..000f85c --- /dev/null +++ b/AspectedRouting/Printer.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using AspectedRouting.IO.itinero1; +using AspectedRouting.IO.itinero2; +using AspectedRouting.IO.md; +using AspectedRouting.Language; +using AspectedRouting.Language.Expression; +using AspectedRouting.Tests; + +namespace AspectedRouting +{ + /** + * Prints to the specified location + */ + public class Printer + { + private readonly List<(AspectMetadata aspect, AspectTestSuite tests)> _aspects; + private readonly Context _context; + private readonly string _outputDirectory; + private readonly ProfileMetaData _profile; + private readonly List<BehaviourTestSuite> _profileTests; + private readonly bool _includeTests; + + public Printer(string outputDirectory, ProfileMetaData profile, Context context, + List<(AspectMetadata aspect, AspectTestSuite tests)> aspects, + List<BehaviourTestSuite> profileTests, bool includeTests) + { + _outputDirectory = outputDirectory; + _profile = profile; + _context = context; + _aspects = aspects; + _profileTests = profileTests; + _includeTests = includeTests; + + + if (!Directory.Exists($"{outputDirectory}/profile-documentation/")) { + Directory.CreateDirectory($"{outputDirectory}/profile-documentation/"); + } + + if (!Directory.Exists($"{outputDirectory}/itinero1/")) { + Directory.CreateDirectory($"{outputDirectory}/itinero1/"); + } + + if (!Directory.Exists($"{outputDirectory}/itinero2/")) { + Directory.CreateDirectory($"{outputDirectory}/itinero2/"); + } + } + + public void PrintUsedTags() + { + var profile = _profile; + var context = _context; + Console.WriteLine("\n\n\n---------- " + profile.Name + + " : used tags and corresponding values --------------"); + 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------------------------"); + } + + public void WriteProfile1() + { + var aspectTests = _aspects.Select(a => a.tests).ToList(); + + var luaProfile = new LuaPrinter1(_profile, _context, + aspectTests, + _profileTests + ).ToLua(); + + var itinero1ProfileFile = Path.Combine($"{_outputDirectory}/itinero1/" + _profile.Name + ".lua"); + File.WriteAllText(itinero1ProfileFile, luaProfile); + Console.WriteLine($"Written {new FileInfo(itinero1ProfileFile).FullName}"); + } + + public void WriteAllProfile2() + { + foreach (var (behaviourName,_) in _profile.Behaviours) { + WriteProfile2(behaviourName); + } + } + + public void WriteProfile2(string behaviourName) + { + var aspectTests = _aspects.Select(a => a.tests).ToList(); + + var lua2behaviour = new LuaPrinter2( + _profile, + behaviourName, + _context, + aspectTests, + _profileTests.Where(testsSuite => testsSuite.BehaviourName == behaviourName), + _includeTests + ).ToLua(); + + var itinero2ProfileFile = Path.Combine($"{_outputDirectory}/itinero2/{_profile.Name}.{behaviourName}.lua"); + File.WriteAllText( + itinero2ProfileFile, + lua2behaviour); + Console.WriteLine($"Written {new FileInfo(itinero2ProfileFile).FullName}"); + + + } + + public void PrintMdInfo() + { + var profileMd = new MarkDownSection(); + profileMd.AddTitle(_profile.Name, 1); + + profileMd.Add(_profile.Description); + profileMd.AddTitle("Default parameters", 4); + profileMd.Add("| name | value | ", "| ---- | ---- | ", + string.Join("\n", + _profile.DefaultParameters.Select(delegate(KeyValuePair<string, IExpression> kv) + { + var v = kv.Value.Evaluate(_context); + if (!(v is string || v is int || v is double)) { + v = "_special value_"; + } + + return $" | {kv.Key} | {v} |"; + })) + ); + foreach (var (behaviourName, vars) in _profile.Behaviours) { + var behaviourMd = new ProfileToMD(_profile, behaviourName, _context); + + File.WriteAllText( + $"{_outputDirectory}/profile-documentation/{_profile.Name}.{behaviourName}.md", + behaviourMd.ToString()); + profileMd.AddTitle($"[{behaviourName}](./{_profile.Name}.{behaviourName}.md)", 2); + profileMd.Add(vars["description"].Evaluate(_context).ToString()); + profileMd.Add(behaviourMd.MainFormula()); + } + + File.WriteAllText( + $"{_outputDirectory}/profile-documentation/{_profile.Name}.md", + profileMd.ToString()); + } + } +} \ No newline at end of file diff --git a/AspectedRouting/Program.cs b/AspectedRouting/Program.cs index 34b580b..60aee5b 100644 --- a/AspectedRouting/Program.cs +++ b/AspectedRouting/Program.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using AspectedRouting.IO; -using AspectedRouting.IO.itinero1; using AspectedRouting.IO.itinero2; using AspectedRouting.IO.jsonParser; using AspectedRouting.IO.md; @@ -19,13 +18,11 @@ namespace AspectedRouting this IEnumerable<string> jsonFileNames, List<string> testFileNames, Context context) { var aspects = new List<(AspectMetadata aspect, AspectTestSuite tests)>(); - foreach (var file in jsonFileNames) - { + foreach (var file in jsonFileNames) { var fi = new FileInfo(file); var aspect = JsonParser.AspectFromJson(context, File.ReadAllText(file), fi.Name); - if (aspect == null) - { + if (aspect == null) { continue; } @@ -33,8 +30,7 @@ namespace AspectedRouting var testName = aspect.Name + ".test.csv"; var testPath = testFileNames.FindTest(testName); AspectTestSuite tests = null; - if (!string.IsNullOrEmpty(testPath) && File.Exists(testPath)) - { + if (!string.IsNullOrEmpty(testPath) && File.Exists(testPath)) { tests = AspectTestSuite.FromString(aspect, File.ReadAllText(testPath)); } @@ -47,13 +43,11 @@ namespace AspectedRouting private static string FindTest(this IEnumerable<string> testFileNames, string testName) { var testPaths = testFileNames.Where(nm => nm.EndsWith(testName)).ToList(); - if (testPaths.Count > 1) - { + if (testPaths.Count > 1) { Console.WriteLine("[WARNING] Multiple tests found for " + testName + ", using only one arbitrarily"); } - if (testPaths.Count > 0) - { + if (testPaths.Count > 0) { return testPaths.First(); } @@ -66,43 +60,35 @@ namespace AspectedRouting { var result = new List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)>(); foreach (var jsonFile in jsonFiles) - { - try - { + try { var profile = JsonParser.ProfileFromJson(context, File.ReadAllText(jsonFile), new FileInfo(jsonFile), lastChange); - if (profile == null) - { + if (profile == null) { continue; } profile.SanityCheckProfile(context); var profileTests = new List<BehaviourTestSuite>(); - foreach (var behaviourName in profile.Behaviours.Keys) - { + foreach (var behaviourName in profile.Behaviours.Keys) { var path = testFiles.FindTest($"{profile.Name}.{behaviourName}.behaviour_test.csv"); - if (path != null && File.Exists(path)) - { + if (path != null && File.Exists(path)) { var test = BehaviourTestSuite.FromString(context, profile, behaviourName, File.ReadAllText(path)); profileTests.Add(test); } - else - { + else { Console.WriteLine($"[{profile.Name}] WARNING: no test found for behaviour {behaviourName}"); } } result.Add((profile, profileTests)); } - catch (Exception e) - { + catch (Exception e) { // PrintError(jsonFile, e); throw new Exception("In the file " + jsonFile, e); } - } return result; } @@ -111,28 +97,23 @@ namespace AspectedRouting { var profile = profiles["emergency_vehicle"]; var behaviour = profile.Behaviours.Keys.First(); - do - { + do { Console.Write(profile.Name + "." + behaviour + " > "); var read = Console.ReadLine(); - if (read == null) - { + if (read == null) { return; // End of stream has been reached } - if (read == "") - { + if (read == "") { Console.WriteLine("looƆ sᴉ dɐWʇǝǝɹʇSuǝdO"); continue; } - if (read.Equals("quit")) - { + if (read.Equals("quit")) { return; } - if (read.Equals("help")) - { + if (read.Equals("help")) { Console.WriteLine( Utils.Lines( "select <behaviourName> to change behaviour or <vehicle.behaviourName> to change vehicle", @@ -140,40 +121,31 @@ namespace AspectedRouting continue; } - if (read.Equals("clear")) - { - for (var i = 0; i < 80; i++) - { - Console.WriteLine(); - } + if (read.Equals("clear")) { + for (var i = 0; i < 80; i++) Console.WriteLine(); continue; } - if (read.StartsWith("select")) - { + if (read.StartsWith("select")) { var beh = read.Substring("select".Length + 1).Trim(); - if (beh.Contains(".")) - { + if (beh.Contains(".")) { var profileName = beh.Split(".")[0]; - if (!profiles.TryGetValue(profileName, out var newProfile)) - { + if (!profiles.TryGetValue(profileName, out var newProfile)) { Console.Error.WriteLine("Profile " + profileName + " not found, ignoring"); continue; } profile = newProfile; - beh = beh.Substring(beh.IndexOf(".") + 1); + beh = beh.Substring(beh.IndexOf(".", StringComparison.Ordinal) + 1); } - if (profile.Behaviours.ContainsKey(beh)) - { + if (profile.Behaviours.ContainsKey(beh)) { behaviour = beh; Console.WriteLine("Switched to " + beh); } - else - { + else { Console.WriteLine("Behaviour not found. Known behaviours are:\n " + string.Join("\n ", profile.Behaviours.Keys)); } @@ -184,34 +156,27 @@ namespace AspectedRouting var tagsRaw = read.Split(";").Select(s => s.Trim()); var tags = new Dictionary<string, string>(); - foreach (var str in tagsRaw) - { - if (str == "") - { + foreach (var str in tagsRaw) { + if (str == "") { continue; } - try - { - + try { var strSplit = str.Split("="); var k = strSplit[0].Trim(); var v = strSplit[1].Trim(); tags[k] = v; } - catch (Exception) - { + catch (Exception) { Console.Error.WriteLine("Could not parse tag: " + str); } } - try - { + try { var result = profile.Run(c, behaviour, tags); Console.WriteLine(result); } - catch (Exception e) - { + catch (Exception e) { Console.WriteLine(e); Console.WriteLine(e.Message); } @@ -221,8 +186,7 @@ namespace AspectedRouting private static void PrintError(string file, Exception exception) { var msg = exception.Message; - while (exception.InnerException != null) - { + while (exception.InnerException != null) { exception = exception.InnerException; msg += "\n " + exception.Message; } @@ -230,113 +194,30 @@ namespace AspectedRouting Console.WriteLine($"Error in the file {file}:\n {msg}"); } - private static void PrintUsedTags(ProfileMetaData profile, Context context) - { - Console.WriteLine("\n\n\n---------- " + profile.Name + " : used tags and corresponding values --------------"); - 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------------------------"); - } private static int Main(string[] args) { var errMessage = MainWithError(args); - if (errMessage == null) return 0; + if (errMessage == null) { + return 0; + } Console.WriteLine(errMessage); return 1; } + private static void WriteOutputFiles(Context context, List<(AspectMetadata aspect, AspectTestSuite tests)> aspects, string outputDir, List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)> profiles, bool includeTests) { - if (!Directory.Exists($"{outputDir}/profile-documentation/")) - { - Directory.CreateDirectory($"{outputDir}/profile-documentation/"); - } - - if (!Directory.Exists($"{outputDir}/itinero1/")) - { - Directory.CreateDirectory($"{outputDir}/itinero1/"); - } - - if (!Directory.Exists($"{outputDir}/itinero2/")) - { - Directory.CreateDirectory($"{outputDir}/itinero2/"); - } - - foreach (var (profile, profileTests) in profiles) - { - PrintUsedTags(profile, context); - - var aspectTests = aspects.Select(a => a.tests).ToList(); - var luaProfile = new LuaPrinter1(profile, context, - aspectTests, - profileTests - ).ToLua(); - - var itinero1ProfileFile = Path.Combine($"{outputDir}/itinero1/" + profile.Name + ".lua"); - File.WriteAllText(itinero1ProfileFile, luaProfile); - Console.WriteLine($"Written {(new FileInfo(itinero1ProfileFile)).FullName}"); - - var profileMd = new MarkDownSection(); - profileMd.AddTitle(profile.Name, 1); - - profileMd.Add(profile.Description); - profileMd.AddTitle("Default parameters", 4); - profileMd.Add("| name | value | ", "| ---- | ---- | ", - string.Join("\n", - profile.DefaultParameters.Select(delegate (KeyValuePair<string, IExpression> kv) - { - var v = kv.Value.Evaluate(context); - if (!(v is string || v is int || v is double)) - { - v = "_special value_"; - } - return $" | {kv.Key} | {v} |"; - })) - ); - - foreach (var (behaviourName, vars) in profile.Behaviours) - { - var lua2behaviour = new LuaPrinter2( - profile, - behaviourName, - context, - aspectTests, - profileTests.Where(testsSuite => testsSuite.BehaviourName == behaviourName), - includeTests - ).ToLua(); - - var itinero2ProfileFile = Path.Combine($"{outputDir}/itinero2/{profile.Name}.{behaviourName}.lua"); - File.WriteAllText( - itinero2ProfileFile, - lua2behaviour); - Console.WriteLine($"Written {(new FileInfo(itinero2ProfileFile)).FullName}"); - - var behaviourMd = new ProfileToMD(profile, behaviourName, context); - - File.WriteAllText( - $"{outputDir}/profile-documentation/{profile.Name}.{behaviourName}.md", - behaviourMd.ToString()); - profileMd.AddTitle($"[{behaviourName}](./{profile.Name}.{behaviourName}.md)", 2); - profileMd.Add(vars["description"].Evaluate(context).ToString()); - profileMd.Add(behaviourMd.MainFormula()); - } - - File.WriteAllText( - $"{outputDir}/profile-documentation/{profile.Name}.md", - profileMd.ToString()); + foreach (var (profile, profileTests) in profiles) { + var printer = new Printer(outputDir, profile, context, aspects, profileTests, includeTests); + printer.PrintUsedTags(); + printer.WriteProfile1(); + printer.PrintMdInfo(); + printer.WriteAllProfile2(); + printer.WriteProfile2("short"); } File.WriteAllText($"{outputDir}/ProfileMetadata.json", @@ -349,19 +230,18 @@ namespace AspectedRouting public static string MainWithError(string[] args) { - if (args.Length < 2) - { - return "Usage: <directory where all aspects and profiles can be found> <outputdirectory> [--include-tests]\n" + - "The flag '--include-tests' will append some self-tests in the lua files"; + if (args.Length < 2) { + return + "Usage: <directory where all aspects and profiles can be found> <outputdirectory> [--include-tests]\n" + + "The flag '--include-tests' will append some self-tests in the lua files"; } var inputDir = args[0]; var outputDir = args[1]; var includeTests = args.Contains("--include-tests"); var runRepl = !args.Contains("--no-repl"); - - if (!Directory.Exists(outputDir)) - { + + if (!Directory.Exists(outputDir)) { Directory.CreateDirectory(outputDir); } @@ -376,10 +256,8 @@ namespace AspectedRouting .ToList(); tests.Sort(); - foreach (var test in tests) - { - if (test.EndsWith(".test.csv") || test.EndsWith(".behaviour_test.csv")) - { + foreach (var test in tests) { + if (test.EndsWith(".test.csv") || test.EndsWith(".behaviour_test.csv")) { continue; } @@ -391,17 +269,12 @@ namespace AspectedRouting var aspects = ParseAspects(files, tests, context); - foreach (var (aspect, _) in aspects) - { - context.AddFunction(aspect.Name, aspect); - } + foreach (var (aspect, _) in aspects) context.AddFunction(aspect.Name, aspect); var lastChange = DateTime.UnixEpoch; - foreach (var file in files) - { + foreach (var file in files) { var time = new FileInfo(file).LastWriteTimeUtc; - if (lastChange < time) - { + if (lastChange < time) { lastChange = time; } } @@ -412,40 +285,32 @@ namespace AspectedRouting // With everything parsed and typechecked, time for tests var testsOk = true; foreach (var (aspect, t) in aspects) - { - if (t == null) - { + if (t == null) { Console.WriteLine($"[{aspect.Name}] WARNING: no tests found: please add {aspect.Name}.test.csv"); } - else - { + else { testsOk &= t.Run(); } - } foreach (var (profile, profileTests) in profiles) - foreach (var test in profileTests) - { - testsOk &= test.Run(context); - } + foreach (var test in profileTests) + testsOk &= test.Run(context); - if (testsOk) - { + if (testsOk) { WriteOutputFiles(context, aspects, outputDir, profiles, includeTests); } - if (runRepl) - { + if (runRepl) { Repl(context, profiles .Select(p => p.profile) .ToDictionary(p => p.Name, p => p)); } - else - { + else { Console.WriteLine("Not starting REPL as --no-repl is specified"); } + return !testsOk ? "Some tests failed, quitting now without generating output" : null; } }