Fixed order of arguments, fix various issues in lua output
This commit is contained in:
parent
e2cd6caa70
commit
a116fd1bdb
13 changed files with 128 additions and 50 deletions
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<LangVersion>8</LangVersion>
|
<LangVersion>8</LangVersion>
|
||||||
<AssemblyName>AspectedRouting</AssemblyName>
|
<AssemblyName>AspectedRouting</AssemblyName>
|
||||||
<RootNamespace>AspectedRouting</RootNamespace>
|
<RootNamespace>AspectedRouting</RootNamespace>
|
||||||
|
|
|
@ -28,10 +28,10 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
Assign(collectedMapping))
|
Assign(collectedMapping))
|
||||||
).Invoke(bare)) {
|
).Invoke(bare)) {
|
||||||
AddDep(Funcs.FirstOf.Name);
|
AddDep(Funcs.FirstOf.Name);
|
||||||
return "first_match_of(tags, result, \n" +
|
return "first_match_of(\n" +
|
||||||
" " + ToLua(order.First(), key) + "," +
|
" " + ToLua(order.First(), key) + ",\n" +
|
||||||
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
|
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
|
||||||
")";
|
",\n tags, result)";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UnApply(
|
if (UnApply(
|
||||||
|
@ -43,10 +43,10 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
Assign(collectedMapping))
|
Assign(collectedMapping))
|
||||||
).Invoke(bare)) {
|
).Invoke(bare)) {
|
||||||
AddDep(Funcs.MustMatch.Name);
|
AddDep(Funcs.MustMatch.Name);
|
||||||
return "must_match(tags, result, \n" +
|
return "must_match(" +
|
||||||
" " + ToLua(order.First(), key) + "," +
|
" " + ToLua(order.First(), key) + "," +
|
||||||
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
|
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
|
||||||
")";
|
",\n tags, result)";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UnApply(
|
if (UnApply(
|
||||||
|
@ -124,7 +124,14 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
var fArgs = bare.DeconstructApply();
|
var fArgs = bare.DeconstructApply();
|
||||||
if (fArgs != null) {
|
if (fArgs != null) {
|
||||||
var (f, args) = fArgs.Value;
|
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)) {
|
if (baseFunc.Name.Equals(Funcs.Id.Name)) {
|
||||||
// This is an ugly hack
|
// This is an ugly hack
|
||||||
|
|
|
@ -45,6 +45,10 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
if (name.StartsWith("mapping")) {
|
if (name.StartsWith("mapping")) {
|
||||||
throw new Exception("A mapping was added as dependency - this is a bug");
|
throw new Exception("A mapping was added as dependency - this is a bug");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name.Contains("stringToTags")) {
|
||||||
|
AddDep("table_to_list");
|
||||||
|
}
|
||||||
_dependencies.Add(name);
|
_dependencies.Add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
for _, key in pairs(order_of_keys) do
|
||||||
local v = tags[key]
|
local v = tags[key]
|
||||||
if (v ~= nil) then
|
if (v ~= nil) then
|
|
@ -22,16 +22,34 @@ Arguments:
|
||||||
- table which is the table to match
|
- 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
|
for _, key in ipairs(needed_keys) do
|
||||||
local v = tags[key]
|
local v = tags[key]
|
||||||
if (v == nil) then
|
if (v == nil) then
|
||||||
-- a key is missing...
|
-- 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
|
end
|
||||||
|
|
||||||
local mapping = table[key]
|
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:
|
-- we have to map the value with a function:
|
||||||
local resultValue = mapping[v]
|
local resultValue = mapping[v]
|
||||||
if (resultValue ~= nil or -- actually, having nil for a mapping is fine for this function!.
|
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)
|
error("MustMatch got a string value it can't handle: " .. bool)
|
||||||
end
|
end
|
||||||
elseif (type(mapping) == "boolean") then
|
elseif (type(mapping) == "boolean") then
|
||||||
if(not mapping) then
|
if (not mapping) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
else
|
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
|
||||||
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
|
for _, key in ipairs(needed_keys) do
|
||||||
local v = tags[key] -- this is the only place where we use the original tags
|
local v = tags[key] -- this is the only place where we use the original tags
|
||||||
if (v ~= nil) then
|
if (v ~= nil) then
|
|
@ -1,5 +1,8 @@
|
||||||
function table_to_list(tags, result, factor_table)
|
function table_to_list(tags, result, factor_table)
|
||||||
local list = {}
|
local list = {}
|
||||||
|
if(tags == nil) then
|
||||||
|
return list
|
||||||
|
end
|
||||||
for key, mapping in pairs(factor_table) do
|
for key, mapping in pairs(factor_table) do
|
||||||
local v = tags[key]
|
local v = tags[key]
|
||||||
if (v ~= nil) then
|
if (v ~= nil) then
|
||||||
|
|
|
@ -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`.";
|
"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 override List<string> ArgNames { get; } = new List<string> {"s"};
|
||||||
|
|
||||||
public FirstMatchOf() : base("firstMatchOf", true,
|
public FirstMatchOf() : base("first_match_of", true,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
// [String] -> (Tags -> [a]) -> Tags -> a
|
// [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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,12 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
var key = (string) s;
|
var key = (string) s;
|
||||||
var otherARgs = arguments.ToList().GetRange(1, arguments.Length - 1);
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AspectedRouting.Language.Expression;
|
using AspectedRouting.Language.Expression;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
using Type = AspectedRouting.Language.Typ.Type;
|
|
||||||
|
|
||||||
namespace AspectedRouting.Language.Functions
|
namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public class MemberOf : Function
|
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; } =
|
public override string Description { get; } =
|
||||||
"This function returns true, if the way is member of a relation matching the specified function.\n" +
|
"This function returns true, if the way is member of a relation matching the specified function.\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
|
@ -23,44 +33,51 @@ namespace AspectedRouting.Language.Functions
|
||||||
"\n\n" +
|
"\n\n" +
|
||||||
"In the test.csv, one can simply use `_relation:<aspect_name>=yes` to mimic relations in your tests";
|
"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>
|
public override List<string> ArgNames { get; } = new List<string> {
|
||||||
{
|
"f", "tags"
|
||||||
"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)
|
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('$');
|
var name = c.AspectName.TrimStart('$');
|
||||||
|
|
||||||
if(tags.TryGetValue("_relation:"+name, out var v))
|
if (tags.TryGetValue("_relation:" + name, out var v)) {
|
||||||
{
|
|
||||||
return 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";
|
return "no";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
||||||
{
|
{
|
||||||
var unified = Types.SpecializeTo(allowedTypes);
|
var unified = Types.SpecializeTo(allowedTypes);
|
||||||
if (unified == null)
|
if (unified == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public class MustMatch : Function
|
public class MustMatch : Function
|
||||||
{
|
{
|
||||||
public MustMatch() : base("mustMatch", true,
|
public MustMatch() : base("must_match", true,
|
||||||
new[] {
|
new[] {
|
||||||
// [String] -> (Tags -> [string]) -> Tags -> bool
|
// [String] -> (Tags -> [string]) -> Tags -> bool
|
||||||
Curry.ConstructFrom(Typs.Bool, // Result type on top!
|
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
|
new Curry(Typs.Tags, new ListType(Typs.String)), // The function to execute on every key
|
||||||
Typs.Tags // The tags to apply this on
|
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(
|
public override string Description { get; } = Utils.Lines(
|
||||||
"Checks that every specified key is present and gives a non-false value.\n",
|
"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)) {
|
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";
|
return "no";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,9 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
var f = arguments[0];
|
var f = arguments[0];
|
||||||
var tags = (Dictionary<string, string>) arguments[1].Evaluate(c);
|
var tags = (Dictionary<string, string>) arguments[1].Evaluate(c);
|
||||||
|
if (tags == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
var result = new List<object>();
|
var result = new List<object>();
|
||||||
foreach (var (k, v) in tags)
|
foreach (var (k, v) in tags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace AspectedRouting.Tests
|
||||||
var testCase = 0;
|
var testCase = 0;
|
||||||
foreach (var test in Tests) {
|
foreach (var test in Tests) {
|
||||||
testCase++;
|
testCase++;
|
||||||
var context = new Context();
|
var context = new Context().WithAspectName("unittest");
|
||||||
foreach (var (key, value) in test.tags) {
|
foreach (var (key, value) in test.tags) {
|
||||||
if (key.StartsWith("#")) {
|
if (key.StartsWith("#")) {
|
||||||
context.AddParameter(key, value);
|
context.AddParameter(key, value);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue