From 6cefdf560296638b9ba9d652f0025fe8f24c2213 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Mon, 5 Apr 2021 18:33:46 +0200 Subject: [PATCH] Add snippets, more fixes to 'must_match', various small iprovements --- .../IO/LuaSnippets/IfThenElseDottedSnippet.cs | 4 +- .../IO/LuaSnippets/IfThenElseSnippet.cs | 39 +++++++++++++++++ .../IO/LuaSnippets/MustMatchSnippet.cs | 43 +++++++++++++++++++ AspectedRouting/IO/LuaSnippets/Snippets.cs | 10 ++++- .../IO/itinero1/LuaPrinter1.MainFunction.cs | 2 +- AspectedRouting/IO/itinero1/LuaPrinter1.cs | 3 +- .../IO/itinero2/LuaPrinter2.MainFunction.cs | 4 +- AspectedRouting/IO/lua/must_match.lua | 21 ++++----- AspectedRouting/IO/lua/stringToTags.lua | 3 ++ AspectedRouting/IO/lua/unitTest.lua | 8 +++- ...unctionTestSuite.cs => AspectTestSuite.cs} | 17 ++++++++ 11 files changed, 134 insertions(+), 20 deletions(-) create mode 100644 AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs create mode 100644 AspectedRouting/IO/LuaSnippets/MustMatchSnippet.cs rename AspectedRouting/Tests/{FunctionTestSuite.cs => AspectTestSuite.cs} (86%) diff --git a/AspectedRouting/IO/LuaSnippets/IfThenElseDottedSnippet.cs b/AspectedRouting/IO/LuaSnippets/IfThenElseDottedSnippet.cs index 8e326c3..6950637 100644 --- a/AspectedRouting/IO/LuaSnippets/IfThenElseDottedSnippet.cs +++ b/AspectedRouting/IO/LuaSnippets/IfThenElseDottedSnippet.cs @@ -11,7 +11,7 @@ namespace AspectedRouting.IO.LuaSnippets public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List args) { - var fCond = args[0]; + var fCond = args[0].Optimize(); var fValue = args[1]; IExpression fElse = null; var arg = args[2]; @@ -26,7 +26,7 @@ namespace AspectedRouting.IO.LuaSnippets var condApplied = fCond.Apply(arg); var isString = condApplied.Types.First().Equals(Typs.String); result += Snippets.Convert(lua, c, condApplied)+"\n"; - result += "if ( "+c + (isString ? " == \"yes\"" : "") + " ) then \n"; + result += $"if ( {c} or {c} == \"yes\" ) then \n"; result += " " + Snippets.Convert(lua, assignTo, fValue.Apply(arg)).Indent() ; if (fElse != null) { diff --git a/AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs b/AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs new file mode 100644 index 0000000..0adbe63 --- /dev/null +++ b/AspectedRouting/IO/LuaSnippets/IfThenElseSnippet.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; +using AspectedRouting.Language; +using AspectedRouting.Language.Typ; + +namespace AspectedRouting.IO.LuaSnippets +{ + public class IfThenElseSnippet : LuaSnippet + { + public IfThenElseSnippet() : base(Funcs.If) { } + + public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List args) + { + var cond = args[0].Optimize(); + var ifTrue = args[1]; + IExpression ifElse = null; + if (args.Count == 3) { + ifElse = args[2]; + } + + var c = lua.FreeVar("cond"); + var result = ""; + result += "local " + c+"\n"; + + var isString = cond.Types.First().Equals(Typs.String); + result += Snippets.Convert(lua, c, cond)+"\n"; + result += $"if ( {c} or {c} == \"yes\" ) then \n"; + result += " " + Snippets.Convert(lua, assignTo, ifTrue).Indent() ; + + if (ifElse != null) { + result += "else\n"; + result += " " + Snippets.Convert(lua, assignTo, ifElse).Indent(); + } + + result += "end\n"; + return result; + } + } +} \ No newline at end of file diff --git a/AspectedRouting/IO/LuaSnippets/MustMatchSnippet.cs b/AspectedRouting/IO/LuaSnippets/MustMatchSnippet.cs new file mode 100644 index 0000000..9dbf84f --- /dev/null +++ b/AspectedRouting/IO/LuaSnippets/MustMatchSnippet.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using AspectedRouting.IO.LuaSkeleton; +using AspectedRouting.Language; +using AspectedRouting.Language.Expression; + +namespace AspectedRouting.IO.LuaSnippets +{ + public class MustMatchSnippet : LuaSnippet + { + public MustMatchSnippet() : base(Funcs.MustMatch) { } + public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List args) + { + var neededKeysExpr = args[0]; + var funcExpr = args[1]; + var tagsExpr = args[2]; + + var result = ""; + var neededKeys = lua.FreeVar("neededKeys"); + var tags = ""; + if (tagsExpr is LuaLiteral literal) { + tags = literal.Lua; + } + else { + tags = lua.FreeVar("tags"); + result += $"local {tags}"; + result += Snippets.Convert(lua, tags, tagsExpr); + + } + + + result += $"local {neededKeys}\n"; + result += Snippets.Convert(lua, neededKeys, neededKeysExpr); + var key = lua.FreeVar("key"); + var value = lua.FreeVar("value"); + result += $"for _, {key} in ipairs({neededKeys}) do\n"; + result += $" local {value} = {tags}[{key}]\n"; + result += $" if ({value} == nil) then\n"; + result += $" -- The value is nil, so mustmatch probably fails...\n"; + + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/AspectedRouting/IO/LuaSnippets/Snippets.cs b/AspectedRouting/IO/LuaSnippets/Snippets.cs index 06723f5..f231e0c 100644 --- a/AspectedRouting/IO/LuaSnippets/Snippets.cs +++ b/AspectedRouting/IO/LuaSnippets/Snippets.cs @@ -4,6 +4,7 @@ using System.Linq; using AspectedRouting.Language; using AspectedRouting.Language.Expression; using AspectedRouting.Language.Functions; +using AspectedRouting.Language.Typ; namespace AspectedRouting.IO.LuaSnippets { @@ -17,10 +18,12 @@ namespace AspectedRouting.IO.LuaSnippets new SumSnippet(), new MaxSnippet(), new MinSnippet(), + new IfThenElseSnippet(), new IfThenElseDottedSnippet(), new InvSnippet(), new HeadSnippet(), - new MemberOfSnippet() + new MemberOfSnippet(), + // new MustMatchSnippet() }; private static readonly Dictionary SnippetsIndex = AllSnippets.ToDictionary( @@ -31,7 +34,10 @@ namespace AspectedRouting.IO.LuaSnippets { var opt = e.Optimize(); - if (!Equals(e.Types.First(), opt.Types.First())) { + // Note that optimization might optimize to a _subtype_ of the original expresion - which is fine! + var origType = e.Types.First(); + var optType = opt.Types.First(); + if (!origType.Equals(optType) && !origType.IsSuperSet(optType)) { throw new Exception("Optimization went wrong!"); } e = opt; diff --git a/AspectedRouting/IO/itinero1/LuaPrinter1.MainFunction.cs b/AspectedRouting/IO/itinero1/LuaPrinter1.MainFunction.cs index a3c8739..1671994 100644 --- a/AspectedRouting/IO/itinero1/LuaPrinter1.MainFunction.cs +++ b/AspectedRouting/IO/itinero1/LuaPrinter1.MainFunction.cs @@ -40,7 +40,7 @@ namespace AspectedRouting.IO.itinero1 " result.attributes_to_keep = {}", "", " local access = " + access, - " if (access == nil or access == \"no\") then", + " if (access == nil or access == \"no\" or access == false) then", " return", " end", " tags.access = access", diff --git a/AspectedRouting/IO/itinero1/LuaPrinter1.cs b/AspectedRouting/IO/itinero1/LuaPrinter1.cs index 3404fd4..d88c663 100644 --- a/AspectedRouting/IO/itinero1/LuaPrinter1.cs +++ b/AspectedRouting/IO/itinero1/LuaPrinter1.cs @@ -24,7 +24,8 @@ namespace AspectedRouting.IO.itinero1 { _profile = profile; _context = context; - _aspectTestSuites = aspectTestSuites; + _aspectTestSuites = aspectTestSuites?.Where(suite => suite != null) + ?.Select(testSuite => testSuite.WithoutRelationTests())?.ToList(); _profileTests = profileTests; _skeleton = new LuaSkeleton.LuaSkeleton(context, false); _parameterPrinter = new LuaParameterPrinter(profile, _skeleton); diff --git a/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs b/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs index 8e1a7ae..2b94e98 100644 --- a/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs +++ b/AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs @@ -122,7 +122,7 @@ namespace AspectedRouting.IO.itinero2 " -- we overwrite the 'access_forward'-value with no; whatever it was...", " access_forward = \"no\"", " end", - " if(access_forward ~= nil and access_forward ~= \"no\") then", + " if(access_forward ~= nil and access_forward ~= \"no\" and access_forward ~= false) then", " tags.access = access_forward -- might be relevant, e.g. for 'access=dismount' for bicycles", " result.forward_speed = " + _skeleton.ToLua(_profile.Speed).Indent(), " tags.speed = result.forward_speed", @@ -142,7 +142,7 @@ namespace AspectedRouting.IO.itinero2 " -- we overwrite the 'access_forward'-value with no; whatever it was...", " access_backward = \"no\"", " end", - " if(access_backward ~= nil and access_backward ~= \"no\") then", + " if(access_backward ~= nil and access_backward ~= \"no\" and access_backward ~= false) then", " tags.access = access_backward", " result.backward_speed = " + _skeleton.ToLua(_profile.Speed).Indent(), " tags.speed = result.backward_speed", diff --git a/AspectedRouting/IO/lua/must_match.lua b/AspectedRouting/IO/lua/must_match.lua index f9e4f7b..f0d21c4 100644 --- a/AspectedRouting/IO/lua/must_match.lua +++ b/AspectedRouting/IO/lua/must_match.lua @@ -25,28 +25,29 @@ Arguments: function must_match(needed_keys, table, tags, result) for _, key in ipairs(needed_keys) do local v = tags[key] + local mapping = table[key] + if (v == nil) then -- a key is missing... - -- this probably means that we must return false... unless the mapping returns something for null! - local mappng = table[key] - if (mappng ~= nil) then - -- there is a mapping! We might be in luck... - local resultValue = mappng[v] + -- note that the mapping might already be executed + if (mapping == true or mapping == "yes") then + -- The function for this key returned "true" despite being fed 'nil' + -- So, we can safely assume that the absence of this key is fine! + -- PASS + elseif (type(mapping) == "table") then + -- there is a mapping! We might be in luck... What does it have for 'nil'? + local resultValue = mapping[v] if (resultValue == nil or resultValue == false) then -- nope, no luck after all return false end - if (resultValue == true or resultValue == "yes") then - return true - end else return false end end - local mapping = table[key] - if (mapping == nil) then + if (mapping == nil) then -- the mapping is nil! That is fine, the key is present anyway -- we ignore elseif (type(mapping) == "table") then diff --git a/AspectedRouting/IO/lua/stringToTags.lua b/AspectedRouting/IO/lua/stringToTags.lua index d6931df..9fc6cc0 100644 --- a/AspectedRouting/IO/lua/stringToTags.lua +++ b/AspectedRouting/IO/lua/stringToTags.lua @@ -1,3 +1,6 @@ function stringToTags(table, tags) + if (tags == nil) then + return table + end return table_to_list(tags, {}, table) end \ No newline at end of file diff --git a/AspectedRouting/IO/lua/unitTest.lua b/AspectedRouting/IO/lua/unitTest.lua index 3112e96..ced3250 100644 --- a/AspectedRouting/IO/lua/unitTest.lua +++ b/AspectedRouting/IO/lua/unitTest.lua @@ -11,8 +11,12 @@ function unit_test(f, fname, index, expected, parameters, tags) -- OK! elseif(tonumber(actual) and tonumber(expected) and math.abs(tonumber(actual) - tonumber(expected)) < 0.1) then -- OK! - elseif (tostring(actual) ~= expected) then - print("[" .. fname .. "] " .. index .. " failed: expected " .. expected .. " but got " .. tostring(actual)) + elseif (expected == "no" and actual == false) then + -- OK! + elseif (expected == actual) then + -- OK! + elseif (tostring(actual) ~= tostring(expected)) then + print("[" .. fname .. "] " .. index .. " failed: expected " .. tostring(expected) .. " but got " .. tostring(actual)) failed_tests = true end end \ No newline at end of file diff --git a/AspectedRouting/Tests/FunctionTestSuite.cs b/AspectedRouting/Tests/AspectTestSuite.cs similarity index 86% rename from AspectedRouting/Tests/FunctionTestSuite.cs rename to AspectedRouting/Tests/AspectTestSuite.cs index 1cc5160..236bd96 100644 --- a/AspectedRouting/Tests/FunctionTestSuite.cs +++ b/AspectedRouting/Tests/AspectTestSuite.cs @@ -53,6 +53,23 @@ namespace AspectedRouting.Tests return new AspectTestSuite(function, tests); } + /// + /// Returns a test suite where no tests are kept which contain keys of the scheme '_relation::' + /// + /// + public AspectTestSuite WithoutRelationTests() + { + var newTests = new List<(string expected, Dictionary tags)>(); + foreach (var (expected, tags) in Tests) { + if (tags.Keys.Any(key => key.StartsWith("_relation") && key.Split(":").Length ==3)) { + continue; + } + newTests.Add((expected, tags)); + } + + return new AspectTestSuite(FunctionToApply, newTests); + } + public bool Run() {