From d990597b55bcde8defe9e713bc6425cd089d9cbe Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Thu, 27 Oct 2022 11:03:36 +0200 Subject: [PATCH 01/10] Expose parameters in obstacleAccess --- AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs b/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs index bcc318b..fcbbd51 100644 --- a/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs +++ b/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs @@ -90,14 +90,15 @@ If result.factor is positive, that is the cost. There is no forward or backward, so this should always be the same for the same attributes */ - + var parameters = _profile.Behaviours[_behaviourName]; var tags = new LuaLiteral(Typs.Tags, "attributes"); var hasAccess = _profile.ObstacleAccess.Apply(tags).SpecializeToSmallestType().Optimize(out _); var code = new List<string> { "--[[ Function called by itinero2 on every turn restriction relation", " ]]", "function turn_cost_factor(attributes, result)", - + " local parameters = default_parameters()", + _parameterPrinter.DeclareParametersFor(parameters), "local has_access", Snippets.Convert(_skeleton, "has_access", hasAccess), "if ( has_access == \"no\" or has_access == \"false\") then", From 86c62e520a5399fb721ad8caac4ba6008a1e400e Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Thu, 27 Oct 2022 13:34:00 +0200 Subject: [PATCH 02/10] Add obstacleAccess & obstracleCost to parameter checks --- AspectedRouting/Language/Analysis.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AspectedRouting/Language/Analysis.cs b/AspectedRouting/Language/Analysis.cs index 2609ae6..1a903b5 100644 --- a/AspectedRouting/Language/Analysis.cs +++ b/AspectedRouting/Language/Analysis.cs @@ -45,6 +45,8 @@ namespace AspectedRouting.Language AddParams(profile.Access, "profile definition for " + profile.Name + ".access"); AddParams(profile.Oneway, "profile definition for " + profile.Name + ".oneway"); AddParams(profile.Speed, "profile definition for " + profile.Name + ".speed"); + AddParams(profile.ObstacleAccess, "profile definition for " + profile.Name + ".obstacleaccess"); + AddParams(profile.ObstacleCost, "profile definition for " + profile.Name + ".obstaclecost"); foreach (var (key, expr) in profile.Priority) { From 717d0a951405d4dc6e99e6ce7c833c9aac566b54 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Thu, 27 Oct 2022 13:35:01 +0200 Subject: [PATCH 03/10] Fix: IfThenElseSnippted would also trigger if any string was specified as condition; this should only be if 'true' or '"yes"' --- AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs b/AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs index cebd784..1f447e4 100644 --- a/AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs +++ b/AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs @@ -53,7 +53,7 @@ namespace AspectedRouting.IO.LuaSnippets var isString = cond.Types.First().Equals(Typs.String); result += Snippets.Convert(lua, c, cond) + "\n"; - result += $"if ( {c} or {c} == \"yes\" ) then \n"; + result += $"if ( {c} == true or {c} == \"yes\" ) then \n"; result += " " + Snippets.Convert(lua, assignTo, ifTrue).Indent(); if (ifElse != null) From e9e53ac8b68c395260f768dea6c45683dcebec6c Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Thu, 27 Oct 2022 13:35:17 +0200 Subject: [PATCH 04/10] Fix typo in comments --- AspectedRouting/IO/lua/if_then_else_dotted.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AspectedRouting/IO/lua/if_then_else_dotted.lua b/AspectedRouting/IO/lua/if_then_else_dotted.lua index 018254e..4e56a0f 100644 --- a/AspectedRouting/IO/lua/if_then_else_dotted.lua +++ b/AspectedRouting/IO/lua/if_then_else_dotted.lua @@ -14,6 +14,6 @@ function if_then_else_dotted(conditionf, thnf, elsef, arg) if (condition) then return applyIfNeeded(thnf, arg) else - return applyIfNeeded(elsef, arg) -- if no third parameter is given, 'els' will be nil + return applyIfNeeded(elsef, arg) -- if no third parameter is given, 'else' will be nil end end \ No newline at end of file From 1eb4139174b60ebfe6ad9579b9de0812dabeca2b Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Thu, 27 Oct 2022 13:36:38 +0200 Subject: [PATCH 05/10] Selftests are only emitted (for Itinero2.0) if the approriate flag is specified, fix https://github.com/anyways-open/routing-profiles-aspects/issues/15 --- AspectedRouting/IO/itinero2/LuaPrinter2.cs | 75 +++++++++++++--------- AspectedRouting/Program.cs | 15 +++-- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/AspectedRouting/IO/itinero2/LuaPrinter2.cs b/AspectedRouting/IO/itinero2/LuaPrinter2.cs index dc3d50c..c7dbf46 100644 --- a/AspectedRouting/IO/itinero2/LuaPrinter2.cs +++ b/AspectedRouting/IO/itinero2/LuaPrinter2.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using AspectedRouting.IO.itinero1; @@ -29,7 +28,7 @@ namespace AspectedRouting.IO.itinero2 private readonly string _behaviourName; private readonly IEnumerable<BehaviourTestSuite> _behaviourTestSuite; private readonly Context _context; - private readonly DateTime _lastChangeTime; + private readonly bool _includeTests; private readonly LuaParameterPrinter _parameterPrinter; private readonly ProfileMetaData _profile; @@ -39,7 +38,7 @@ namespace AspectedRouting.IO.itinero2 public LuaPrinter2(ProfileMetaData profile, string behaviourName, Context context, List<AspectTestSuite> aspectTests, IEnumerable<BehaviourTestSuite> behaviourTestSuite, - DateTime lastChangeTime) + bool includeTests = true) { _skeleton = new LuaSkeleton.LuaSkeleton(context, true); _profile = profile; @@ -47,29 +46,59 @@ namespace AspectedRouting.IO.itinero2 _context = context; _aspectTests = aspectTests; _behaviourTestSuite = behaviourTestSuite; - _lastChangeTime = lastChangeTime; + _includeTests = includeTests; _parameterPrinter = new LuaParameterPrinter(_profile, _skeleton); } + private string TestRunner() + { + return new List<string> + { + "if (itinero == nil) then", + " itinero = {}", + " itinero.log = print", + "", + " -- Itinero is not defined -> we are running from a lua interpreter -> the tests are intended", + " runTests = true", + "", + "", + "else", + " print = itinero.log", + "end", + "", + "test_all()", + "if (not failed_tests and not failed_profile_tests and print ~= nil) then", + $" print(\"Tests OK ({_profile.Name}.{_behaviourName})\")", + "end" + }.Lined(); + } + public string ToLua() { var profileDescr = _profile.Behaviours[_behaviourName]["description"].Evaluate(_context).ToString(); var header = - new List<string> { + new List<string> + { $"name = \"{_profile.Name}.{_behaviourName}\"", $"description = \"{profileDescr} ({_profile.Description})\"", "", "-- The hierarchy of types that this vehicle is; mostly used to check access restrictions", - $"vehicle_types = "+_skeleton.ToLua(new Constant( _profile.VehicleTyps.Select(v => new Constant(v)).ToArray())) + "vehicle_types = " + + _skeleton.ToLua(new Constant(_profile.VehicleTyps.Select(v => new Constant(v)).ToArray())) }; - var testPrinter = new LuaTestPrinter(_skeleton, - new List<string> { "unitTestProfile2" }); - var tests = testPrinter.GenerateFullTestSuite( - _behaviourTestSuite.ToList(), - new List<AspectTestSuite>(), - true); - var all = new List<string> { + var tests = ""; + if (_includeTests) { + var testPrinter = new LuaTestPrinter(_skeleton, + new List<string> { "unitTestProfile2" }); + tests = testPrinter.GenerateFullTestSuite( + _behaviourTestSuite.ToList(), + new List<AspectTestSuite>(), + true) + "\n\n" + TestRunner(); + } + + var all = new List<string> + { header.Lined(), "", GenerateMainFunction(), @@ -87,25 +116,7 @@ namespace AspectedRouting.IO.itinero2 "", string.Join("\n\n", _skeleton.GenerateConstants()), "", - tests, - "", - - "if (itinero == nil) then", - " itinero = {}", - " itinero.log = print", - "", - " -- Itinero is not defined -> we are running from a lua interpreter -> the tests are intended", - " runTests = true", - "", - "", - "else", - " print = itinero.log", - "end", - "", - "test_all()", - "if (not failed_tests and not failed_profile_tests and print ~= nil) then", - $" print(\"Tests OK ({_profile.Name}.{_behaviourName})\")", - "end" + tests }; return all.Lined(); diff --git a/AspectedRouting/Program.cs b/AspectedRouting/Program.cs index 898dc1f..34b580b 100644 --- a/AspectedRouting/Program.cs +++ b/AspectedRouting/Program.cs @@ -258,7 +258,7 @@ namespace AspectedRouting private static void WriteOutputFiles(Context context, List<(AspectMetadata aspect, AspectTestSuite tests)> aspects, string outputDir, - List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)> profiles, DateTime lastChange) + List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)> profiles, bool includeTests) { if (!Directory.Exists($"{outputDir}/profile-documentation/")) { @@ -315,7 +315,7 @@ namespace AspectedRouting context, aspectTests, profileTests.Where(testsSuite => testsSuite.BehaviourName == behaviourName), - lastChange + includeTests ).ToLua(); var itinero2ProfileFile = Path.Combine($"{outputDir}/itinero2/{profile.Name}.{behaviourName}.lua"); @@ -351,12 +351,15 @@ namespace AspectedRouting { if (args.Length < 2) { - return "Usage: <directory where all aspects and profiles can be found> <outputdirectory>"; + 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)) { Directory.CreateDirectory(outputDir); @@ -429,11 +432,11 @@ namespace AspectedRouting if (testsOk) { - WriteOutputFiles(context, aspects, outputDir, profiles, lastChange); + WriteOutputFiles(context, aspects, outputDir, profiles, includeTests); } - if (!args.Contains("--no-repl")) + if (runRepl) { Repl(context, profiles .Select(p => p.profile) From 59bc7fef63ca67021bb38f5e667d12c7e69937b3 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Tue, 1 Nov 2022 18:05:30 +0100 Subject: [PATCH 06/10] Split of printing code --- AspectedRouting.Test/Snippets/SnippetTests.cs | 23 ++ AspectedRouting/Printer.cs | 148 ++++++++++ AspectedRouting/Program.cs | 257 +++++------------- 3 files changed, 232 insertions(+), 196 deletions(-) create mode 100644 AspectedRouting/Printer.cs 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; } } From 54fa859aee72f815ba3e4591f1e4a22f3025726b Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Tue, 1 Nov 2022 18:06:47 +0100 Subject: [PATCH 07/10] Set Locale before starting actual program, should mitigate #22 --- AspectedRouting/Program.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AspectedRouting/Program.cs b/AspectedRouting/Program.cs index 60aee5b..cb96f87 100644 --- a/AspectedRouting/Program.cs +++ b/AspectedRouting/Program.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; +using System.Threading; using AspectedRouting.IO; -using AspectedRouting.IO.itinero2; using AspectedRouting.IO.jsonParser; -using AspectedRouting.IO.md; using AspectedRouting.Language; using AspectedRouting.Language.Expression; using AspectedRouting.Tests; @@ -230,6 +230,7 @@ namespace AspectedRouting public static string MainWithError(string[] args) { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false); if (args.Length < 2) { return "Usage: <directory where all aspects and profiles can be found> <outputdirectory> [--include-tests]\n" + From ba177dd0cd6ea8005a0bf54594650a4cdc17ceab Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Tue, 1 Nov 2022 18:48:53 +0100 Subject: [PATCH 08/10] Remove obsolete testing code --- AspectedRouting/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/AspectedRouting/Program.cs b/AspectedRouting/Program.cs index cb96f87..b94fe52 100644 --- a/AspectedRouting/Program.cs +++ b/AspectedRouting/Program.cs @@ -217,7 +217,6 @@ namespace AspectedRouting printer.WriteProfile1(); printer.PrintMdInfo(); printer.WriteAllProfile2(); - printer.WriteProfile2("short"); } File.WriteAllText($"{outputDir}/ProfileMetadata.json", From cb90b4c57c34749ec133fc03c839c50f983c5d0b Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Tue, 1 Nov 2022 18:49:29 +0100 Subject: [PATCH 09/10] Crash on failing self test; add some mitigation for locale variant strings (WIP) --- .../IO/LuaSkeleton/LuaSkeleton.Expressions.cs | 5 +++-- AspectedRouting/IO/LuaSkeleton/LuaStringExtensions.cs | 5 +++-- AspectedRouting/IO/LuaSkeleton/LuaTestPrinter.cs | 10 +++++----- AspectedRouting/IO/itinero1/LuaPrinter1.cs | 2 ++ AspectedRouting/IO/itinero2/LuaPrinter2.cs | 2 ++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs b/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs index b34dbe1..d8f09b0 100644 --- a/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs +++ b/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Dynamic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using AspectedRouting.IO.itinero1; @@ -280,9 +281,9 @@ namespace AspectedRouting.IO.LuaSkeleton case IExpression e: return ToLua(e); case int i: - return "" + i; + return i.ToString(CultureInfo.InvariantCulture); case double d: - return "" + d; + return d.ToString(CultureInfo.InvariantCulture); case string s: return '"' + s.Replace("\"", "\\\"") + '"'; case null: diff --git a/AspectedRouting/IO/LuaSkeleton/LuaStringExtensions.cs b/AspectedRouting/IO/LuaSkeleton/LuaStringExtensions.cs index b172e4d..4f46d89 100644 --- a/AspectedRouting/IO/LuaSkeleton/LuaStringExtensions.cs +++ b/AspectedRouting/IO/LuaSkeleton/LuaStringExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; @@ -12,14 +13,14 @@ namespace AspectedRouting.IO.itinero1 var contents = tags.Select(kv => { var (key, value) = kv; - var left = "[\"" + key + "\"]"; + var left = "[\"" + key .ToString(CultureInfo.InvariantCulture)+ "\"]"; if (Regex.IsMatch(key, "^[a-zA-Z][_a-zA-Z-9]*$")) { left = key; } - return $"{left} = \"{value}\""; + return $"{left.ToString(CultureInfo.InvariantCulture)} = \"{value.ToString(CultureInfo.InvariantCulture)}\""; }); return "{" + string.Join(", ", contents) + "}"; } diff --git a/AspectedRouting/IO/LuaSkeleton/LuaTestPrinter.cs b/AspectedRouting/IO/LuaSkeleton/LuaTestPrinter.cs index cdd684a..733bbf7 100644 --- a/AspectedRouting/IO/LuaSkeleton/LuaTestPrinter.cs +++ b/AspectedRouting/IO/LuaSkeleton/LuaTestPrinter.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using AspectedRouting.Tests; @@ -94,10 +95,10 @@ namespace AspectedRouting.IO.itinero1 tags.Remove("#" + paramName); } - var expectedPriority = "" + expected.Priority; + var expectedPriority = expected.Priority.ToString(CultureInfo.InvariantCulture); if (invertPriority) { - expectedPriority = $"inv({expectedPriority})"; + expectedPriority = $"inv({expectedPriority.ToString(CultureInfo.InvariantCulture)})"; } // Generates something like: @@ -106,7 +107,7 @@ namespace AspectedRouting.IO.itinero1 $"unit_test_profile(behaviour_{testSuite.Profile.Name.AsLuaIdentifier()}_{testSuite.BehaviourName.AsLuaIdentifier()}, " + $"\"{testSuite.BehaviourName}\", " + $"{index}, " + - $"{{access = \"{D(expected.Access)}\", speed = {expected.Speed}, oneway = \"{D(expected.Oneway)}\", priority = {expectedPriority} }}, " + + $"{{access = \"{D(expected.Access)}\", speed = {expected.Speed.ToString(CultureInfo.InvariantCulture)}, oneway = \"{D(expected.Oneway)}\", priority = {expectedPriority} }}, " + tags.ToLuaTable() + ")"; } @@ -151,8 +152,7 @@ namespace AspectedRouting.IO.itinero1 _skeleton.AddDep("unitTest"); _skeleton.AddDep("debug_table"); - return - $"unit_test({functionToApplyName.AsLuaIdentifier()}, \"{functionToApplyName}\", {index}, \"{expected}\", {parameters.ToLuaTable()}, {tags.ToLuaTable()})"; + return $"unit_test({functionToApplyName.AsLuaIdentifier()}, \"{functionToApplyName}\", {index.ToString(CultureInfo.InvariantCulture)}, \"{expected.ToString(CultureInfo.InvariantCulture)}\", {parameters.ToLuaTable()}, {tags.ToLuaTable()})"; } diff --git a/AspectedRouting/IO/itinero1/LuaPrinter1.cs b/AspectedRouting/IO/itinero1/LuaPrinter1.cs index 05290d6..1526367 100644 --- a/AspectedRouting/IO/itinero1/LuaPrinter1.cs +++ b/AspectedRouting/IO/itinero1/LuaPrinter1.cs @@ -151,6 +151,8 @@ namespace AspectedRouting.IO.itinero1 "test_all()", "if (not failed_tests and not failed_profile_tests) then", " print(\"Tests OK\")", + "else", + " error(\"Some tests failed\")", "end" ); } diff --git a/AspectedRouting/IO/itinero2/LuaPrinter2.cs b/AspectedRouting/IO/itinero2/LuaPrinter2.cs index c7dbf46..1e16d81 100644 --- a/AspectedRouting/IO/itinero2/LuaPrinter2.cs +++ b/AspectedRouting/IO/itinero2/LuaPrinter2.cs @@ -69,6 +69,8 @@ namespace AspectedRouting.IO.itinero2 "test_all()", "if (not failed_tests and not failed_profile_tests and print ~= nil) then", $" print(\"Tests OK ({_profile.Name}.{_behaviourName})\")", + "else", + " error(\"Some tests failed\")", "end" }.Lined(); } From 499ede6ae332799c17c3f6e28fd2e8768ba15cfb Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet <pietervdvn@posteo.net> Date: Wed, 2 Nov 2022 12:30:45 +0100 Subject: [PATCH 10/10] More invariant-cultures in toString, tests now work, fix #22 --- AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs b/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs index fcbbd51..a095dc0 100644 --- a/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs +++ b/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using AspectedRouting.IO.LuaSkeleton; using AspectedRouting.IO.LuaSnippets; @@ -45,7 +46,7 @@ namespace AspectedRouting.IO.itinero2 var exprInLua = _skeleton.ToLua(exprSpecialized); if (exprInLua.Contains("constRight") || exprInLua.Contains("firstArg")) throw new Exception("Not optimized properly:" + exprSpecialized.Repr()); - aspects.Add(weight + " * " + exprInLua); + aspects.Add(weight.ToString(CultureInfo.InvariantCulture) + " * " + exprInLua.ToString(CultureInfo.InvariantCulture)); } var scalingFactor = Funcs.Default.Apply(new Constant(Typs.Double, 1.0), _profile.ScalingFactor, tags)