Rework output system: apply 'Tags', add many rewriting rules, add tests
This commit is contained in:
parent
1f27a45037
commit
a84bbceda2
42 changed files with 1384 additions and 424 deletions
|
@ -54,7 +54,7 @@ public class FunctionsTest
|
|||
{ "x", "y" }
|
||||
};
|
||||
|
||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize();
|
||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize(out _);
|
||||
var result = expr.Evaluate(new Context());
|
||||
Assert.Equal("yes", result);
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ public class FunctionsTest
|
|||
{ "a", "b" }
|
||||
};
|
||||
|
||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize();
|
||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize(out var _);
|
||||
var result = expr.Evaluate(new Context());
|
||||
Assert.Equal("no", result);
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ public class FunctionsTest
|
|||
{ "x", "someRandomValue" }
|
||||
};
|
||||
|
||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize();
|
||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize(out _);
|
||||
var result = expr.Evaluate(new Context());
|
||||
Assert.Equal("no", result);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ public class FunctionsTest
|
|||
|
||||
var resultT = ifExpr.Evaluate(c);
|
||||
Assert.Equal("thenResult", resultT);
|
||||
resultT = ifExpr.Optimize().Evaluate(c);
|
||||
resultT = ifExpr.Optimize(out _).Evaluate(c);
|
||||
Assert.Equal("thenResult", resultT);
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ public class FunctionsTest
|
|||
{
|
||||
var c = new Context();
|
||||
var ifExpr = JsonParser.ParseExpression(c, IfDottedConditionJson);
|
||||
ifExpr = ifExpr.Optimize();
|
||||
ifExpr = ifExpr.Optimize(out _);
|
||||
var resultT = ifExpr.Evaluate(c,
|
||||
new Constant(Typs.String, "yes"));
|
||||
var resultF = ifExpr.Evaluate(c,
|
||||
|
@ -393,8 +393,8 @@ public class FunctionsTest
|
|||
var o = f.Evaluate(new Context(), tags0);
|
||||
Assert.Equal(50.0, o);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ApplyFirstMatchOf_FirstMatchIsTaken_ResidentialDefault()
|
||||
{
|
||||
|
@ -407,7 +407,7 @@ public class FunctionsTest
|
|||
var o = f.Evaluate(new Context(), tags0);
|
||||
Assert.Equal(30, o);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ApplyFirstMatchOf_NoMatchIfFound_Null()
|
||||
{
|
||||
|
@ -444,4 +444,36 @@ public class FunctionsTest
|
|||
);
|
||||
return Funcs.FirstOf.Apply(order, mapping);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
/**
|
||||
* Regression test for a misbehaving ifDotted
|
||||
*/
|
||||
public void IfDotted_CorrectExpression()
|
||||
{
|
||||
var e = Funcs.IfDotted.Apply(
|
||||
Funcs.Const.Apply(new Parameter("follow_restrictions")),
|
||||
Funcs.Head.Apply( Funcs.StringStringToTags.Apply( new Mapping(new[] { "oneway" }, new[] { Funcs.Id }))),
|
||||
Funcs.Const.Apply(new Constant("dont-care"))
|
||||
);
|
||||
|
||||
var c = new Context();
|
||||
c.AddParameter("follow_restrictions", "yes");
|
||||
|
||||
var tags = new Dictionary<string, string>();
|
||||
tags["oneway"] = "with";
|
||||
|
||||
var r = e.Evaluate(c, new Constant(tags));
|
||||
Assert.Equal("with", r);
|
||||
|
||||
var c0 = new Context();
|
||||
c0.AddParameter("follow_restrictions", "no");
|
||||
|
||||
|
||||
var r0 = e.Evaluate(c0, new Constant(tags));
|
||||
Assert.Equal("dont-care", r0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
151
AspectedRouting.Test/OptimizationsTests.cs
Normal file
151
AspectedRouting.Test/OptimizationsTests.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using AspectedRouting.IO.LuaSkeleton;
|
||||
using AspectedRouting.Language;
|
||||
using AspectedRouting.Language.Expression;
|
||||
using AspectedRouting.Language.Functions;
|
||||
using AspectedRouting.Language.Typ;
|
||||
using Xunit;
|
||||
|
||||
namespace AspectedRouting.Test;
|
||||
|
||||
public class OptimizationsTests
|
||||
{
|
||||
[Fact]
|
||||
public void AppliedListDot_Optimize_ListOfApplications()
|
||||
{
|
||||
var lit = new LuaLiteral(Typs.Nat, "tags");
|
||||
var e0 = Funcs.ListDot.Apply(
|
||||
new Constant(new[]
|
||||
{
|
||||
Funcs.Eq.Apply(new Constant(5)),
|
||||
Funcs.Eq.Apply(new Constant(42))
|
||||
}));
|
||||
|
||||
var e = e0.Apply(lit).SpecializeToSmallestType();
|
||||
var x = e.Optimize(out var sc);
|
||||
Assert.True(sc);
|
||||
Assert.Equal(
|
||||
new Constant(new[]
|
||||
{
|
||||
Funcs.Eq.Apply(new Constant(5)).Apply(lit),
|
||||
Funcs.Eq.Apply(new Constant(42)).Apply(lit)
|
||||
}).SpecializeToSmallestType().ToString(), x.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdvancedApplied_Optimized_ListOfAppliedValues()
|
||||
{
|
||||
var legal_access_be = new FunctionCall("$legal_access_be", new Curry(Typs.Tags, Typs.String));
|
||||
var legal_access_pedestrian = new FunctionCall("$pedestrian.legal_access", new Curry(Typs.Tags, Typs.String));
|
||||
var tags = new LuaLiteral(Typs.Tags, "tags");
|
||||
var e = new Apply( // string
|
||||
Funcs.Head,
|
||||
new Apply( // list (string)
|
||||
new Apply( // tags -> list (string)
|
||||
Funcs.ListDot,
|
||||
new Constant(new[]
|
||||
{
|
||||
legal_access_be,
|
||||
legal_access_pedestrian
|
||||
})),
|
||||
tags));
|
||||
var eOpt = e.Optimize(out var sc);
|
||||
Assert.True(sc);
|
||||
Assert.Equal(
|
||||
Funcs.Head.Apply(new Constant(
|
||||
new[]
|
||||
{
|
||||
legal_access_be.Apply(tags),
|
||||
legal_access_pedestrian.Apply(tags)
|
||||
}
|
||||
)).ToString(),
|
||||
eOpt.ToString()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void advancedExpr_Optimize_Works()
|
||||
{
|
||||
var e = new Apply( // double
|
||||
new Apply( // tags -> double
|
||||
new Apply( // (tags -> double) -> tags -> doubleTag
|
||||
Funcs.Default,
|
||||
new Constant(0)),
|
||||
new Apply( // tags -> double
|
||||
new Apply( // (tags -> list (double)) -> tags -> double
|
||||
Funcs.Dot,
|
||||
Funcs.Head),
|
||||
new Apply( // tags -> list (double)
|
||||
Funcs.StringStringToTags,
|
||||
new Mapping(
|
||||
new[]
|
||||
{
|
||||
"access"
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new Mapping(
|
||||
new[]
|
||||
{
|
||||
"private",
|
||||
"destination",
|
||||
"permissive"
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new Constant(-500), new Constant(-3), new Constant(-1)
|
||||
}
|
||||
)
|
||||
}
|
||||
)))),
|
||||
new LuaLiteral(Typs.Tags, "tags"));
|
||||
var eOpt = e.Optimize(out var sc);
|
||||
Assert.True(sc);
|
||||
Assert.NotEmpty(eOpt.Types);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void optimizeListdotAway()
|
||||
{
|
||||
var tagsToStr = new Curry(Typs.Tags, Typs.PDouble);
|
||||
var e = new Apply( // pdouble
|
||||
new Apply( // tags -> pdouble
|
||||
Funcs.Id,
|
||||
new Apply( // tags -> pdouble
|
||||
new Apply( // (tags -> list (pdouble)) -> tags -> pdouble
|
||||
Funcs.Dot,
|
||||
Funcs.Min),
|
||||
new Apply( // tags -> list (pdouble)
|
||||
Funcs.ListDot,
|
||||
new Constant(new IExpression[]
|
||||
{
|
||||
new FunctionCall("$legal_maxspeed_be", tagsToStr),
|
||||
new FunctionCall("$car.practical_max_speed", tagsToStr),
|
||||
new Apply( // tags -> pdouble
|
||||
Funcs.Const,
|
||||
new Parameter("#maxspeed"))
|
||||
})))),
|
||||
new LuaLiteral(Typs.Tags, "tags"));
|
||||
var opt = e.SpecializeToSmallestType().Optimize(out var sc);
|
||||
Assert.True(sc);
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Regression_ShouldOptimize()
|
||||
{
|
||||
var e = new Apply( // nat
|
||||
new Apply( // tags -> nat
|
||||
new Apply( // nat -> tags -> nat
|
||||
new Apply( // (nat -> tags -> nat) -> nat -> tags -> nat
|
||||
Funcs.ConstRight,
|
||||
Funcs.Id),
|
||||
Funcs.Const),
|
||||
new LuaLiteral(Typs.PDouble, "distance")),
|
||||
new LuaLiteral(Typs.Tags, "tags")).SpecializeToSmallestType();
|
||||
var opt = e.Optimize(out var sc);
|
||||
Assert.True(sc);
|
||||
|
||||
}
|
||||
}
|
52
AspectedRouting.Test/RegressionTest.cs
Normal file
52
AspectedRouting.Test/RegressionTest.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using AspectedRouting.IO.jsonParser;
|
||||
using AspectedRouting.Language;
|
||||
using AspectedRouting.Language.Expression;
|
||||
using AspectedRouting.Language.Functions;
|
||||
using AspectedRouting.Language.Typ;
|
||||
using Xunit;
|
||||
|
||||
namespace AspectedRouting.Test;
|
||||
|
||||
public class RegressionTest
|
||||
{
|
||||
[Fact]
|
||||
public void IfDotted_ShouldBeParsed()
|
||||
{
|
||||
var carOneway = Funcs.Const.Apply(new Constant("result of car.oneway")).Specialize(new Curry(
|
||||
Typs.Tags, Typs.String));
|
||||
|
||||
var doc = JsonDocument.Parse("{\"oneway\":{\"$ifdotted\":{\"$const\": \"#follow_restrictions\"},\"then\": \"$car.oneway\",\"else\": {\"$const\": \"both-ignored-restrictions\"}}}");
|
||||
|
||||
var parsingContext = new Context();
|
||||
parsingContext .AddFunction("car.oneway", new AspectMetadata(
|
||||
carOneway, "car.oneway","oneway function", "test", "with|against|both",
|
||||
"N/A", false
|
||||
));
|
||||
parsingContext.AddParameter("follow_restrictions","no");
|
||||
var aspect = JsonParser.ParseProfileProperty(doc.RootElement,parsingContext, "oneway");
|
||||
var oneway = new Dictionary<string, string>();
|
||||
|
||||
var c = new Context();
|
||||
c .AddFunction("car.oneway", new AspectMetadata(
|
||||
carOneway, "car.oneway","oneway function", "test", "with|against|both",
|
||||
"N/A", false
|
||||
));
|
||||
|
||||
c.AddParameter("follow_restrictions","yes");
|
||||
var result = aspect.Run(c, oneway);
|
||||
Assert.Equal("result of car.oneway", result);
|
||||
|
||||
var c0 = new Context();
|
||||
c0.AddFunction("car.oneway", new AspectMetadata(
|
||||
carOneway, "car.oneway","oneway function", "test", "with|against|both",
|
||||
"N/A", false
|
||||
));
|
||||
c0.AddParameter("follow_restrictions","no");
|
||||
var result0 = aspect.Run(c0, oneway);
|
||||
Assert.Equal("both-ignored-restrictions", result0);
|
||||
|
||||
}
|
||||
}
|
|
@ -7,84 +7,91 @@ using AspectedRouting.Language.Functions;
|
|||
using AspectedRouting.Language.Typ;
|
||||
using Xunit;
|
||||
|
||||
namespace AspectedRouting.Test.Snippets
|
||||
namespace AspectedRouting.Test.Snippets;
|
||||
|
||||
public class SnippetTests
|
||||
{
|
||||
public class SnippetTests
|
||||
[Fact]
|
||||
public void DefaultSnippet_SimpleDefault_GetsLua()
|
||||
{
|
||||
[Fact]
|
||||
public void DefaultSnippet_SimpleDefault_GetsLua()
|
||||
var gen = new DefaultSnippet();
|
||||
var lua = new LuaSkeleton(new Context(), true);
|
||||
var code = gen.Convert(lua, "result", new List<IExpression>
|
||||
{
|
||||
var gen = new DefaultSnippet();
|
||||
var lua = new LuaSkeleton(new Context(), true);
|
||||
var code = gen.Convert(lua, "result", new List<IExpression> {
|
||||
new Constant("the_default_value"),
|
||||
Funcs.Id,
|
||||
new Constant("value")
|
||||
});
|
||||
Assert.Contains("if (result == nil) then\n result = \"the_default_value\"", code);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void FirstOfSnippet_SimpleFirstOf_GetLua()
|
||||
{
|
||||
var gen = new FirstMatchOfSnippet();
|
||||
var lua = new LuaSkeleton(new Context(), true);
|
||||
|
||||
// FirstMatchOf: [a] -> (Tags -> [a]) -> Tags -> a
|
||||
|
||||
// Order: [string]
|
||||
var order = new Constant(new List<IExpression> {
|
||||
new Constant("bicycle"),
|
||||
new Constant("access")
|
||||
});
|
||||
|
||||
// Func: (Tags -> [a])
|
||||
var func = new Apply(
|
||||
Funcs.StringStringToTags,
|
||||
new Mapping(
|
||||
new[] { "bicycle", "access" },
|
||||
new IExpression[] {
|
||||
Funcs.Id,
|
||||
Funcs.Id
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
var tags = new LuaLiteral(new[] { Typs.Tags }, "tags");
|
||||
|
||||
var code = gen.Convert(lua, "result",
|
||||
new List<IExpression> {
|
||||
order,
|
||||
func,
|
||||
tags
|
||||
}
|
||||
);
|
||||
// First the more general ones!
|
||||
Assert.Equal(
|
||||
"if (tags[\"access\"] ~= nil) then\n result = tags[\"access\"]\n \nend\nif (tags[\"bicycle\"] ~= nil) then\n result = tags[\"bicycle\"]\n \nend\n",
|
||||
code);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SimpleMappingSnippet_SimpleMapping_GeneratesLua()
|
||||
{
|
||||
var mapping = new Mapping(
|
||||
new[] { "1", "-1" },
|
||||
new IExpression[] {
|
||||
new Constant("with"),
|
||||
new Constant("against")
|
||||
}
|
||||
);
|
||||
var gen = new SimpleMappingSnippet(mapping);
|
||||
var code = gen.Convert(new LuaSkeleton(new Context(), true), "result", new List<IExpression> {
|
||||
new LuaLiteral(Typs.String, "tags.oneway")
|
||||
});
|
||||
|
||||
var expected =
|
||||
"local v\nv = tags.oneway\n\nif (v == \"1\") then\n result = \"with\"\nelseif (v == \"-1\") then\n result = \"against\"\nend";
|
||||
Assert.Equal(expected, code);
|
||||
}
|
||||
new Constant("the_default_value"),
|
||||
Funcs.Id,
|
||||
new Constant("value")
|
||||
});
|
||||
Assert.Contains("if (result == nil) then\n result = \"the_default_value\"", code);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void FirstOfSnippet_SimpleFirstOf_GetLua()
|
||||
{
|
||||
var gen = new FirstMatchOfSnippet();
|
||||
var lua = new LuaSkeleton(new Context(), true);
|
||||
|
||||
// FirstMatchOf: [a] -> (Tags -> [a]) -> Tags -> a
|
||||
|
||||
// Order: [string]
|
||||
var order = new Constant(new List<IExpression>
|
||||
{
|
||||
new Constant("bicycle"),
|
||||
new Constant("access")
|
||||
});
|
||||
|
||||
// Func: (Tags -> [a])
|
||||
var func = new Apply(
|
||||
Funcs.StringStringToTags,
|
||||
new Mapping(
|
||||
new[] { "bicycle", "access" },
|
||||
new IExpression[]
|
||||
{
|
||||
Funcs.Id,
|
||||
Funcs.Id
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
var tags = new LuaLiteral(new[] { Typs.Tags }, "tags");
|
||||
|
||||
var code = gen.Convert(lua, "result",
|
||||
new List<IExpression>
|
||||
{
|
||||
order,
|
||||
func,
|
||||
tags
|
||||
}
|
||||
);
|
||||
// First the more general ones!
|
||||
Assert.Equal(
|
||||
"if (tags[\"access\"] ~= nil) then\n result = tags[\"access\"]\n \nend\nif (tags[\"bicycle\"] ~= nil) then\n result = tags[\"bicycle\"]\n \nend\n",
|
||||
code);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SimpleMappingSnippet_SimpleMapping_GeneratesLua()
|
||||
{
|
||||
var mapping = new Mapping(
|
||||
new[] { "1", "-1" },
|
||||
new IExpression[]
|
||||
{
|
||||
new Constant("with"),
|
||||
new Constant("against")
|
||||
}
|
||||
);
|
||||
var gen = new SimpleMappingSnippet(mapping);
|
||||
var code = gen.Convert(new LuaSkeleton(new Context(), true), "result", new List<IExpression>
|
||||
{
|
||||
new LuaLiteral(Typs.String, "tags.oneway")
|
||||
});
|
||||
|
||||
var expected =
|
||||
"local v\nv = tags.oneway\n\nif (v == \"1\") then\n result = \"with\"\nelseif (v == \"-1\") then\n result = \"against\"\nend";
|
||||
Assert.Equal(expected, code);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AspectedRouting.Language;
|
||||
using AspectedRouting.Language.Typ;
|
||||
using Type = AspectedRouting.Language.Typ.Type;
|
||||
|
||||
namespace AspectedRouting.IO.LuaSkeleton
|
||||
|
@ -40,14 +41,35 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
return null;
|
||||
}
|
||||
|
||||
public IExpression Optimize()
|
||||
public IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
somethingChanged = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Visit(Func<IExpression, bool> f)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
f(this);
|
||||
}
|
||||
|
||||
public bool Equals(IExpression other)
|
||||
{
|
||||
if (other is LuaLiteral ll)
|
||||
{
|
||||
return ll.Lua.Equals(this.Lua);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Repr()
|
||||
{
|
||||
if (this.Types.Count() == 1 && this.Types.First() == Typs.Tags)
|
||||
{
|
||||
return $"new LuaLiteral(Typs.Tags, \"{this.Lua}\")";
|
||||
}
|
||||
|
||||
return $"new LuaLiteral(\"{this.Lua}\")";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using AspectedRouting.IO.itinero1;
|
||||
|
@ -13,6 +14,12 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
{
|
||||
public partial class LuaSkeleton
|
||||
{
|
||||
|
||||
internal string ToLuaWithTags(IExpression bare)
|
||||
{
|
||||
var opt = bare.Apply(new LuaLiteral(Typs.Tags, "tags")).SpecializeToSmallestType().Optimize(out _);
|
||||
return this.ToLua(opt);
|
||||
}
|
||||
internal string ToLua(IExpression bare, string key = "nil", bool forceFirstArgInDot = false)
|
||||
{
|
||||
var collectedMapping = new List<IExpression>();
|
||||
|
@ -57,36 +64,29 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
return "memberOf(funcName, parameters, tags, result)";
|
||||
}
|
||||
|
||||
|
||||
var collectedList = new List<IExpression>();
|
||||
var func = new List<IExpression>();
|
||||
if (
|
||||
UnApply(
|
||||
UnApply(IsFunc(Funcs.Dot), Assign(func)),
|
||||
UnApply(IsFunc(Funcs.ListDot),
|
||||
Assign(collectedList))).Invoke(bare)) {
|
||||
var exprs = (IEnumerable<IExpression>) ((Constant) collectedList.First()).Evaluate(_context);
|
||||
var luaExprs = new List<string>();
|
||||
var funcName = func.First().ToString().TrimStart('$');
|
||||
AddDep(funcName);
|
||||
foreach (var expr in exprs) {
|
||||
var c = new List<IExpression>();
|
||||
if (UnApply(IsFunc(Funcs.Const), Assign(c)).Invoke(expr)) {
|
||||
luaExprs.Add(ToLua(c.First(), key));
|
||||
continue;
|
||||
{
|
||||
var name = new List<string>();
|
||||
var arg = new List<IExpression>();
|
||||
if (UnApply(
|
||||
IsFunctionCall(name),
|
||||
Assign(arg)
|
||||
).Invoke(bare))
|
||||
{
|
||||
var called = _context.DefinedFunctions[name.First()];
|
||||
if (called.ProfileInternal) {
|
||||
return called.Name;
|
||||
}
|
||||
|
||||
if (expr.Types.First() is Curry curry
|
||||
&& curry.ArgType.Equals(Typs.Tags)) {
|
||||
var lua = ToLua(expr, key);
|
||||
luaExprs.Add(lua);
|
||||
AddDependenciesFor(called);
|
||||
AddFunction(called);
|
||||
var usesParams = called.ExpressionImplementation.UsedParameters().Any();
|
||||
if (usesParams)
|
||||
{
|
||||
return $"{name.First().Replace(".","_")}({ToLua(arg.First())}, parameters)";
|
||||
}
|
||||
return $"{name.First().Replace(".","_")}({ToLua(arg.First())})";
|
||||
}
|
||||
|
||||
return "\n " + funcName + "({\n " + string.Join(",\n ", luaExprs) +
|
||||
"\n })";
|
||||
}
|
||||
|
||||
collectedMapping.Clear();
|
||||
var dottedFunction = new List<IExpression>();
|
||||
dottedFunction.Clear();
|
||||
|
@ -116,7 +116,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
bare.Types.First() is Curry curr &&
|
||||
curr.ArgType.Equals(Typs.String)) {
|
||||
var applied = new Apply(bare, new Constant(curr.ArgType, ("tags", "\"" + key + "\"")));
|
||||
return ToLua(applied.Optimize(), key);
|
||||
return ToLua(applied.Optimize(out _), key);
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,7 +139,13 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
}
|
||||
|
||||
if (baseFunc.Name.Equals(Funcs.Dot.Name)) {
|
||||
if (args.Count == 1 || forceFirstArgInDot) {
|
||||
if (args.Count == 1 )
|
||||
{
|
||||
return ToLua(args[0]);
|
||||
}
|
||||
|
||||
if (forceFirstArgInDot)
|
||||
{
|
||||
return ToLua(args[0]);
|
||||
}
|
||||
|
||||
|
@ -173,7 +179,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
|
||||
AddDependenciesFor(called);
|
||||
AddFunction(called);
|
||||
return $"{fc.CalledFunctionName.AsLuaIdentifier()}(parameters, tags, result)";
|
||||
return $"{fc.CalledFunctionName.AsLuaIdentifier()}(tags, parameters)";
|
||||
case Constant c:
|
||||
return ConstantToLua(c);
|
||||
case Mapping m:
|
||||
|
@ -241,12 +247,12 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
/// <returns></returns>
|
||||
private string ConstantToLua(Constant c)
|
||||
{
|
||||
var o = c.Evaluate(_context);
|
||||
var o = c.Get();
|
||||
switch (o) {
|
||||
case LuaLiteral lua:
|
||||
return lua.Lua;
|
||||
case IExpression e:
|
||||
return ConstantToLua(new Constant(e.Types.First(), e.Evaluate(null)));
|
||||
return ToLua(e);
|
||||
case int i:
|
||||
return "" + i;
|
||||
case double d:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AspectedRouting.IO.itinero1;
|
||||
|
@ -35,17 +36,21 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
return true;
|
||||
});
|
||||
|
||||
var expression = meta.ExpressionImplementation;
|
||||
var expression = Funcs.Either(Funcs.Id, Funcs.Const, meta.ExpressionImplementation)
|
||||
.Apply(new LuaLiteral(Typs.Tags, "tags"))
|
||||
.PruneTypes(t => !(t is Curry))
|
||||
.SpecializeToSmallestType()
|
||||
.Optimize(out _);
|
||||
if (!expression.Types.Any())
|
||||
{
|
||||
throw new Exception("Could not optimize expression with applied tags");
|
||||
}
|
||||
|
||||
var ctx = Context;
|
||||
_context = _context.WithAspectName(meta.Name);
|
||||
|
||||
var body = "";
|
||||
if (_useSnippets) {
|
||||
if (expression.Types.First() is Curry c) {
|
||||
expression = expression.Apply(new LuaLiteral(Typs.Tags, "tags"));
|
||||
}
|
||||
|
||||
body = Utils.Lines(
|
||||
" local r = nil",
|
||||
" " + Snippets.Convert(this, "r", expression).Indent(),
|
||||
|
@ -56,7 +61,6 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
body = " return " + ToLua(expression);
|
||||
}
|
||||
|
||||
|
||||
var impl = Utils.Lines(
|
||||
"--[[",
|
||||
meta.Description,
|
||||
|
@ -68,7 +72,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
"Number of combintations: " + numberOfCombinations,
|
||||
"Returns values: ",
|
||||
"]]",
|
||||
"function " + meta.Name.AsLuaIdentifier() + "(parameters, tags, result)" + funcNameDeclaration,
|
||||
"function " + meta.Name.AsLuaIdentifier() + "(tags, parameters)" + funcNameDeclaration,
|
||||
body,
|
||||
"end"
|
||||
);
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
|||
internal void AddDep(string name)
|
||||
{
|
||||
if (name.StartsWith("mapping")) {
|
||||
Console.Error.WriteLine(">>>");
|
||||
throw new Exception("A mapping was added as dependency - this is a bug");
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
|||
result += "end\n";
|
||||
// note: we do not do an 'elseif' as we have to fallthrough
|
||||
if (result.Contains("tags[\"nil\"]")) {
|
||||
Console.WriteLine("EUHM");
|
||||
Console.WriteLine("Warning: FirstMatchOf has a 'nil' in the indexes due to expression "+t.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
|||
|
||||
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
||||
{
|
||||
var fCond = args[0].Optimize();
|
||||
var fCond = args[0].Optimize(out _);
|
||||
var fValue = args[1];
|
||||
IExpression fElse = null;
|
||||
var arg = args[2];
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AspectedRouting.Language;
|
||||
using AspectedRouting.Language.Typ;
|
||||
using static AspectedRouting.Language.Deconstruct;
|
||||
|
||||
namespace AspectedRouting.IO.LuaSnippets
|
||||
{
|
||||
|
@ -11,29 +13,56 @@ namespace AspectedRouting.IO.LuaSnippets
|
|||
|
||||
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
||||
{
|
||||
var cond = args[0].Optimize();
|
||||
var cond = args[0].Optimize(out _);
|
||||
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();
|
||||
{
|
||||
var fa = new List<IExpression>();
|
||||
if (UnApply(
|
||||
IsFunc(Funcs.IsNull),
|
||||
Assign(fa)
|
||||
).Invoke(cond))
|
||||
{
|
||||
|
||||
if (fa.First().ToString() == ifElse.ToString())
|
||||
{
|
||||
var result = "";
|
||||
|
||||
// We calculate the value that we need
|
||||
result += Snippets.Convert(lua,assignTo , ifElse)+"\n";
|
||||
result += "if (" + assignTo + " == nil) then\n";
|
||||
result += " " + Snippets.Convert(lua, assignTo, ifTrue).Indent();
|
||||
result += "end\n";
|
||||
return result;
|
||||
|
||||
}
|
||||
throw new Exception("TODO optimize with default");
|
||||
}
|
||||
}
|
||||
|
||||
result += "end\n";
|
||||
return result;
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,99 +21,150 @@ namespace AspectedRouting.IO.LuaSnippets
|
|||
|
||||
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
||||
{
|
||||
|
||||
// Multiply multiplies a list of values - we thus have to handle _each_ arg
|
||||
// Note: we get a single argument which is an expression resulting in a list of values
|
||||
var listToMultiply = args[0];
|
||||
var mappings = new List<Mapping>();
|
||||
var arg = new List<IExpression>();
|
||||
if (UnApply(UnApply(
|
||||
IsFunc(Funcs.StringStringToTags),
|
||||
IsMapping(mappings)),
|
||||
Assign(arg)
|
||||
).Invoke(listToMultiply)) {
|
||||
var mapping = mappings.First();
|
||||
|
||||
var result = assignTo + " = " + _neutralValue + "\n";
|
||||
var mappingArg = arg.First();
|
||||
if (!Equals(mappingArg.Types.First(), Typs.Tags)) {
|
||||
return null;
|
||||
}
|
||||
{
|
||||
var mappings = new List<Mapping>();
|
||||
var arg = new List<IExpression>();
|
||||
if (args.Count == 1 && UnApply(UnApply(
|
||||
IsFunc(Funcs.StringStringToTags),
|
||||
IsMapping(mappings)),
|
||||
Assign(arg)
|
||||
).Invoke(args[0]))
|
||||
{
|
||||
var mapping = mappings.First();
|
||||
|
||||
string tags;
|
||||
if (mappingArg is LuaLiteral literal) {
|
||||
tags = literal.Lua;
|
||||
}
|
||||
else {
|
||||
tags = lua.FreeVar("tags");
|
||||
result += "local " + tags + " = nil\n";
|
||||
result += Snippets.Convert(lua, tags, mappingArg);
|
||||
}
|
||||
|
||||
var m = lua.FreeVar("m");
|
||||
result += " local " + m + " = nil\n";
|
||||
|
||||
foreach (var (key, func) in mapping.StringToResultFunctions) {
|
||||
result += "if (" + tags + "[\"" + key + "\"] ~= nil) then\n";
|
||||
result += m + " = nil\n";
|
||||
result += " " +
|
||||
Snippets.Convert(lua, m,
|
||||
func.Apply(new LuaLiteral(Typs.String, tags + "[\"" + key + "\"]"))).Indent() + "\n";
|
||||
result += "\n\n if (" + m + " ~= nil) then\n " +
|
||||
Combine(assignTo, m) +
|
||||
"\n end\n";
|
||||
result += "end\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
var listDotArgs = new List<IExpression>();
|
||||
if (UnApply(
|
||||
UnApply(IsFunc(Funcs.ListDot),
|
||||
Assign(listDotArgs)),
|
||||
Assign(arg)
|
||||
).Invoke(listToMultiply)) {
|
||||
var listDotArg = arg.First();
|
||||
if (!(listDotArgs.First().Evaluate(lua.Context) is List<IExpression> functionsToApply)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = " " + assignTo + " = " + _neutralValue + "\n";
|
||||
string tags;
|
||||
if (listDotArg is LuaLiteral literal) {
|
||||
tags = literal.Lua;
|
||||
}
|
||||
else {
|
||||
tags = lua.FreeVar("tags");
|
||||
result += " local " + tags + "\n";
|
||||
result += Snippets.Convert(lua, tags, listDotArg);
|
||||
}
|
||||
|
||||
var m = lua.FreeVar("m");
|
||||
result += " local " + m + "\n";
|
||||
foreach (var func in functionsToApply) {
|
||||
result += " " + m + " = nil\n";
|
||||
var subMapping = ExtractSubMapping(func);
|
||||
if (subMapping != null) {
|
||||
var (key, f) = subMapping.Value;
|
||||
var e = f.Apply(new LuaLiteral(Typs.String, tags + "[\"" + key + "\"]"));
|
||||
e = e.Optimize();
|
||||
result += Snippets.Convert(lua, m, e).Indent();
|
||||
}
|
||||
else {
|
||||
result += Snippets.Convert(lua, m, func.Apply(new LuaLiteral(Typs.Tags, "tags")));
|
||||
var result = assignTo + " = " + _neutralValue + "\n";
|
||||
var mappingArg = arg.First();
|
||||
if (!Equals(mappingArg.Types.First(), Typs.Tags))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string tags;
|
||||
if (mappingArg is LuaLiteral literal)
|
||||
{
|
||||
tags = literal.Lua;
|
||||
}
|
||||
else
|
||||
{
|
||||
tags = lua.FreeVar("tags");
|
||||
result += "local " + tags + " = nil\n";
|
||||
result += Snippets.Convert(lua, tags, mappingArg);
|
||||
}
|
||||
|
||||
result += "\n\n if (" + m + " ~= nil) then\n " + Combine(assignTo, m) + "\n end\n";
|
||||
var m = lua.FreeVar("m");
|
||||
result += " local " + m + " = nil\n";
|
||||
|
||||
foreach (var (key, func) in mapping.StringToResultFunctions)
|
||||
{
|
||||
result += "if (" + tags + "[\"" + key + "\"] ~= nil) then\n";
|
||||
result += m + " = nil\n";
|
||||
result += " " +
|
||||
Snippets.Convert(lua, m,
|
||||
func.Apply(new LuaLiteral(Typs.String, tags + "[\"" + key + "\"]"))).Indent() +
|
||||
"\n";
|
||||
result += "\n\n if (" + m + " ~= nil) then\n " +
|
||||
Combine(assignTo, m) +
|
||||
"\n end\n";
|
||||
result += "end\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
{
|
||||
// Print a 'listDot', assume 'tags' is the applied argument
|
||||
var arg = new List<IExpression>();
|
||||
|
||||
var listDotArgs = new List<IExpression>();
|
||||
if (args.Count == 1 && UnApply(
|
||||
UnApply(IsFunc(Funcs.ListDot),
|
||||
Assign(listDotArgs)),
|
||||
Assign(arg)
|
||||
).Invoke(args[0]))
|
||||
{
|
||||
var listDotArg = arg.First();
|
||||
if (!(listDotArgs.First().Evaluate(lua.Context) is List<IExpression> functionsToApply))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = " " + assignTo + " = " + _neutralValue + "\n";
|
||||
string tags;
|
||||
if (listDotArg is LuaLiteral literal)
|
||||
{
|
||||
tags = literal.Lua;
|
||||
}
|
||||
else
|
||||
{
|
||||
tags = lua.FreeVar("tags");
|
||||
result += " local " + tags + "\n";
|
||||
result += Snippets.Convert(lua, tags, listDotArg);
|
||||
}
|
||||
|
||||
var m = lua.FreeVar("m");
|
||||
result += " local " + m + "\n";
|
||||
foreach (var func in functionsToApply)
|
||||
{
|
||||
result += " " + m + " = nil\n";
|
||||
var subMapping = ExtractSubMapping(func);
|
||||
if (subMapping != null)
|
||||
{
|
||||
var (key, f) = subMapping.Value;
|
||||
var e = f.Apply(new LuaLiteral(Typs.String, tags + "[\"" + key + "\"]"));
|
||||
e = e.Optimize(out _);
|
||||
result += Snippets.Convert(lua, m, e).Indent();
|
||||
}
|
||||
else
|
||||
{
|
||||
result += Snippets.Convert(lua, m, func.Apply(new LuaLiteral(Typs.Tags, "tags")));
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
result += "\n\n if (" + m + " ~= nil) then\n " + Combine(assignTo, m) + "\n end\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
{
|
||||
|
||||
|
||||
var constantArgs = new List<Constant>();
|
||||
if (args.Count == 1 && IsConstant(constantArgs).Invoke(args[0]))
|
||||
{
|
||||
if (!(constantArgs.First().Get() is List<IExpression> listItems))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = " " + assignTo + " = " + _neutralValue + "\n";
|
||||
|
||||
|
||||
var m = lua.FreeVar("m");
|
||||
result += " local " + m + "\n";
|
||||
foreach (var listItem in listItems)
|
||||
{
|
||||
result += " " + m + " = nil\n";
|
||||
result += Snippets.Convert(lua, m, listItem).Indent();
|
||||
result += "\n\n if (" + m + " ~= nil) then\n " + Combine(assignTo, m) + "\n end\n";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Console.Error.WriteLine("ListFoldingSnippet encountered an unsupported expression");
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
|||
public static string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, IExpression e)
|
||||
{
|
||||
|
||||
var opt = e.Optimize();
|
||||
var opt = e.Optimize(out _);
|
||||
// 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();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AspectedRouting.IO.LuaSkeleton;
|
||||
|
@ -14,9 +15,9 @@ namespace AspectedRouting.IO.itinero1
|
|||
private string GenerateMainProfileFunction()
|
||||
{
|
||||
|
||||
var access = _skeleton.ToLua(_profile.Access);
|
||||
var oneway = _skeleton.ToLua(_profile.Oneway);
|
||||
var speed = _skeleton.ToLua(_profile.Speed);
|
||||
var access = _skeleton.ToLuaWithTags(_profile.Access);
|
||||
var oneway = _skeleton.ToLuaWithTags(_profile.Oneway);
|
||||
var speed = _skeleton.ToLuaWithTags(_profile.Speed);
|
||||
|
||||
var impl = string.Join("\n",
|
||||
"",
|
||||
|
@ -58,13 +59,16 @@ namespace AspectedRouting.IO.itinero1
|
|||
var paramInLua = _skeleton.ToLua(new Parameter(parameterName));
|
||||
|
||||
|
||||
var exprInLua = _skeleton.ToLua(expression.Optimize(), forceFirstArgInDot: true);
|
||||
var resultTypes = expression.Types.Select(t => t.Uncurry().Last());
|
||||
if (resultTypes.Any(t => t.Name.Equals(Typs.Bool.Name)))
|
||||
var expr = Funcs.Either(Funcs.Id, Funcs.Const, expression).Apply(new LuaLiteral(Typs.Tags, "tags"))
|
||||
.SpecializeToSmallestType()
|
||||
.PruneTypes(t => !(t is Curry))
|
||||
.Optimize(out _);
|
||||
|
||||
if (expr.Types.Any(t => t.Name.Equals(Typs.Bool.Name)))
|
||||
{
|
||||
_skeleton. AddDep("parse");
|
||||
exprInLua = "parse(" + exprInLua + ")";
|
||||
expr = Funcs.Parse.Apply(expr).SpecializeToSmallestType();
|
||||
}
|
||||
var exprInLua = _skeleton.ToLua(expr);
|
||||
|
||||
impl += "\n " + string.Join("\n ",
|
||||
$"if({paramInLua} ~= 0) then",
|
||||
|
@ -108,9 +112,15 @@ namespace AspectedRouting.IO.itinero1
|
|||
var functionName = referenceName.AsLuaIdentifier();
|
||||
behaviourParameters.TryGetValue("description", out var description);
|
||||
|
||||
_skeleton.AddDep("copy_tags");
|
||||
var usedkeys = _profile.AllExpressionsFor(behaviourName, _context)
|
||||
.PossibleTagsRecursive(_context)
|
||||
.Select(t => "\""+ t.Key+"\"")
|
||||
.ToHashSet();
|
||||
|
||||
_skeleton.AddDep("remove_relation_prefix");
|
||||
var impl = string.Join("\n",
|
||||
"",
|
||||
"behaviour_"+functionName+"_used_keys = create_set({"+ string.Join(", " , usedkeys) + "})",
|
||||
"--[[",
|
||||
description,
|
||||
"]]",
|
||||
|
@ -124,6 +134,7 @@ namespace AspectedRouting.IO.itinero1
|
|||
impl += _parameterPrinter.DeclareParametersFor(behaviourParameters);
|
||||
|
||||
impl += " " + _profile.Name + "(parameters, tags, result)\n";
|
||||
impl += " copy_tags(tags, result.attributes_to_keep, behaviour_" + functionName + "_used_keys)\n";
|
||||
impl += "end\n";
|
||||
return (functionName, impl);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace AspectedRouting.IO.itinero1
|
|||
func.Add("");
|
||||
func.Add(" subresult.attributes_to_keep = {}");
|
||||
func.Add(" parameters = default_parameters()");
|
||||
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
||||
func.Add($" matched = {preProcName}(relation_tags, parameters)");
|
||||
func.Add(" if (matched) then");
|
||||
var tagKey = "_relation:" + calledInFunction.AsLuaIdentifier();
|
||||
extraKeys.Add(tagKey);
|
||||
|
@ -90,7 +90,7 @@ namespace AspectedRouting.IO.itinero1
|
|||
func.Add(" parameters = default_parameters()");
|
||||
func.Add(_parameterPrinter.DeclareParametersFor(parameters.Where(kv => usedParameters.Contains(kv.Key))
|
||||
.ToDictionary(kv => kv.Key, kv => kv.Value)));
|
||||
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
||||
func.Add($" matched = {preProcName}(relation_tags, parameters)");
|
||||
func.Add(" if (matched) then");
|
||||
tagKey = "_relation:" + behaviourName.AsLuaIdentifier() + ":" + calledInFunction.AsLuaIdentifier();
|
||||
extraKeys.Add(tagKey);
|
||||
|
|
|
@ -27,18 +27,19 @@ namespace AspectedRouting.IO.itinero1
|
|||
_aspectTestSuites = aspectTestSuites?.Where(suite => suite != null)
|
||||
?.Select(testSuite => testSuite.WithoutRelationTests())?.ToList();
|
||||
_profileTests = profileTests;
|
||||
_skeleton = new LuaSkeleton.LuaSkeleton(context, false);
|
||||
_skeleton = new LuaSkeleton.LuaSkeleton(context, true);
|
||||
_parameterPrinter = new LuaParameterPrinter(profile, _skeleton);
|
||||
}
|
||||
|
||||
public string ToLua()
|
||||
{
|
||||
_skeleton.AddDep("spoken_instructions");
|
||||
_skeleton.AddDep("spoken_instructions");
|
||||
|
||||
var (membershipFunction, extraKeys) = GenerateMembershipPreprocessor();
|
||||
var (profileOverview, behaviourFunctions) = GenerateProfileFunctions();
|
||||
var mainFunction = GenerateMainProfileFunction();
|
||||
var tests = new LuaTestPrinter(_skeleton, new List<string>{"unitTest","unitTestProfile"}).GenerateFullTestSuite(_profileTests, _aspectTestSuites);
|
||||
var tests = new LuaTestPrinter(_skeleton, new List<string> { "unitTest", "unitTestProfile" })
|
||||
.GenerateFullTestSuite(_profileTests, _aspectTestSuites);
|
||||
|
||||
|
||||
var keys = _profile.AllExpressions(_context).PossibleTags().Keys
|
||||
|
@ -62,7 +63,15 @@ namespace AspectedRouting.IO.itinero1
|
|||
"",
|
||||
profileOverview,
|
||||
"",
|
||||
_parameterPrinter.GenerateDefaultParameters()
|
||||
_parameterPrinter.GenerateDefaultParameters(),
|
||||
"",
|
||||
"function create_set(list)",
|
||||
" local set = {}",
|
||||
" for _, l in ipairs(list) do " +
|
||||
" set[l] = true" +
|
||||
" end",
|
||||
" return set",
|
||||
"end"
|
||||
};
|
||||
|
||||
|
||||
|
@ -106,7 +115,7 @@ namespace AspectedRouting.IO.itinero1
|
|||
var behaviourImplementations = new List<string>();
|
||||
foreach (var (behaviourName, behaviourParameters) in _profile.Behaviours)
|
||||
{
|
||||
var (functionName, implementation ) = GenerateBehaviourFunction(behaviourName, behaviourParameters);
|
||||
var (functionName, implementation) = GenerateBehaviourFunction(behaviourName, behaviourParameters);
|
||||
behaviourImplementations.Add(implementation);
|
||||
profiles.Add(
|
||||
string.Join(",\n ",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AspectedRouting.IO.LuaSkeleton;
|
||||
using AspectedRouting.Language;
|
||||
using AspectedRouting.Language.Typ;
|
||||
|
||||
|
@ -39,23 +40,22 @@ namespace AspectedRouting.IO.itinero2
|
|||
|
||||
// The expression might still have multiple typings,
|
||||
// which take inputs different from 'Tags', so we specialize the expr first
|
||||
var exprSpecialized = expr;
|
||||
var resultType = expr.Types.First();
|
||||
if (exprSpecialized.Types.Count() >=2) {
|
||||
exprSpecialized = expr.Specialize(new Curry(Typs.Tags, new Var("a")));
|
||||
if (exprSpecialized == null) {
|
||||
throw new Exception("Could not specialize expression to type tags -> $a");
|
||||
}
|
||||
resultType = (exprSpecialized.Types.First() as Curry).ResultType;
|
||||
var appliedExpr = Funcs.Either(Funcs.Id, Funcs.Const, expr)
|
||||
.Apply(new LuaLiteral(Typs.Tags, "tags").SpecializeToSmallestType())
|
||||
.PruneTypes(tp => !(tp is Curry));
|
||||
var exprSpecialized = appliedExpr.Optimize(out _);
|
||||
|
||||
if (exprSpecialized.Types.First().Equals(Typs.Bool) || exprSpecialized.Types.First().Equals(Typs.String))
|
||||
{
|
||||
_skeleton.AddDep("parse");
|
||||
exprSpecialized = Funcs.Parse.Apply(exprSpecialized);
|
||||
}
|
||||
|
||||
var exprInLua = _skeleton.ToLua(exprSpecialized);
|
||||
if (resultType.Equals(Typs.Bool) || resultType.Equals(Typs.String))
|
||||
if (exprInLua.Contains("constRight") || exprInLua.Contains("firstArg"))
|
||||
{
|
||||
_skeleton.AddDep("parse");
|
||||
exprInLua = "parse(" + exprInLua + ")";
|
||||
throw new Exception("Not optimized properly:" + exprSpecialized.Repr());
|
||||
}
|
||||
|
||||
aspects.Add(weight + " * " + exprInLua);
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ namespace AspectedRouting.IO.itinero2
|
|||
" local parameters = default_parameters()",
|
||||
_parameterPrinter.DeclareParametersFor(parameters),
|
||||
"",
|
||||
" local oneway = " + _skeleton.ToLua(_profile.Oneway),
|
||||
" local oneway = " + _skeleton.ToLuaWithTags(_profile.Oneway).Indent(),
|
||||
" tags.oneway = oneway",
|
||||
" -- An aspect describing oneway should give either 'both', 'against' or 'width'",
|
||||
|
||||
|
@ -134,7 +134,7 @@ namespace AspectedRouting.IO.itinero2
|
|||
"",
|
||||
" -- forward calculation. We set the meta tag '_direction' to 'width' to indicate that we are going forward. The other functions will pick this up",
|
||||
" tags[\"_direction\"] = \"with\"",
|
||||
" local access_forward = " + _skeleton.ToLua(_profile.Access),
|
||||
" local access_forward = " + _skeleton.ToLuaWithTags(_profile.Access).Indent(),
|
||||
" if(oneway == \"against\") then",
|
||||
" -- no 'oneway=both' or 'oneway=with', so we can only go back over this segment",
|
||||
" -- we overwrite the 'access_forward'-value with no; whatever it was...",
|
||||
|
@ -142,7 +142,7 @@ namespace AspectedRouting.IO.itinero2
|
|||
" end",
|
||||
" 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(),
|
||||
" result.forward_speed = " + _skeleton.ToLuaWithTags(_profile.Speed).Indent(),
|
||||
" tags.speed = result.forward_speed",
|
||||
" local priority = calculate_priority(parameters, tags, result, access_forward, oneway, result.forward_speed)",
|
||||
" if (priority <= 0) then",
|
||||
|
@ -154,7 +154,7 @@ namespace AspectedRouting.IO.itinero2
|
|||
"",
|
||||
" -- backward calculation",
|
||||
" tags[\"_direction\"] = \"against\" -- indicate the backward direction to priority calculation",
|
||||
" local access_backward = " + _skeleton.ToLua(_profile.Access),
|
||||
" local access_backward = " + _skeleton.ToLuaWithTags(_profile.Access).Indent(),
|
||||
" if(oneway == \"with\") then",
|
||||
" -- no 'oneway=both' or 'oneway=against', so we can only go forward over this segment",
|
||||
" -- we overwrite the 'access_forward'-value with no; whatever it was...",
|
||||
|
@ -162,7 +162,7 @@ namespace AspectedRouting.IO.itinero2
|
|||
" end",
|
||||
" 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(),
|
||||
" result.backward_speed = " + _skeleton.ToLuaWithTags(_profile.Speed).Indent(),
|
||||
" tags.speed = result.backward_speed",
|
||||
" local priority = calculate_priority(parameters, tags, result, access_backward, oneway, result.backward_speed)",
|
||||
" if (priority <= 0) then",
|
||||
|
|
|
@ -24,9 +24,12 @@ namespace AspectedRouting.IO.jsonParser
|
|||
return null;
|
||||
}
|
||||
|
||||
Console.WriteLine("Parsing " + fileName);
|
||||
Console.Write("Parsing " + fileName+"... ");
|
||||
|
||||
return doc.RootElement.ParseAspect(fileName, c);
|
||||
var aspect= doc.RootElement.ParseAspect(fileName, c);
|
||||
|
||||
Console.WriteLine($"\rAspect {aspect.Name} has type {string.Join(",", aspect.ExpressionImplementation.Types)}");
|
||||
return aspect;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -90,15 +93,26 @@ namespace AspectedRouting.IO.jsonParser
|
|||
filepath + " is not a valid profile; it does not contain the obligated parameter " + name);
|
||||
}
|
||||
|
||||
var defaultParameters = e.GetProperty("defaults").ParseParameters();
|
||||
|
||||
var contextWithParameters = new Context(context);
|
||||
foreach (var (paramName, paramExpression) in defaultParameters)
|
||||
{
|
||||
if (!context.Parameters.TryGetValue(paramName, out var previousParam))
|
||||
{
|
||||
contextWithParameters.AddParameter(paramName, paramExpression);
|
||||
}
|
||||
}
|
||||
|
||||
var vehicleTypes = GetTopProperty("vehicletypes").EnumerateArray().Select(
|
||||
el => el.GetString()).ToList();
|
||||
var metadata = GetTopProperty("metadata").EnumerateArray().Select(
|
||||
el => el.GetString()).ToList();
|
||||
|
||||
|
||||
var access = ParseProfileProperty(e, context, "access").Finalize();
|
||||
var oneway = ParseProfileProperty(e, context, "oneway").Finalize();
|
||||
var speed = ParseProfileProperty(e, context, "speed").Finalize();
|
||||
var access = ParseProfileProperty(e, contextWithParameters, "access").Finalize();
|
||||
var oneway = ParseProfileProperty(e, contextWithParameters, "oneway").Finalize();
|
||||
var speed = ParseProfileProperty(e, contextWithParameters, "speed").Finalize();
|
||||
|
||||
|
||||
IExpression TagsApplied(IExpression x)
|
||||
|
@ -152,7 +166,7 @@ namespace AspectedRouting.IO.jsonParser
|
|||
author,
|
||||
filepath?.DirectoryName ?? "unknown",
|
||||
vehicleTypes,
|
||||
e.GetProperty("defaults").ParseParameters(),
|
||||
defaultParameters,
|
||||
profiles,
|
||||
access,
|
||||
oneway,
|
||||
|
@ -293,6 +307,12 @@ namespace AspectedRouting.IO.jsonParser
|
|||
if (s.StartsWith("#"))
|
||||
{
|
||||
// This is a parameter, the type of it is free
|
||||
if (context.Parameters.TryGetValue(s.Substring(1), out var param))
|
||||
{
|
||||
return new Parameter(s).Specialize(param.Types);
|
||||
|
||||
}
|
||||
|
||||
return new Parameter(s);
|
||||
}
|
||||
|
||||
|
@ -511,7 +531,6 @@ namespace AspectedRouting.IO.jsonParser
|
|||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Aspect {name} has type {string.Join(",", expr.Types)}");
|
||||
return new AspectMetadata(
|
||||
expr,
|
||||
name,
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using AspectedRouting.Language;
|
||||
using AspectedRouting.Language.Functions;
|
||||
using AspectedRouting.Language.Typ;
|
||||
|
||||
[assembly: InternalsVisibleTo("AspectedRouting.Test")]
|
||||
namespace AspectedRouting.IO.jsonParser
|
||||
{
|
||||
public static partial class JsonParser
|
||||
{
|
||||
private static IExpression ParseProfileProperty(JsonElement e, Context c, string property)
|
||||
internal static IExpression ParseProfileProperty(JsonElement e, Context c, string property)
|
||||
{
|
||||
if (!e.TryGetProperty(property, out var prop)) {
|
||||
throw new ArgumentException("Not a valid profile: the declaration expression for '" + property +
|
||||
|
@ -23,7 +25,7 @@ namespace AspectedRouting.IO.jsonParser
|
|||
throw new Exception($"Could not parse field {property}, no valid typing for expression found");
|
||||
}
|
||||
|
||||
expr = expr.Optimize();
|
||||
expr = expr.Optimize(out _);
|
||||
expr = Funcs.Either(Funcs.Id, Funcs.Const, expr);
|
||||
var specialized = expr.Specialize(new Curry(Typs.Tags, new Var("a")));
|
||||
|
||||
|
@ -52,7 +54,7 @@ namespace AspectedRouting.IO.jsonParser
|
|||
string.Join(",", pruned.Types) + "\n" + pruned.TypeBreakdown());
|
||||
}
|
||||
|
||||
return pruned.Optimize();
|
||||
return pruned.Optimize(out _);
|
||||
}
|
||||
catch (Exception exc) {
|
||||
throw new Exception("While parsing the property " + property, exc);
|
||||
|
|
12
AspectedRouting/IO/lua/copy_tags.lua
Normal file
12
AspectedRouting/IO/lua/copy_tags.lua
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
--[[
|
||||
copies all attributes from the source-table into the target-table,
|
||||
but only if the key is listed in 'whitelist' (which is a set)
|
||||
]]
|
||||
function copy_tags(source, target, whitelist)
|
||||
for k, v in pairs(source) do
|
||||
if whitelist[k] then
|
||||
target[k] = v
|
||||
end
|
||||
end
|
||||
end
|
5
AspectedRouting/IO/lua/create_set.lua
Normal file
5
AspectedRouting/IO/lua/create_set.lua
Normal file
|
@ -0,0 +1,5 @@
|
|||
function create_set(list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
3
AspectedRouting/IO/lua/is_null.lua
Normal file
3
AspectedRouting/IO/lua/is_null.lua
Normal file
|
@ -0,0 +1,3 @@
|
|||
function is_null(a)
|
||||
return a == nil;
|
||||
end
|
|
@ -79,7 +79,7 @@ function must_match(needed_keys, table, tags, result)
|
|||
|
||||
-- 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!
|
||||
-- euhm, well, seems like we don't care about the attributes_to_keep; early return!
|
||||
return true
|
||||
end
|
||||
for _, key in ipairs(needed_keys) do
|
||||
|
|
|
@ -5,8 +5,7 @@ function unit_test(f, fname, index, expected, parameters, tags)
|
|||
failed_tests = true
|
||||
return
|
||||
end
|
||||
local result = {attributes_to_keep = {}}
|
||||
local actual = f(parameters, tags, result)
|
||||
local actual = f(tags)
|
||||
if(expected == "null" and actual == nil) then
|
||||
-- OK!
|
||||
elseif(tonumber(actual) and tonumber(expected) and math.abs(tonumber(actual) - tonumber(expected)) < 0.1) then
|
||||
|
|
|
@ -206,7 +206,7 @@ namespace AspectedRouting.Language
|
|||
if (diff.Any()) {
|
||||
throw new ArgumentException("No default value set for parameter: " + MetaList(diff));
|
||||
}
|
||||
|
||||
|
||||
var unused = defaultParameters.Except(usedParameters);
|
||||
if (unused.Any()) {
|
||||
Console.WriteLine("[WARNING] A default value is set for parameter, but it is unused: " +
|
||||
|
@ -254,6 +254,7 @@ namespace AspectedRouting.Language
|
|||
Console.WriteLine(
|
||||
$"[{pmd.Name}] WARNING: Some parameters only have a default value: {string.Join(", ", defaultOnly)}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void SanityCheck(this IExpression e)
|
||||
|
|
|
@ -33,6 +33,11 @@ namespace AspectedRouting.Language
|
|||
{
|
||||
Parameters.Add(name, new Constant(value));
|
||||
}
|
||||
|
||||
public void AddParameter(string name, IExpression value)
|
||||
{
|
||||
Parameters.Add(name, value);
|
||||
}
|
||||
|
||||
public void AddFunction(string name, AspectMetadata function)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,19 @@ namespace AspectedRouting.Language
|
|||
};
|
||||
}
|
||||
|
||||
public static Func<IExpression, bool> IsConstant(List<Constant> collect)
|
||||
{
|
||||
return e =>
|
||||
{
|
||||
if (!(e is Constant c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
collect.Add(c);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
public static Func<IExpression, bool> Assign(List<IExpression> collect)
|
||||
{
|
||||
|
@ -66,6 +79,19 @@ namespace AspectedRouting.Language
|
|||
return f.Name.Equals(fe.Name);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static Func<IExpression, bool> IsFunctionCall(List<string> names)
|
||||
{
|
||||
return e => {
|
||||
if (!(e is FunctionCall fc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
names.Add(fc.CalledFunctionName);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
public static Func<IExpression, bool> UnApplyAny(
|
||||
Func<IExpression, bool> matchFunc,
|
||||
|
@ -93,7 +119,7 @@ namespace AspectedRouting.Language
|
|||
}
|
||||
else {
|
||||
if (!doesMatch) {
|
||||
// All must match - otherwise we might have registered a wrong collectiin
|
||||
// All must match - otherwise we might have registered a wrong collection
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace AspectedRouting.Language.Expression
|
|||
/// </summary>
|
||||
public readonly Dictionary<Type, (IExpression f, IExpression a)> FunctionApplications;
|
||||
|
||||
private IExpression optimizedForm = null;
|
||||
|
||||
private Apply(string debugInfo, Dictionary<Type, (IExpression f, IExpression a)> argument)
|
||||
{
|
||||
_debugInfo = debugInfo;
|
||||
|
@ -27,15 +29,18 @@ namespace AspectedRouting.Language.Expression
|
|||
|
||||
public Apply(IExpression f, IExpression argument)
|
||||
{
|
||||
if (f == null || argument == null) {
|
||||
if (f == null || argument == null)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
|
||||
FunctionApplications = new Dictionary<Type, (IExpression f, IExpression a)>();
|
||||
|
||||
var typesCleaned = argument.Types.RenameVars(f.Types).ToList();
|
||||
foreach (var funcType in f.Types) {
|
||||
if (!(funcType is Curry c)) {
|
||||
foreach (var funcType in f.Types)
|
||||
{
|
||||
if (!(funcType is Curry c))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -43,10 +48,12 @@ namespace AspectedRouting.Language.Expression
|
|||
var expectedResultType = c.ResultType;
|
||||
|
||||
|
||||
foreach (var argType in typesCleaned) {
|
||||
foreach (var argType in typesCleaned)
|
||||
{
|
||||
// we try to unify the argType with the expected type
|
||||
var substitutions = expectedArgType.UnificationTable(argType);
|
||||
if (substitutions == null) {
|
||||
if (substitutions == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -56,25 +63,30 @@ namespace AspectedRouting.Language.Expression
|
|||
var actualFunction = f.Specialize(new Curry(actualArgType, actualResultType));
|
||||
var actualArgument = argument.Specialize(actualArgType);
|
||||
|
||||
if (actualFunction == null || actualArgument == null) {
|
||||
if (actualFunction == null || actualArgument == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FunctionApplications.ContainsKey(actualResultType)) {
|
||||
|
||||
if (FunctionApplications.ContainsKey(actualResultType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FunctionApplications.Add(actualResultType, (actualFunction, actualArgument));
|
||||
}
|
||||
}
|
||||
|
||||
if (!FunctionApplications.Any()) {
|
||||
try {
|
||||
_debugInfo = $"\n{f.Optimize().TypeBreakdown().Indent()}\n" +
|
||||
if (!FunctionApplications.Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
_debugInfo = $"\n{f.Optimize(out var _).TypeBreakdown().Indent()}\n" +
|
||||
"is given the argument: " +
|
||||
"(" + argument.Optimize().TypeBreakdown() + ")";
|
||||
"(" + argument.Optimize(out var _).TypeBreakdown() + ")";
|
||||
}
|
||||
catch (Exception) {
|
||||
catch (Exception)
|
||||
{
|
||||
_debugInfo = $"\n (NO OPT) {f.TypeBreakdown().Indent()}\n" +
|
||||
"is given the argument: " +
|
||||
"(" + argument.TypeBreakdown() + ")";
|
||||
|
@ -90,7 +102,8 @@ namespace AspectedRouting.Language.Expression
|
|||
|
||||
public object Evaluate(Context c, params IExpression[] arguments)
|
||||
{
|
||||
if (!Types.Any()) {
|
||||
if (!Types.Any())
|
||||
{
|
||||
throw new ArgumentException("Trying to invoke an invalid expression: " + this);
|
||||
}
|
||||
|
||||
|
@ -101,7 +114,8 @@ namespace AspectedRouting.Language.Expression
|
|||
var arg = argExpr;
|
||||
var allArgs = new IExpression[arguments.Length + 1];
|
||||
allArgs[0] = arg;
|
||||
for (var i = 0; i < arguments.Length; i++) {
|
||||
for (var i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
allArgs[i + 1] = arguments[i];
|
||||
}
|
||||
|
||||
|
@ -114,23 +128,42 @@ namespace AspectedRouting.Language.Expression
|
|||
return Specialize(allowedTypes);
|
||||
}
|
||||
|
||||
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
||||
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
||||
{
|
||||
var passed = this.FunctionApplications.Where(kv => allowedTypes.Invoke(kv.Key));
|
||||
if (!passed.Any()) {
|
||||
var passed = FunctionApplications.Where(kv => allowedTypes.Invoke(kv.Key));
|
||||
if (!passed.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Apply("pruned", new Dictionary<Type, (IExpression A, IExpression F)>(passed));
|
||||
}
|
||||
|
||||
public IExpression Optimize()
|
||||
public IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
if (Types.Count() == 0) {
|
||||
if (this.optimizedForm != null)
|
||||
{
|
||||
somethingChanged = this.optimizedForm != this;
|
||||
return this.optimizedForm;
|
||||
}
|
||||
this.optimizedForm = this.OptimizeInternal(out somethingChanged);
|
||||
if (!optimizedForm.Types.Any())
|
||||
{
|
||||
throw new Exception("Optimizing " + this.ToString() + " failed: cannot be typechecked anymore");
|
||||
}
|
||||
return this.optimizedForm;
|
||||
}
|
||||
|
||||
internal IExpression OptimizeInternal(out bool somethingChanged)
|
||||
{
|
||||
if (Types.Count() == 0)
|
||||
{
|
||||
throw new ArgumentException("This application contain no valid types, so cannot be optimized" + this);
|
||||
}
|
||||
|
||||
somethingChanged = false;
|
||||
// (eitherfunc dot id) id
|
||||
// => (const dot _) id => dot id => id
|
||||
// => (const dot _) id => dot id => id
|
||||
// or => (constRight _ id) id => id id => id
|
||||
if (
|
||||
UnApplyAny(
|
||||
|
@ -147,23 +180,37 @@ namespace AspectedRouting.Language.Expression
|
|||
Any),
|
||||
IsFunc(Funcs.Id)),
|
||||
IsFunc(Funcs.Id)
|
||||
).Invoke(this)) {
|
||||
).Invoke(this))
|
||||
{
|
||||
somethingChanged = true;
|
||||
return Funcs.Id;
|
||||
}
|
||||
|
||||
|
||||
if (Types.Count() > 1) {
|
||||
// Too much types to optimize
|
||||
if (Types.Count() > 1)
|
||||
{
|
||||
// Too much types to optimize: we optimize the subparts instead
|
||||
var optimized = new Dictionary<Type, (IExpression f, IExpression a)>();
|
||||
foreach (var (resultType, (f, a)) in FunctionApplications) {
|
||||
var fOpt = f.Optimize();
|
||||
var aOpt = a.Optimize();
|
||||
foreach (var (resultType, (f, a)) in FunctionApplications)
|
||||
{
|
||||
var fOpt = f.Optimize(out var scf);
|
||||
var aOpt = a.Optimize(out var sca);
|
||||
somethingChanged |= scf || sca;
|
||||
optimized.Add(resultType, (fOpt, aOpt));
|
||||
}
|
||||
|
||||
return new Apply(_debugInfo, optimized);
|
||||
if (somethingChanged)
|
||||
{
|
||||
return new Apply(_debugInfo, optimized);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// At this point, we know there only is a single type;
|
||||
// We can safely assume all the 'assign' will only match a single entry
|
||||
|
||||
{
|
||||
// id a => a
|
||||
var arg = new List<IExpression>();
|
||||
|
@ -171,11 +218,40 @@ namespace AspectedRouting.Language.Expression
|
|||
UnApplyAny(
|
||||
IsFunc(Funcs.Id),
|
||||
Assign(arg)
|
||||
).Invoke(this)) {
|
||||
return arg.First();
|
||||
).Invoke(this))
|
||||
{
|
||||
var argOpt = arg.First().Optimize(out _);
|
||||
somethingChanged = true;
|
||||
return argOpt;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var exprs = new List<Constant>();
|
||||
var arg = new List<IExpression>();
|
||||
// listDot ([f0, f1, f2, ...]) arg ---> [f0 arg, f1 arg, f2 arg, ...]
|
||||
if (UnApply(
|
||||
UnApply(
|
||||
IsFunc(Funcs.ListDot),
|
||||
IsConstant(exprs)
|
||||
),
|
||||
Assign(arg)
|
||||
).Invoke(this))
|
||||
{
|
||||
var a = arg.First();
|
||||
var c = exprs.First();
|
||||
if (c.Types.All(t => t is ListType))
|
||||
{
|
||||
// The constant is a list
|
||||
var o = (List<IExpression>)c.Get();
|
||||
somethingChanged = true;
|
||||
return new Constant(
|
||||
o.Select(e => e.Apply(a).Optimize(out var _)).ToList()
|
||||
);
|
||||
}
|
||||
// fallthrough!
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// ifdotted fcondition fthen felse arg => if (fcondition arg) (fthen arg) (felse arg)
|
||||
|
@ -194,38 +270,104 @@ namespace AspectedRouting.Language.Expression
|
|||
Assign(fthen)),
|
||||
Assign(felse)),
|
||||
Assign(arg)
|
||||
).Invoke(this)) {
|
||||
).Invoke(this))
|
||||
{
|
||||
var a = arg.First();
|
||||
somethingChanged = true;
|
||||
return
|
||||
Funcs.If.Apply(
|
||||
fcondition.First().Apply(a),
|
||||
fthen.First().Apply(a),
|
||||
felse.First().Apply(a)
|
||||
fcondition.First().Apply(a).Optimize(out var _),
|
||||
fthen.First().Apply(a).Optimize(out var _),
|
||||
felse.First().Apply(a).Optimize(out var _)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// ifdotted fcondition fthen <null> arg => if (fcondition arg) (fthen arg) (felse arg)
|
||||
var fcondition = new List<IExpression>();
|
||||
var fthen = new List<IExpression>();
|
||||
var arg = new List<IExpression>();
|
||||
|
||||
if (
|
||||
this.Types.Any(t => !(t is Curry)) &&
|
||||
UnApply(
|
||||
UnApply(
|
||||
UnApply(
|
||||
IsFunc(Funcs.IfDotted),
|
||||
Assign(fcondition)),
|
||||
Assign(fthen)),
|
||||
Assign(arg)
|
||||
).Invoke(this))
|
||||
{
|
||||
var a = arg.First();
|
||||
somethingChanged = true;
|
||||
return
|
||||
Funcs.If.Apply(
|
||||
fcondition.First().Apply(a).Optimize(out var _),
|
||||
fthen.First().Apply(a).Optimize(out var _)
|
||||
).Specialize(this.Types).PruneTypes(t => !(t is Curry)).Optimize(out _);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// (default x f) a --> if (isNull (f a)) x (f a)
|
||||
var defaultArg = new List<IExpression>();
|
||||
var f = new List<IExpression>();
|
||||
var a = new List<IExpression>();
|
||||
if (
|
||||
UnApply(
|
||||
UnApply(
|
||||
UnApply(
|
||||
IsFunc(Funcs.Default),
|
||||
Assign(defaultArg)
|
||||
),
|
||||
Assign(f)
|
||||
|
||||
), Assign(a)
|
||||
).Invoke(this))
|
||||
{
|
||||
|
||||
somethingChanged = true;
|
||||
var fa = f.First().Apply(a.First()).Optimize(out var _);
|
||||
return Funcs.If.Apply(
|
||||
Funcs.IsNull.Apply(fa)
|
||||
).Apply(defaultArg).Apply(fa);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// The fallback case
|
||||
// We couldn't optimize with a pattern, but the subparts might be optimizable
|
||||
var (f, a) = FunctionApplications.Values.First();
|
||||
|
||||
var (newFa, expr) = OptimizeApplicationPair(f, a);
|
||||
if (expr != null) {
|
||||
var (newFa, expr) = OptimizeApplicationPair(f, a, out var changed);
|
||||
if (expr != null)
|
||||
{
|
||||
somethingChanged = true;
|
||||
return expr;
|
||||
}
|
||||
|
||||
(f, a) = newFa.Value;
|
||||
return new Apply(f, a);
|
||||
if (changed)
|
||||
{
|
||||
somethingChanged = true;
|
||||
(f, a) = newFa.Value;
|
||||
return new Apply(f, a).Optimize(out _);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Visit(Func<IExpression, bool> visitor)
|
||||
{
|
||||
var continueVisit = visitor(this);
|
||||
if (!continueVisit) {
|
||||
if (!continueVisit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (_, (f, a)) in FunctionApplications) {
|
||||
foreach (var (_, (f, a)) in FunctionApplications)
|
||||
{
|
||||
f.Visit(visitor);
|
||||
a.Visit(visitor);
|
||||
}
|
||||
|
@ -235,10 +377,13 @@ namespace AspectedRouting.Language.Expression
|
|||
{
|
||||
var newArgs = new Dictionary<Type, (IExpression f, IExpression a)>();
|
||||
|
||||
foreach (var allowedType in allowedTypes) {
|
||||
foreach (var (resultType, (funExpr, argExpr)) in FunctionApplications) {
|
||||
foreach (var allowedType in allowedTypes)
|
||||
{
|
||||
foreach (var (resultType, (funExpr, argExpr)) in FunctionApplications)
|
||||
{
|
||||
var substitutions = resultType.UnificationTable(allowedType, true);
|
||||
if (substitutions == null) {
|
||||
if (substitutions == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -250,7 +395,8 @@ namespace AspectedRouting.Language.Expression
|
|||
var actualFunction = funExpr.Specialize(substitutions);
|
||||
var actualArgument = argExpr.Specialize(substitutions);
|
||||
|
||||
if (actualFunction == null || actualArgument == null) {
|
||||
if (actualFunction == null || actualArgument == null)
|
||||
{
|
||||
// One of the subexpressions can't be optimized
|
||||
return null;
|
||||
}
|
||||
|
@ -259,34 +405,47 @@ namespace AspectedRouting.Language.Expression
|
|||
}
|
||||
}
|
||||
|
||||
if (!newArgs.Any()) {
|
||||
if (!newArgs.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Apply(_debugInfo, newArgs);
|
||||
}
|
||||
|
||||
private ((IExpression fOpt, IExpression fArg)?, IExpression result) OptimizeApplicationPair(IExpression f,
|
||||
IExpression a)
|
||||
private ((IExpression fOpt, IExpression fArg)?, IExpression result) OptimizeApplicationPair(
|
||||
IExpression fRaw,
|
||||
IExpression a,
|
||||
out bool somethingChanged)
|
||||
{
|
||||
f = f.Optimize();
|
||||
somethingChanged = false;
|
||||
var f = fRaw.Optimize(out var scf);
|
||||
somethingChanged |= scf;
|
||||
|
||||
if (f.Types.Count() == 0)
|
||||
{
|
||||
throw new ArgumentException("Optimizing " + f + " failed, no types returned. The original expression\n "+fRaw.ToString()+"has types"+string.Join("\n ", fRaw.Types));
|
||||
}
|
||||
|
||||
a = a.Optimize();
|
||||
|
||||
switch (f) {
|
||||
a = a.Optimize(out var sca);
|
||||
somethingChanged |= sca;
|
||||
switch (f)
|
||||
{
|
||||
case Id _:
|
||||
return (null, a);
|
||||
|
||||
case Apply apply:
|
||||
|
||||
if (apply.F is Const _) {
|
||||
if (apply.F is Const _)
|
||||
{
|
||||
// (const x) y -> y
|
||||
// apply == (const x) thus we return 'x' and ignore 'a'
|
||||
|
||||
return (null, apply.A);
|
||||
}
|
||||
|
||||
if (apply.F is ConstRight _) {
|
||||
if (apply.F is ConstRight _)
|
||||
{
|
||||
// constRight x y -> y
|
||||
// apply == (constRight x) so we return a
|
||||
return (null, a);
|
||||
|
@ -300,12 +459,14 @@ namespace AspectedRouting.Language.Expression
|
|||
Assign(f0)
|
||||
),
|
||||
Assign(f1)).Invoke(apply)
|
||||
) {
|
||||
)
|
||||
{
|
||||
// apply == ((dot f0) f1)
|
||||
// ((dot f0) f1) a is the actual expression, but arg is already split of
|
||||
|
||||
// f0 (f1 arg)
|
||||
// which used to be (f0 . f1) arg
|
||||
somethingChanged = true;
|
||||
return ((f0.First(), new Apply(f1.First(), a)), null);
|
||||
}
|
||||
|
||||
|
@ -318,21 +479,82 @@ namespace AspectedRouting.Language.Expression
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
if (!FunctionApplications.Any()) {
|
||||
if (!FunctionApplications.Any())
|
||||
{
|
||||
return "NOT-TYPECHECKABLE APPLICATION: " + _debugInfo;
|
||||
}
|
||||
|
||||
var (f, arg) = FunctionApplications.Values.First();
|
||||
if (f is Id _) {
|
||||
if (f is Id _)
|
||||
{
|
||||
return arg.ToString();
|
||||
}
|
||||
|
||||
var extra = "";
|
||||
if (FunctionApplications.Count() > 1) {
|
||||
if (FunctionApplications.Count() > 1)
|
||||
{
|
||||
extra = " [" + FunctionApplications.Count + " IMPLEMENTATIONS]";
|
||||
}
|
||||
|
||||
return $"({f} {arg.ToString().Indent()})" + extra;
|
||||
}
|
||||
|
||||
public bool Equals(IExpression other)
|
||||
{
|
||||
if (!(other is Apply apply))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var otherOptions = apply.FunctionApplications;
|
||||
if (otherOptions.Count != FunctionApplications.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var (type, (otherF, otherA)) in otherOptions)
|
||||
{
|
||||
if (!FunctionApplications.TryGetValue(type, out var tuple))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!otherF.Equals(tuple.f))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!otherA.Equals(tuple.a))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string Repr()
|
||||
{
|
||||
if (this.Types.Count() == 1)
|
||||
{
|
||||
var f = this.F.Repr().Replace("\n", "\n ");
|
||||
var a = this.A.Repr().Replace("\n", "\n ");
|
||||
|
||||
return $"new Apply( // {string.Join(" ; ", this.Types)}\n {f},\n {a})";
|
||||
}
|
||||
|
||||
var r = "new Apply(";
|
||||
|
||||
foreach (var (type, (f, a)) in this.FunctionApplications)
|
||||
{
|
||||
r += "\n // " + type+"\n";
|
||||
r += " | " + f.Repr().Replace("\n", "\n | ")+",\n";
|
||||
r += " | " + a.Repr().Replace("\n", "\n | ")+"\n";
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -32,7 +32,6 @@ namespace AspectedRouting.Language.Expression
|
|||
|
||||
public object Evaluate(Context c, params IExpression[] arguments)
|
||||
{
|
||||
|
||||
return ExpressionImplementation.Evaluate(c, arguments);
|
||||
}
|
||||
|
||||
|
@ -43,20 +42,29 @@ namespace AspectedRouting.Language.Expression
|
|||
Name, Description, Author, Unit, Filepath);
|
||||
}
|
||||
|
||||
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
||||
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
||||
{
|
||||
var e = ExpressionImplementation.PruneTypes(allowedTypes);
|
||||
if (e == null) {
|
||||
if (e == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AspectMetadata(e, Name, Description, Author, Unit,
|
||||
Filepath, ProfileInternal);
|
||||
}
|
||||
|
||||
public IExpression Optimize()
|
||||
public IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
return new AspectMetadata(ExpressionImplementation.Optimize(),
|
||||
Name, Description, Author, Unit, Filepath);
|
||||
var optE = ExpressionImplementation.Optimize(out var sc);
|
||||
somethingChanged = sc;
|
||||
if (sc)
|
||||
{
|
||||
return new AspectMetadata(optE,
|
||||
Name, Description, Author, Unit, Filepath);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Visit(Func<IExpression, bool> f)
|
||||
|
@ -74,5 +82,20 @@ namespace AspectedRouting.Language.Expression
|
|||
{
|
||||
return $"# {Name}; {Unit} by {Author}\n\n# by {Author}\n# {Description}\n{ExpressionImplementation}";
|
||||
}
|
||||
|
||||
public bool Equals(IExpression other)
|
||||
{
|
||||
if (other is AspectMetadata amd)
|
||||
{
|
||||
return amd.ExpressionImplementation.Equals(ExpressionImplementation);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Repr()
|
||||
{
|
||||
return "Aspect_" + Name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,8 +44,9 @@ namespace AspectedRouting.Language.Expression
|
|||
return new FunctionCall(this.Name, passedTypes);
|
||||
}
|
||||
|
||||
public virtual IExpression Optimize()
|
||||
public virtual IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
somethingChanged = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -100,5 +101,20 @@ namespace AspectedRouting.Language.Expression
|
|||
|
||||
return dict;
|
||||
}
|
||||
|
||||
public bool Equals(IExpression other)
|
||||
{
|
||||
if (other is Function f)
|
||||
{
|
||||
return f.Name.Equals(this.Name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Repr()
|
||||
{
|
||||
return "Funcs."+this.Name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,7 +33,11 @@ namespace AspectedRouting.Language.Expression
|
|||
Types = types;
|
||||
}
|
||||
|
||||
public object Evaluate(Context c, params IExpression[] arguments)
|
||||
public FunctionCall(string name, Type type): this(name, new []{type}){
|
||||
|
||||
}
|
||||
|
||||
public object Evaluate(Context c, params IExpression[] arguments)
|
||||
{
|
||||
|
||||
var func = c.GetFunction(_name);
|
||||
|
@ -62,8 +66,9 @@ namespace AspectedRouting.Language.Expression
|
|||
return new FunctionCall(this._name, passedTypes);
|
||||
}
|
||||
|
||||
public IExpression Optimize()
|
||||
public IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
somethingChanged = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -87,6 +92,21 @@ namespace AspectedRouting.Language.Expression
|
|||
f(this);
|
||||
}
|
||||
|
||||
public bool Equals(IExpression other)
|
||||
{
|
||||
if (other is FunctionCall fc)
|
||||
{
|
||||
return fc._name.Equals(this._name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Repr()
|
||||
{
|
||||
return "new FunctionCall(\"" + this._name + "\")";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"${_name}";
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace AspectedRouting.Language.Expression
|
|||
public string Author { get; }
|
||||
public string Filename { get; }
|
||||
public List<string> VehicleTyps { get; }
|
||||
|
||||
|
||||
/*
|
||||
* Which tags are included in the routerdb but are _not_ used for routeplanning?
|
||||
* Typically these are tags that are useful for navigation (name of the road, is this a tunnel, ...)
|
||||
|
@ -29,6 +29,7 @@ namespace AspectedRouting.Language.Expression
|
|||
public IExpression Oneway { get; }
|
||||
public IExpression Speed { get; }
|
||||
public Dictionary<string, IExpression> Priority { get; }
|
||||
|
||||
/**
|
||||
* Moment of last change of any upstream file
|
||||
*/
|
||||
|
@ -45,9 +46,9 @@ namespace AspectedRouting.Language.Expression
|
|||
Author = author;
|
||||
Filename = filename;
|
||||
VehicleTyps = vehicleTyps;
|
||||
Access = access.Optimize();
|
||||
Oneway = oneway.Optimize();
|
||||
Speed = speed.Optimize();
|
||||
Access = access.Optimize(out var _);
|
||||
Oneway = oneway.Optimize(out var _);
|
||||
Speed = speed.Optimize(out var _);
|
||||
Priority = priority;
|
||||
Metadata = metadata;
|
||||
LastChange = lastChange;
|
||||
|
@ -57,21 +58,22 @@ namespace AspectedRouting.Language.Expression
|
|||
CheckTypes(Access, "access");
|
||||
CheckTypes(Oneway, "oneway");
|
||||
CheckTypes(Speed, "speed");
|
||||
|
||||
}
|
||||
|
||||
private static void CheckTypes(IExpression e, string name)
|
||||
{
|
||||
if (e.Types.Count() == 1) {
|
||||
if (e.Types.Count() == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception("Insufficient specialization: " + name + " has multiple types left, namely " + e.Types.Pretty());
|
||||
throw new Exception("Insufficient specialization: " + name + " has multiple types left, namely " +
|
||||
e.Types.Pretty());
|
||||
}
|
||||
|
||||
public List<IExpression> AllExpressions(Context ctx)
|
||||
{
|
||||
var l = new List<IExpression> {Access, Oneway, Speed};
|
||||
var l = new List<IExpression> { Access, Oneway, Speed };
|
||||
l.AddRange(DefaultParameters.Values);
|
||||
l.AddRange(Behaviours.Values.SelectMany(b => b.Values));
|
||||
l.AddRange(Priority.Values);
|
||||
|
@ -88,6 +90,7 @@ namespace AspectedRouting.Language.Expression
|
|||
var called = ctx.GetFunction(fc.CalledFunctionName);
|
||||
allExpr.Add(called);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
@ -95,6 +98,41 @@ namespace AspectedRouting.Language.Expression
|
|||
return allExpr;
|
||||
}
|
||||
|
||||
public List<IExpression> AllExpressionsFor(string behaviourName, Context context)
|
||||
{
|
||||
var allExpressions = new List<IExpression>();
|
||||
allExpressions.Add(Access);
|
||||
allExpressions.Add(Oneway);
|
||||
allExpressions.Add(Speed);
|
||||
|
||||
var behaviourContext = new Context(context);
|
||||
var behaviourParameters = ParametersFor(behaviourName);
|
||||
|
||||
|
||||
foreach (var (paramName, valueexpression) in Priority)
|
||||
{
|
||||
var weightingFactor = behaviourParameters[paramName].Evaluate(behaviourContext);
|
||||
if (weightingFactor is double d)
|
||||
{
|
||||
if (d == 0.0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (weightingFactor is int i)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
allExpressions.Add(valueexpression);
|
||||
}
|
||||
|
||||
return allExpressions;
|
||||
}
|
||||
|
||||
public Dictionary<string, IExpression> ParametersFor(string behaviour)
|
||||
{
|
||||
|
@ -122,11 +160,11 @@ namespace AspectedRouting.Language.Expression
|
|||
}
|
||||
|
||||
c = c.WithParameters(ParametersFor(behaviour))
|
||||
.WithAspectName(this.Name);
|
||||
.WithAspectName(Name);
|
||||
tags = new Dictionary<string, string>(tags);
|
||||
var canAccess = Access.Run(c, tags);
|
||||
tags["access"] = "" + canAccess;
|
||||
var speed = (double) Speed.Run(c, tags);
|
||||
var speed = (double)Speed.Run(c, tags);
|
||||
tags["speed"] = "" + speed;
|
||||
var oneway = Oneway.Run(c, tags);
|
||||
tags["oneway"] = "" + oneway;
|
||||
|
@ -143,7 +181,7 @@ namespace AspectedRouting.Language.Expression
|
|||
var weightExplanation = new List<string>();
|
||||
foreach (var (paramName, expression) in Priority)
|
||||
{
|
||||
var aspectInfluence = (double) c.Parameters[paramName].Evaluate(c);
|
||||
var aspectInfluence = (double)c.Parameters[paramName].Evaluate(c);
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
if (aspectInfluence == 0)
|
||||
{
|
||||
|
@ -193,8 +231,16 @@ namespace AspectedRouting.Language.Expression
|
|||
canAccess = "no";
|
||||
}
|
||||
|
||||
return new ProfileResult((string) canAccess, (string) oneway, speed, priority,
|
||||
string.Join("\n ", weightExplanation));
|
||||
if (canAccess is string canAccessString && oneway is string onewayString)
|
||||
{
|
||||
return new ProfileResult(canAccessString, onewayString, speed, priority,
|
||||
string.Join("\n ", weightExplanation));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("CanAccess or oneway are not strings but " + canAccess.GetType().ToString() +
|
||||
" and " + (oneway?.GetType()?.ToString() ?? "<null>"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace AspectedRouting.Language
|
|||
public static readonly Function Eq = new Eq();
|
||||
public static readonly Function NotEq = new NotEq();
|
||||
public static readonly Function Inv = new Inv();
|
||||
public static readonly Function IsNull = new IsNull();
|
||||
|
||||
public static readonly Function Default = new Default();
|
||||
|
||||
|
@ -94,7 +95,7 @@ namespace AspectedRouting.Language
|
|||
|
||||
// TODO FIX THIS so that it works
|
||||
// An argument 'optimizes' it's types from 'string -> bool' to 'string -> string'
|
||||
var eOpt = eSmallest.Optimize();
|
||||
var eOpt = eSmallest.Optimize(out _);
|
||||
if (eOpt == null || eOpt.Types.Count() == 0)
|
||||
{
|
||||
throw new Exception("Could not optimize " + eSmallest);
|
||||
|
@ -106,6 +107,10 @@ namespace AspectedRouting.Language
|
|||
|
||||
public static IExpression SpecializeToSmallestType(this IExpression e)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
throw new Exception("Cannot specialize null to a smallest type");
|
||||
}
|
||||
if (e.Types.Count() == 1)
|
||||
{
|
||||
return e;
|
||||
|
@ -160,7 +165,8 @@ namespace AspectedRouting.Language
|
|||
|
||||
var lastArg = args[args.Count - 1];
|
||||
var firstArgs = args.GetRange(0, args.Count - 1);
|
||||
return new Apply(Apply(function, firstArgs), lastArg);
|
||||
var applied = Apply(function, firstArgs);
|
||||
return new Apply(applied, lastArg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,9 +14,11 @@ namespace AspectedRouting.Language.Functions
|
|||
public Constant(IEnumerable<Type> types, object o)
|
||||
{
|
||||
Types = types.ToList();
|
||||
if (o is IEnumerable<IExpression> enumerable) {
|
||||
if (o is IEnumerable<IExpression> enumerable)
|
||||
{
|
||||
o = enumerable.ToList();
|
||||
if (enumerable.Any(x => x == null)) {
|
||||
if (enumerable.Any(x => x == null))
|
||||
{
|
||||
throw new NullReferenceException("Some subexpression is null");
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +28,12 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public Constant(Type t, object o)
|
||||
{
|
||||
Types = new List<Type> {t};
|
||||
if (o is IEnumerable<IExpression> enumerable) {
|
||||
Types = new List<Type> { t };
|
||||
if (o is IEnumerable<IExpression> enumerable)
|
||||
{
|
||||
o = enumerable.ToList();
|
||||
if (enumerable.Any(x => x == null)) {
|
||||
if (enumerable.Any(x => x == null))
|
||||
{
|
||||
throw new NullReferenceException("Some subexpression is null");
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +46,8 @@ namespace AspectedRouting.Language.Functions
|
|||
var tps = exprs
|
||||
.SpecializeToCommonTypes(out var specializedVersions)
|
||||
.Select(t => new ListType(t));
|
||||
if (specializedVersions.Any(x => x == null)) {
|
||||
if (specializedVersions.Any(x => x == null))
|
||||
{
|
||||
throw new Exception("Specializing to common types failed for " +
|
||||
string.Join(",", exprs.Select(e => e.ToString())));
|
||||
}
|
||||
|
@ -53,40 +58,50 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public Constant(IReadOnlyCollection<IExpression> exprs)
|
||||
{
|
||||
try {
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
Types = exprs
|
||||
.SpecializeToCommonTypes(out var specializedVersions)
|
||||
.Select(t => new ListType(t))
|
||||
.ToList();
|
||||
if (specializedVersions.Any(x => x == null)) {
|
||||
throw new NullReferenceException("Some subexpression is null");
|
||||
specializedVersions = specializedVersions.ToList();
|
||||
if (specializedVersions.Any(x => x == null))
|
||||
{
|
||||
Console.Error.WriteLine(">> Some subexpressions of the list are null:");
|
||||
foreach (var expr in exprs)
|
||||
{
|
||||
Console.Error.WriteLine(expr.Repr());
|
||||
Console.Error.WriteLine("\n-------------------------\n");
|
||||
}
|
||||
|
||||
throw new NullReferenceException("Some subexpression of specialized versions are null");
|
||||
}
|
||||
|
||||
_o = specializedVersions.ToList();
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception("While creating a list with members " +
|
||||
string.Join(", ", exprs.Select(x => x.Optimize())) +
|
||||
string.Join(", ", exprs.Select(x => x.Optimize(out var _))) +
|
||||
$" {e.Message}", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Constant(string s)
|
||||
{
|
||||
Types = new List<Type> {Typs.String};
|
||||
Types = new List<Type> { Typs.String };
|
||||
_o = s;
|
||||
}
|
||||
|
||||
public Constant(double d)
|
||||
{
|
||||
if (d >= 0) {
|
||||
Types = new[] {Typs.Double, Typs.PDouble};
|
||||
if (d >= 0)
|
||||
{
|
||||
Types = new[] { Typs.Double, Typs.PDouble };
|
||||
}
|
||||
else {
|
||||
Types = new[] {Typs.Double};
|
||||
else
|
||||
{
|
||||
Types = new[] { Typs.Double };
|
||||
}
|
||||
|
||||
_o = d;
|
||||
|
@ -94,11 +109,13 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public Constant(int i)
|
||||
{
|
||||
if (i >= 0) {
|
||||
Types = new[] {Typs.Double, Typs.Nat, Typs.Nat, Typs.PDouble};
|
||||
if (i >= 0)
|
||||
{
|
||||
Types = new[] { Typs.Double, Typs.Nat, Typs.Nat, Typs.PDouble };
|
||||
}
|
||||
else {
|
||||
Types = new[] {Typs.Double, Typs.Int};
|
||||
else
|
||||
{
|
||||
Types = new[] { Typs.Double, Typs.Int };
|
||||
}
|
||||
|
||||
_o = i;
|
||||
|
@ -106,16 +123,17 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public Constant(Dictionary<string, string> tags)
|
||||
{
|
||||
Types = new[] {Typs.Tags};
|
||||
Types = new[] { Typs.Tags };
|
||||
_o = tags;
|
||||
}
|
||||
|
||||
public IEnumerable<Type> Types { get; }
|
||||
|
||||
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
||||
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
||||
{
|
||||
var passedTypes = Types.Where(allowedTypes);
|
||||
if (!passedTypes.Any()) {
|
||||
if (!passedTypes.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -124,28 +142,32 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public object Evaluate(Context c, params IExpression[] args)
|
||||
{
|
||||
if (_o is IExpression e) {
|
||||
if (_o is IExpression e)
|
||||
{
|
||||
return e.Evaluate(c).Pretty();
|
||||
}
|
||||
|
||||
|
||||
if (Types.Count() > 1) {
|
||||
if (Types.Count() > 1)
|
||||
{
|
||||
return _o;
|
||||
}
|
||||
|
||||
var t = Types.First();
|
||||
switch (t) {
|
||||
switch (t)
|
||||
{
|
||||
case DoubleType _:
|
||||
case PDoubleType _:
|
||||
if (_o is int i) {
|
||||
if (_o is int i)
|
||||
{
|
||||
return
|
||||
(double) i; // I know, it seems absurd having to write this as it is nearly the same as the return beneath, but it _is_ needed
|
||||
(double)i; // I know, it seems absurd having to write this as it is nearly the same as the return beneath, but it _is_ needed
|
||||
}
|
||||
|
||||
return (double) _o;
|
||||
return (double)_o;
|
||||
case IntType _:
|
||||
case NatType _:
|
||||
return (int) _o;
|
||||
return (int)_o;
|
||||
}
|
||||
|
||||
return _o;
|
||||
|
@ -155,31 +177,39 @@ namespace AspectedRouting.Language.Functions
|
|||
{
|
||||
var allowedTypes = allowedTypesEnumerable.ToList();
|
||||
var unified = Types.SpecializeTo(allowedTypes);
|
||||
if (unified == null) {
|
||||
if (unified == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var newO = _o;
|
||||
if (_o is IExpression e) {
|
||||
if (_o is IExpression e)
|
||||
{
|
||||
newO = e.Specialize(allowedTypes);
|
||||
}
|
||||
|
||||
if (_o is IEnumerable<IExpression> es) {
|
||||
if (_o is IEnumerable<IExpression> es)
|
||||
{
|
||||
var innerTypes = new List<Type>();
|
||||
foreach (var allowedType in allowedTypes) {
|
||||
if (allowedType is ListType listType) {
|
||||
foreach (var allowedType in allowedTypes)
|
||||
{
|
||||
if (allowedType is ListType listType)
|
||||
{
|
||||
innerTypes.Add(listType.InnerType);
|
||||
}
|
||||
}
|
||||
|
||||
var specializedExpressions = new List<IExpression>();
|
||||
foreach (var expr in es) {
|
||||
if (expr == null) {
|
||||
foreach (var expr in es)
|
||||
{
|
||||
if (expr == null)
|
||||
{
|
||||
throw new NullReferenceException("Subexpression is null");
|
||||
}
|
||||
|
||||
var specialized = expr.Specialize(innerTypes);
|
||||
if (specialized == null) {
|
||||
if (specialized == null)
|
||||
{
|
||||
// If a subexpression can not be specialized, this list cannot be specialized
|
||||
return null;
|
||||
}
|
||||
|
@ -193,26 +223,38 @@ namespace AspectedRouting.Language.Functions
|
|||
return new Constant(unified, newO);
|
||||
}
|
||||
|
||||
public IExpression Optimize()
|
||||
public IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
if (_o is IEnumerable<IExpression> exprs) {
|
||||
somethingChanged = false;
|
||||
if (_o is IEnumerable<IExpression> exprs)
|
||||
{
|
||||
// This is a list
|
||||
var optExprs = new List<IExpression>();
|
||||
foreach (var expression in exprs) {
|
||||
var exprOpt = expression.Optimize();
|
||||
if (exprOpt == null || exprOpt.Types.Count() == 0) {
|
||||
foreach (var expression in exprs)
|
||||
{
|
||||
var exprOpt = expression.Optimize(out var sc);
|
||||
somethingChanged |= sc;
|
||||
if (exprOpt == null || exprOpt.Types.Count() == 0)
|
||||
{
|
||||
throw new ArgumentException("Non-optimizable expression:" + expression);
|
||||
}
|
||||
|
||||
optExprs.Add(exprOpt);
|
||||
}
|
||||
|
||||
return new Constant(optExprs);
|
||||
if (somethingChanged)
|
||||
{
|
||||
return new Constant(optExprs);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
if (_o is IExpression expr) {
|
||||
// This is a list
|
||||
return new Constant(expr.Types, expr.Optimize());
|
||||
if (_o is IExpression expr)
|
||||
{
|
||||
// This is a subexpression
|
||||
somethingChanged = true;
|
||||
return expr.Optimize(out var _);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -220,12 +262,15 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public void Visit(Func<IExpression, bool> f)
|
||||
{
|
||||
if (_o is IExpression e) {
|
||||
if (_o is IExpression e)
|
||||
{
|
||||
e.Visit(f);
|
||||
}
|
||||
|
||||
if (_o is IEnumerable<IExpression> es) {
|
||||
foreach (var x in es) {
|
||||
if (_o is IEnumerable<IExpression> es)
|
||||
{
|
||||
foreach (var x in es)
|
||||
{
|
||||
x.Visit(f);
|
||||
}
|
||||
}
|
||||
|
@ -233,6 +278,28 @@ namespace AspectedRouting.Language.Functions
|
|||
f(this);
|
||||
}
|
||||
|
||||
public bool Equals(IExpression other)
|
||||
{
|
||||
if (other is Constant c)
|
||||
{
|
||||
return c._o.Equals(_o);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Repr()
|
||||
{
|
||||
if (_o is IEnumerable<IExpression> exprs)
|
||||
{
|
||||
return "new Constant(new []{" +
|
||||
string.Join(",\n ", exprs.Select(e => e.Repr().Replace("\n","\n ")))
|
||||
+ "})";
|
||||
}
|
||||
|
||||
return "new Constant(" + (_o?.ToString() ?? null)+ ")";
|
||||
}
|
||||
|
||||
public void EvaluateAll(Context c, HashSet<IExpression> addTo)
|
||||
{
|
||||
addTo.Add(this);
|
||||
|
@ -247,26 +314,35 @@ namespace AspectedRouting.Language.Functions
|
|||
{
|
||||
return ObjectExtensions.Pretty(_o);
|
||||
}
|
||||
|
||||
public object Get()
|
||||
{
|
||||
return _o;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static string Pretty(this object o, Context context = null)
|
||||
{
|
||||
switch (o) {
|
||||
switch (o)
|
||||
{
|
||||
case null: return "null";
|
||||
case Dictionary<string, string> d:
|
||||
var txt = "";
|
||||
foreach (var (k, v) in d) {
|
||||
foreach (var (k, v) in d)
|
||||
{
|
||||
txt += $"{k}={v};";
|
||||
}
|
||||
|
||||
return $"{{{txt}}}";
|
||||
case Dictionary<string, List<string>> d:
|
||||
var t = "";
|
||||
foreach (var (k, v) in d) {
|
||||
foreach (var (k, v) in d)
|
||||
{
|
||||
var values = v.Pretty();
|
||||
if (!v.Any()) {
|
||||
if (!v.Any())
|
||||
{
|
||||
values = "*";
|
||||
}
|
||||
|
||||
|
@ -282,7 +358,7 @@ namespace AspectedRouting.Language.Functions
|
|||
case object[] arr:
|
||||
return arr.ToList().Pretty();
|
||||
case double[] arr:
|
||||
return arr.Select(d => (object) d).ToList().Pretty();
|
||||
return arr.Select(d => (object)d).ToList().Pretty();
|
||||
case string s:
|
||||
return "\"" + s.Replace("\"", "\\\"") + "\"";
|
||||
case IEnumerable<object> ls:
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace AspectedRouting.Language.Functions
|
|||
{
|
||||
if (arguments.Count() <= 2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
var f0 = arguments[0];
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AspectedRouting.Language.Expression;
|
||||
using AspectedRouting.Language.Typ;
|
||||
using Type = AspectedRouting.Language.Typ.Type;
|
||||
|
||||
namespace AspectedRouting.Language.Functions
|
||||
{
|
||||
|
@ -11,7 +13,7 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public override string Description { get; } = "An if_then_else, but one which takes an extra argument and applies it on the condition, then and else.\n" +
|
||||
"Consider `fc`, `fthen` and `felse` are all functions taking an `a`, then:\n" +
|
||||
"`(ifDotted fc fthen felse) a` === `(if (fc a) (fthen a) (felse a)" +
|
||||
"`(ifDotted fc fthen felse) a` === `(if (fc a) (fthen a) (felse a)`" +
|
||||
"Selects either one of the branches, depending on the condition." +
|
||||
" The 'then' branch is returned if the condition returns the string `yes` or `true` or the boolean `true`" +
|
||||
"If the `else` branch is not set, `null` is returned in the condition is false." +
|
||||
|
|
50
AspectedRouting/Language/Functions/IsNull.cs
Normal file
50
AspectedRouting/Language/Functions/IsNull.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using AspectedRouting.Language.Expression;
|
||||
using AspectedRouting.Language.Typ;
|
||||
using Type = AspectedRouting.Language.Typ.Type;
|
||||
|
||||
namespace AspectedRouting.Language.Functions
|
||||
{
|
||||
public class IsNull : Function
|
||||
{
|
||||
public override string Description { get; } = "Returns true if the given argument is null";
|
||||
public override List<string> ArgNames { get; } = new List<string>{"a"};
|
||||
|
||||
public IsNull() : base("is_null", true,
|
||||
new[]
|
||||
{
|
||||
new Curry(new Var("a"), Typs.Bool),
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
private IsNull(IEnumerable<Type> specializedTypes) : base("is_null", specializedTypes)
|
||||
{
|
||||
}
|
||||
|
||||
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
||||
{
|
||||
var unified = Types.SpecializeTo(allowedTypes);
|
||||
if (unified == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IsNull(unified);
|
||||
}
|
||||
|
||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||
{
|
||||
var arg = (string) arguments[0].Evaluate(c);
|
||||
if (arg == null)
|
||||
{
|
||||
return "yes";
|
||||
}
|
||||
|
||||
return "no";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,18 +101,18 @@ namespace AspectedRouting.Language.Functions
|
|||
return resultFunction.Evaluate(c, otherARgs.ToArray());
|
||||
}
|
||||
|
||||
public override IExpression Optimize()
|
||||
public override IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
var optimizedFunctions = new Dictionary<string, IExpression>();
|
||||
|
||||
somethingChanged = false;
|
||||
foreach (var (k, e) in StringToResultFunctions)
|
||||
{
|
||||
var opt = e.Optimize();
|
||||
|
||||
var typeOptStr = string.Join(";", opt.Types);
|
||||
var typeEStr = string.Join("; ", e.Types);
|
||||
var opt = e.Optimize(out var sc);
|
||||
somethingChanged |= sc;
|
||||
if (!opt.Types.Any())
|
||||
{
|
||||
var typeOptStr = string.Join(";", opt.Types);
|
||||
var typeEStr = string.Join("; ", e.Types);
|
||||
throw new NullReferenceException($"Optimized version is null, has different or empty types: " +
|
||||
$"\n{typeEStr}" +
|
||||
$"\n{typeOptStr}");
|
||||
|
@ -121,7 +121,13 @@ namespace AspectedRouting.Language.Functions
|
|||
optimizedFunctions[k] = opt;
|
||||
}
|
||||
|
||||
if (!somethingChanged)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return new Mapping(optimizedFunctions);
|
||||
|
||||
}
|
||||
|
||||
public static Mapping Construct(params (string key, IExpression e)[] exprs)
|
||||
|
|
|
@ -37,6 +37,11 @@ namespace AspectedRouting.Language.Functions
|
|||
|
||||
public IExpression Specialize(IEnumerable<Type> allowedTypes)
|
||||
{
|
||||
/* var filtered = allowedTypes.Where(at => !(at is Curry));
|
||||
if (filtered.Count() == 0)
|
||||
{
|
||||
return null;
|
||||
}*/
|
||||
var unified = Types.SpecializeTo(allowedTypes);
|
||||
if (unified == null)
|
||||
{
|
||||
|
@ -56,8 +61,9 @@ namespace AspectedRouting.Language.Functions
|
|||
return new Parameter(passedTypes, this.ParamName);
|
||||
}
|
||||
|
||||
public IExpression Optimize()
|
||||
public IExpression Optimize(out bool somethingChanged)
|
||||
{
|
||||
somethingChanged = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -71,9 +77,26 @@ namespace AspectedRouting.Language.Functions
|
|||
f(this);
|
||||
}
|
||||
|
||||
public bool Equals(IExpression other)
|
||||
{
|
||||
if (other is Parameter p)
|
||||
{
|
||||
return p.ParamName.Equals( this.ParamName);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Repr()
|
||||
{
|
||||
return "new Parameter(\"" + this.ParamName + "\")";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ParamName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AspectedRouting.Language.Functions;
|
||||
using AspectedRouting.Language.Typ;
|
||||
|
@ -31,20 +32,33 @@ namespace AspectedRouting.Language
|
|||
/// Optimize a single expression, eventually recursively (e.g. a list can optimize all the contents)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IExpression Optimize();
|
||||
IExpression Optimize(out bool somethingChanged);
|
||||
|
||||
/// <summary>
|
||||
/// Optimize with the given argument, e.g. listdot can become a list of applied arguments.
|
||||
/// By default, this should return 'this.Apply(argument)'
|
||||
/// </summary>
|
||||
/// <param name="argument"></param>
|
||||
/// <returns></returns>
|
||||
// IExpression OptimizeWithArgument(IExpression argument);
|
||||
void Visit(Func<IExpression, bool> f);
|
||||
|
||||
bool Equals(IExpression other);
|
||||
|
||||
/**
|
||||
* Builds a string representation that can be used to paste into C# test programs
|
||||
*/
|
||||
string Repr();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class ExpressionExtensions
|
||||
{
|
||||
|
||||
public static void PrintRepr(this IExpression e)
|
||||
{
|
||||
Console.WriteLine(e.Repr()+"\n\n-----------\n");
|
||||
}
|
||||
public static object Run(this IExpression e, Context c, Dictionary<string, string> tags)
|
||||
{
|
||||
try {
|
||||
|
@ -111,7 +125,7 @@ namespace AspectedRouting.Language
|
|||
|
||||
foreach (var expr in exprs) {
|
||||
if (specializedTypes == null) {
|
||||
specializedTypes = expr.Types;
|
||||
specializedTypes = expr.Types; // This is t
|
||||
}
|
||||
else {
|
||||
var newlySpecialized = Typs.WidestCommonTypes(specializedTypes, expr.Types);
|
||||
|
|
|
@ -165,10 +165,18 @@ namespace AspectedRouting
|
|||
continue;
|
||||
}
|
||||
|
||||
var strSplit = str.Split("=");
|
||||
var k = strSplit[0].Trim();
|
||||
var v = strSplit[1].Trim();
|
||||
tags[k] = v;
|
||||
try
|
||||
{
|
||||
|
||||
var strSplit = str.Split("=");
|
||||
var k = strSplit[0].Trim();
|
||||
var v = strSplit[1].Trim();
|
||||
tags[k] = v;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.Error.WriteLine("Could not parse tag: "+str);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -184,11 +184,11 @@ namespace AspectedRouting.Tests
|
|||
}
|
||||
|
||||
if (actual.Priority >= 100 || actual.Priority <= -100)
|
||||
{
|
||||
{/*
|
||||
Err($"priority is not within range of -100 and +100. This is needed due to a bug in Itinero2.0, see https://github.com/itinero/routing2/issues/30",
|
||||
actual.Priority + " < 100 && -100 < "+actual.Priority,
|
||||
actual.Priority);
|
||||
success = false;
|
||||
success = false;*/
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue