Fixed order of arguments, fix various issues in lua output

This commit is contained in:
Pieter Vander Vennet 2021-04-04 01:57:41 +02:00
parent e2cd6caa70
commit a116fd1bdb
13 changed files with 128 additions and 50 deletions

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>8</LangVersion>
<AssemblyName>AspectedRouting</AssemblyName>
<RootNamespace>AspectedRouting</RootNamespace>

View file

@ -28,10 +28,10 @@ namespace AspectedRouting.IO.LuaSkeleton
Assign(collectedMapping))
).Invoke(bare)) {
AddDep(Funcs.FirstOf.Name);
return "first_match_of(tags, result, \n" +
" " + ToLua(order.First(), key) + "," +
return "first_match_of(\n" +
" " + ToLua(order.First(), key) + ",\n" +
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
")";
",\n tags, result)";
}
if (UnApply(
@ -43,10 +43,10 @@ namespace AspectedRouting.IO.LuaSkeleton
Assign(collectedMapping))
).Invoke(bare)) {
AddDep(Funcs.MustMatch.Name);
return "must_match(tags, result, \n" +
return "must_match(" +
" " + ToLua(order.First(), key) + "," +
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
")";
",\n tags, result)";
}
if (UnApply(
@ -124,7 +124,14 @@ namespace AspectedRouting.IO.LuaSkeleton
var fArgs = bare.DeconstructApply();
if (fArgs != null) {
var (f, args) = fArgs.Value;
var baseFunc = (Function) f;
if(f is Constant constant) {
return ConstantToLua(constant);
}
if (!(f is Function baseFunc)) {
throw new ArgumentException("Not a function: " + f);
}
if (baseFunc.Name.Equals(Funcs.Id.Name)) {
// This is an ugly hack

View file

@ -45,6 +45,10 @@ namespace AspectedRouting.IO.LuaSkeleton
if (name.StartsWith("mapping")) {
throw new Exception("A mapping was added as dependency - this is a bug");
}
if (name.Contains("stringToTags")) {
AddDep("table_to_list");
}
_dependencies.Add(name);
}

View file

@ -1,4 +1,7 @@
function first_match_of(tags, result, order_of_keys, table)
function first_match_of(order_of_keys, table, tags, result)
if (result == nil) then
result = { attributes_to_keep = {} }
end
for _, key in pairs(order_of_keys) do
local v = tags[key]
if (v ~= nil) then

View file

@ -22,16 +22,34 @@ Arguments:
- table which is the table to match
]]
function must_match(tags, result, needed_keys, table)
function must_match(needed_keys, table, tags, result)
for _, key in ipairs(needed_keys) do
local v = tags[key]
if (v == nil) then
-- a key is missing...
return false
-- 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]
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 (type(mapping) == "table") then
if (mapping == nil) then
-- the mapping is nil! That is fine, the key is present anyway
-- we ignore
elseif (type(mapping) == "table") then
-- we have to map the value with a function:
local resultValue = mapping[v]
if (resultValue ~= nil or -- actually, having nil for a mapping is fine for this function!.
@ -50,15 +68,19 @@ function must_match(tags, result, needed_keys, table)
error("MustMatch got a string value it can't handle: " .. bool)
end
elseif (type(mapping) == "boolean") then
if(not mapping) then
if (not mapping) then
return false
end
else
error("The mapping is not a table. This is not supported. We got " .. tostring(mapping) .. " (" .. type(mapping)..")")
error("The mapping is not a table. This is not supported. We got " .. tostring(mapping) .. " (" .. type(mapping) .. ")")
end
end
-- Now that we know for sure that every key matches, we add them all
-- Now that we know for sure that every key matches, we add them all to the 'attributes_to_keep'
if (result == nil) then
-- euhm, well, seems like we don't are about the attributes_to_keep; early return!
return true
end
for _, key in ipairs(needed_keys) do
local v = tags[key] -- this is the only place where we use the original tags
if (v ~= nil) then

View file

@ -1,5 +1,8 @@
function table_to_list(tags, result, factor_table)
local list = {}
if(tags == nil) then
return list
end
for key, mapping in pairs(factor_table) do
local v = tags[key]
if (v ~= nil) then

View file

@ -12,7 +12,7 @@ namespace AspectedRouting.Language.Functions
"E.g. `$firstMatchOf ['maxspeed','highway'] {'maxspeed' --> $parse, 'highway' --> {residential --> 30, tertiary --> 50}}` applied on `{maxspeed=70, highway=tertiary}` will yield `70` as that is the first key in the list; `{highway=residential}` will yield `30`.";
public override List<string> ArgNames { get; } = new List<string> {"s"};
public FirstMatchOf() : base("firstMatchOf", true,
public FirstMatchOf() : base("first_match_of", true,
new[]
{
// [String] -> (Tags -> [a]) -> Tags -> a
@ -23,9 +23,10 @@ namespace AspectedRouting.Language.Functions
)
})
{
Funcs.AddBuiltin( this,"firstMatchOf");
}
private FirstMatchOf(IEnumerable<Type> types) : base("firstMatchOf", types)
private FirstMatchOf(IEnumerable<Type> types) : base("first_match_of", types)
{
}

View file

@ -89,8 +89,12 @@ namespace AspectedRouting.Language.Functions
var key = (string) s;
var otherARgs = arguments.ToList().GetRange(1, arguments.Length - 1);
if (!StringToResultFunctions.TryGetValue(key, out var resultFunction))
{
if (!StringToResultFunctions.ContainsKey(key)) { // This is really roundabout, but it has to be
return null;
}
var resultFunction = StringToResultFunctions[key];
if (resultFunction == null) {
return null;
}

View file

@ -1,12 +1,22 @@
using System.Collections.Generic;
using AspectedRouting.Language.Expression;
using AspectedRouting.Language.Typ;
using Type = AspectedRouting.Language.Typ.Type;
namespace AspectedRouting.Language.Functions
{
public class MemberOf : Function
{
public MemberOf() : base(
"memberOf", true,
new[] {
new Curry(
new Curry(Typs.Tags, Typs.Bool),
new Curry(Typs.Tags, Typs.Bool))
}
) { }
public MemberOf(IEnumerable<Type> types) : base("memberOf", types) { }
public override string Description { get; } =
"This function returns true, if the way is member of a relation matching the specified function.\n" +
"\n" +
@ -23,44 +33,51 @@ namespace AspectedRouting.Language.Functions
"\n\n" +
"In the test.csv, one can simply use `_relation:<aspect_name>=yes` to mimic relations in your tests";
public override List<string> ArgNames { get; } = new List<string>
{
"f","tags"
public override List<string> ArgNames { get; } = new List<string> {
"f", "tags"
};
public MemberOf() : base(
"memberOf", true,
new[]
{
new Curry(
new Curry(Typs.Tags, Typs.Bool),
new Curry(Typs.Tags, Typs.Bool))
}
)
{
}
public MemberOf(IEnumerable<Type> types) : base("memberOf", types)
{
}
public override object Evaluate(Context c, params IExpression[] arguments)
{
var tags =(Dictionary<string, string>) arguments[1].Evaluate(c);
var tags = (Dictionary<string, string>) arguments[1].Evaluate(c);
var name = c.AspectName.TrimStart('$');
if(tags.TryGetValue("_relation:"+name, out var v))
{
if (tags.TryGetValue("_relation:" + name, out var v)) {
return v;
}
// In the case of tests, relations might be added with "_relation:1:<key>"
// So, we create this table as dictionary
var relationTags = new Dictionary<string, Dictionary<string, string>>();
foreach (var tag in tags) {
if (tag.Key.StartsWith("_relation:")) {
var keyParts = tag.Key.Split(":");
if (keyParts.Length != 3) {
continue;
}
var relationName = keyParts[1];
if (!relationTags.ContainsKey(relationName)) {
relationTags.Add(relationName, new Dictionary<string, string>());
}
relationTags[relationName].Add(keyParts[2], tag.Value);
}
}
foreach (var relationTagging in relationTags) {
var result = arguments[0].Evaluate(c, new Constant(relationTagging.Value));
if (result.Equals("yes")) {
return "yes";
}
}
return "no";
}
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
{
var unified = Types.SpecializeTo(allowedTypes);
if (unified == null)
{
if (unified == null) {
return null;
}

View file

@ -7,7 +7,7 @@ namespace AspectedRouting.Language.Functions
{
public class MustMatch : Function
{
public MustMatch() : base("mustMatch", true,
public MustMatch() : base("must_match", true,
new[] {
// [String] -> (Tags -> [string]) -> Tags -> bool
Curry.ConstructFrom(Typs.Bool, // Result type on top!
@ -15,9 +15,12 @@ namespace AspectedRouting.Language.Functions
new Curry(Typs.Tags, new ListType(Typs.String)), // The function to execute on every key
Typs.Tags // The tags to apply this on
)
}) { }
})
{
Funcs.AddBuiltin(this, "mustMatch");
}
private MustMatch(IEnumerable<Type> types) : base("mustMatch", types) { }
private MustMatch(IEnumerable<Type> types) : base("must_match", types) { }
public override string Description { get; } = Utils.Lines(
"Checks that every specified key is present and gives a non-false value.\n",
@ -64,7 +67,18 @@ namespace AspectedRouting.Language.Functions
}
if (!tags.ContainsKey(tagKey)) {
// A required key is missing: return 'no'
// A required key is missing
// Normally, we return no; but there is a second chance
// IF the mapping returns 'yes' on null, we make an exception and ignore it
var applied = function.Evaluate(c, new Constant(new Dictionary<string, string> {
{tagKey, ""}
}));
if (applied == null) {
return "no";
}
if (applied.Equals("yes") || (applied is IEnumerable<object> l && l.Count() > 0 && l.ToList()[0].Equals("yes")) ) {
continue; // We ignore the absence of the key
}
return "no";
}
}

View file

@ -34,6 +34,9 @@ namespace AspectedRouting.Language.Functions
{
var f = arguments[0];
var tags = (Dictionary<string, string>) arguments[1].Evaluate(c);
if (tags == null) {
return null;
}
var result = new List<object>();
foreach (var (k, v) in tags)
{

View file

@ -60,7 +60,7 @@ namespace AspectedRouting.Tests
var testCase = 0;
foreach (var test in Tests) {
testCase++;
var context = new Context();
var context = new Context().WithAspectName("unittest");
foreach (var (key, value) in test.tags) {
if (key.StartsWith("#")) {
context.AddParameter(key, value);