Compare commits
12 commits
master
...
feature/js
Author | SHA1 | Date | |
---|---|---|---|
5821db3b55 | |||
c4cd9d1806 | |||
2cc170395c | |||
|
9aba3939c3 | ||
|
0dafbabc23 | ||
|
9c31a92abd | ||
|
2ba01713ef | ||
|
2289827a9d | ||
|
00b6f66110 | ||
|
a751490e4b | ||
77fa88dfd4 | |||
12fc26fa44 |
118 changed files with 11982 additions and 3685 deletions
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -4,5 +4,14 @@
|
||||||
.~lock.*
|
.~lock.*
|
||||||
output/*
|
output/*
|
||||||
AspectedRouting.sln.DotSettings
|
AspectedRouting.sln.DotSettings
|
||||||
AspectedRouting.sln.DotSettings.user
|
|
||||||
.DS_Store
|
#Visual Studio Code
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
# Node Modules
|
||||||
|
*/node_modules
|
||||||
|
|
||||||
|
.fake
|
||||||
|
.ionide
|
||||||
|
|
||||||
|
*/.routeExamples
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.IO.jsonParser;
|
using AspectedRouting.IO.jsonParser;
|
||||||
|
@ -8,472 +7,379 @@ using AspectedRouting.Language.Functions;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace AspectedRouting.Test;
|
namespace AspectedRouting.Test
|
||||||
|
|
||||||
public class FunctionsTest
|
|
||||||
{
|
{
|
||||||
private readonly string constString = "{\"$const\": \"a\"}";
|
public class FunctionsTest
|
||||||
|
|
||||||
private readonly string IfDottedConditionJson
|
|
||||||
= "{" +
|
|
||||||
"\"$ifdotted\": {\"$eq\": \"yes\"}," +
|
|
||||||
"\"then\":{\"$const\": \"a\"}," +
|
|
||||||
"\"else\": {\"$const\": \"b\"}" +
|
|
||||||
"}";
|
|
||||||
|
|
||||||
private readonly string IfSimpleConditionJson
|
|
||||||
= "{" +
|
|
||||||
"\"$if\": true," +
|
|
||||||
"\"then\":\"thenResult\"," +
|
|
||||||
"\"else\": \"elseResult\"}";
|
|
||||||
|
|
||||||
private IExpression MustMatchJson()
|
|
||||||
{
|
{
|
||||||
var json = "{" +
|
private IExpression MustMatchJson()
|
||||||
"\"name\":\"test\"," +
|
|
||||||
"\"description\":\"test\"," +
|
|
||||||
"\"$mustMatch\":{\"a\":\"b\",\"x\":\"y\"}}";
|
|
||||||
return JsonParser.AspectFromJson(new Context(), json, "test.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
private IExpression MustMatchJsonWithOr()
|
|
||||||
{
|
|
||||||
var json = "{" +
|
|
||||||
"\"name\":\"test\"," +
|
|
||||||
"\"description\":\"test\"," +
|
|
||||||
"\"$mustMatch\":{\"a\":\"b\",\"x\":\"y\"}}";
|
|
||||||
return JsonParser.AspectFromJson(new Context(), json, "test.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestAll_AllTags_Yes()
|
|
||||||
{
|
|
||||||
var tagsAx = new Dictionary<string, string>
|
|
||||||
{
|
{
|
||||||
{ "a", "b" },
|
var json = "{" +
|
||||||
{ "x", "y" }
|
"\"name\":\"test\"," +
|
||||||
};
|
"\"description\":\"test\"," +
|
||||||
|
"\"$mustMatch\":{\"a\":\"b\",\"x\":\"y\"}}";
|
||||||
|
return JsonParser.AspectFromJson(new Context(), json, "test.json");
|
||||||
|
}
|
||||||
|
|
||||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize(out _);
|
private IExpression MustMatchJsonWithOr()
|
||||||
var result = expr.Evaluate(new Context());
|
|
||||||
Assert.Equal("yes", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestAll_NoMatch_No()
|
|
||||||
{
|
|
||||||
var tagsAx = new Dictionary<string, string>
|
|
||||||
{
|
{
|
||||||
{ "a", "b" }
|
var json = "{" +
|
||||||
};
|
"\"name\":\"test\"," +
|
||||||
|
"\"description\":\"test\"," +
|
||||||
|
"\"$mustMatch\":{\"a\":\"b\",\"x\":\"y\"}}";
|
||||||
|
return JsonParser.AspectFromJson(new Context(), json, "test.json");
|
||||||
|
}
|
||||||
|
|
||||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize(out var _);
|
[Fact]
|
||||||
var result = expr.Evaluate(new Context());
|
public void TestAll_AllTags_Yes()
|
||||||
Assert.Equal("no", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestAll_NoMatchDifferent_No()
|
|
||||||
{
|
|
||||||
var tagsAx = new Dictionary<string, string>
|
|
||||||
{
|
{
|
||||||
{ "a", "b" },
|
var tagsAx = new Dictionary<string, string>
|
||||||
{ "x", "someRandomValue" }
|
{
|
||||||
};
|
{"a", "b"},
|
||||||
|
{"x", "y"}
|
||||||
|
};
|
||||||
|
|
||||||
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize(out _);
|
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize();
|
||||||
var result = expr.Evaluate(new Context());
|
var result = expr.Evaluate(new Context());
|
||||||
Assert.Equal("no", result);
|
Assert.Equal("yes", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestParsing_SimpleIf_CorrectExpression()
|
public void TestAll_NoMatch_No()
|
||||||
{
|
|
||||||
var c = new Context();
|
|
||||||
var ifExpr = JsonParser.ParseExpression(c, IfSimpleConditionJson);
|
|
||||||
|
|
||||||
Assert.Single(ifExpr.Types);
|
|
||||||
Assert.Equal(ifExpr.Types.First(), Typs.String);
|
|
||||||
|
|
||||||
var resultT = ifExpr.Evaluate(c);
|
|
||||||
Assert.Equal("thenResult", resultT);
|
|
||||||
resultT = ifExpr.Optimize(out _).Evaluate(c);
|
|
||||||
Assert.Equal("thenResult", resultT);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestEvaluate_DottedIf_CorrectExpression()
|
|
||||||
{
|
|
||||||
var ifExpr = Funcs.IfDotted.Apply(
|
|
||||||
Funcs.Eq.Apply(new Constant("abc")),
|
|
||||||
Funcs.Const.Apply(new Constant("a")),
|
|
||||||
Funcs.Const.Apply(new Constant("b"))
|
|
||||||
);
|
|
||||||
|
|
||||||
var c = new Context();
|
|
||||||
var ifResultMatch = ifExpr.Evaluate(c, new Constant("abc"));
|
|
||||||
Assert.Equal("a", ifResultMatch);
|
|
||||||
|
|
||||||
var ifResultNoMatch = ifExpr.Evaluate(c, new Constant("def"));
|
|
||||||
Assert.Equal("b", ifResultNoMatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TestParsing_DottedIf_CorrectExpression()
|
|
||||||
{
|
|
||||||
var c = new Context();
|
|
||||||
var ifExpr = JsonParser.ParseExpression(c, IfDottedConditionJson);
|
|
||||||
ifExpr = ifExpr.Optimize(out _);
|
|
||||||
var resultT = ifExpr.Evaluate(c,
|
|
||||||
new Constant(Typs.String, "yes"));
|
|
||||||
var resultF = ifExpr.Evaluate(c,
|
|
||||||
new Constant(Typs.String, "no"));
|
|
||||||
Assert.Equal("a", resultT);
|
|
||||||
Assert.Equal("b", resultF);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Parse_ConstString_TypeIsFree()
|
|
||||||
{
|
|
||||||
var e = JsonParser.ParseExpression(new Context(), constString);
|
|
||||||
Assert.Single(e.Types);
|
|
||||||
Assert.Equal(new Curry(new Var("d"), Typs.String), e.Types.First());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void TypeInference_EitherIdConstConst_CorrectType()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* id : a -> a
|
|
||||||
* dot: (b -> c) -> (a -> b) -> a -> c
|
|
||||||
* const - throw away b: a -> b -> a
|
|
||||||
* eitherFunc: (a -> b) -> (c -> d) -> (a -> b)
|
|
||||||
* eitherFunc: (a -> b) -> (c -> d) -> (c -> d)
|
|
||||||
|
|
||||||
*
|
|
||||||
* All with free vars:
|
|
||||||
* id: a -> a
|
|
||||||
* dot: (b -> c) -> (x -> b) -> x -> c
|
|
||||||
* const: y -> z -> y
|
|
||||||
* eitherfunc: (d -> e) -> (f -> g) -> (d -> e)
|
|
||||||
* (d -> e) -> (f -> g) -> (f -> g)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (((eitherfunc id) dot) const)
|
|
||||||
*
|
|
||||||
* (eitherfunc id)
|
|
||||||
* [(d -> e) -> (f -> g) -> (d -> e)] (a -> a)
|
|
||||||
* [(d -> e) -> (f -> g) -> (f -> g)] (a -> a)
|
|
||||||
*
|
|
||||||
* Gives:
|
|
||||||
* d ~ a
|
|
||||||
* e ~ a
|
|
||||||
* thus:
|
|
||||||
* (f -> g) -> (a -> a)
|
|
||||||
* (f -> g) -> (f -> g)
|
|
||||||
*
|
|
||||||
* ((eitherfunc id) dot)
|
|
||||||
* [(f -> g) -> (a -> a)] ((b -> c) -> (x -> b) -> x -> c)
|
|
||||||
* [(f -> g) -> (f -> g)] (b -> c) -> (x -> b) -> (x -> c)
|
|
||||||
*
|
|
||||||
* Thus: (f -> g) ~ (b -> c) -> ((x -> b) -> x -> c)
|
|
||||||
* thus: f ~ (b -> c)
|
|
||||||
* g ~ ((x -> b) -> (x -> c))
|
|
||||||
* thus:
|
|
||||||
* (a -> a)
|
|
||||||
* (b -> c) -> ((x -> b) -> (x -> c))
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* (((eitherfunc id) dot) const):
|
|
||||||
* [(a -> a)] (y -> (z -> y))
|
|
||||||
* [(b -> c) -> ((x -> b) -> (x -> c))] (y -> (z -> y))
|
|
||||||
*
|
|
||||||
* Thus: case 1:
|
|
||||||
* a ~ (y -> (z -> y)
|
|
||||||
* Type is: (y -> z -> y) === typeof(const)
|
|
||||||
* case2:
|
|
||||||
* (b -> c) ~ (y -> (z -> y))
|
|
||||||
* thus: b ~ y
|
|
||||||
* c ~ (z -> y)
|
|
||||||
* ((x -> y) -> (x -> (z -> y))))
|
|
||||||
* = ((x -> y) -> x -> z -> y === mix of dot and const
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
var a = new Var("a");
|
|
||||||
var c = new Var("c");
|
|
||||||
var d = new Var("d");
|
|
||||||
|
|
||||||
|
|
||||||
var e = Funcs.Either(Funcs.Id, Funcs.Dot, Funcs.Const);
|
|
||||||
var types = e.Types.ToList();
|
|
||||||
Assert.Equal(Curry.ConstructFrom(c, c, d), types[0]);
|
|
||||||
Assert.Equal(Curry.ConstructFrom(
|
|
||||||
c, // RESULT TYPE
|
|
||||||
new Curry(a, c),
|
|
||||||
a, d
|
|
||||||
), types[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void RenameVars_Constant_ConstantType()
|
|
||||||
{
|
|
||||||
// Funcs.Const.RenameVars(noUse: ["a","b","d","e","f"] should give something like 'c -> g -> c'
|
|
||||||
var a = new Var("a");
|
|
||||||
var b = new Var("b");
|
|
||||||
|
|
||||||
var c = new Var("c");
|
|
||||||
var d = new Var("d");
|
|
||||||
|
|
||||||
var e = new Var("e");
|
|
||||||
var f = new Var("f");
|
|
||||||
var newTypes = Funcs.Const.Types.RenameVars(new[]
|
|
||||||
{
|
{
|
||||||
new Curry(e, e),
|
var tagsAx = new Dictionary<string, string>
|
||||||
new Curry(new Curry(b, f), new Curry(new Curry(a, b), new Curry(a, f)))
|
{
|
||||||
}).ToList();
|
{"a", "b"},
|
||||||
Assert.Single(newTypes);
|
};
|
||||||
Assert.Equal(new Curry(c, new Curry(d, c)),
|
|
||||||
newTypes[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize();
|
||||||
public void BuildSubstitution_TagsToStringTagsToBool_ShouldUnify()
|
var result = expr.Evaluate(new Context());
|
||||||
{
|
Assert.Equal("no", result);
|
||||||
var biggerType = new Curry(Typs.Tags, Typs.String);
|
}
|
||||||
var smallerType = new Curry(Typs.Tags, Typs.Bool);
|
|
||||||
// The expected type (biggerType) on the left, the argument type on the right (as it should be)
|
|
||||||
var unificationTable = biggerType.UnificationTable(smallerType);
|
|
||||||
Assert.NotNull(unificationTable);
|
|
||||||
unificationTable = smallerType.UnificationTable(biggerType);
|
|
||||||
Assert.Null(unificationTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void BuildSubstitution_TagsToDoubleTagsToPDouble_ShouldUnify()
|
public void TestAll_NoMatchDifferent_No()
|
||||||
{
|
|
||||||
var biggerType = new Curry(Typs.Tags, Typs.Double);
|
|
||||||
var smallerType = new Curry(Typs.Tags, Typs.PDouble);
|
|
||||||
var unificationTable = biggerType.UnificationTable(smallerType);
|
|
||||||
Assert.NotNull(unificationTable);
|
|
||||||
unificationTable = smallerType.UnificationTable(biggerType);
|
|
||||||
Assert.Null(unificationTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void BuildSubstitution_DoubleToStringPDoubleToString_ShouldUnify()
|
|
||||||
{
|
|
||||||
var biggerType = new Curry(Typs.PDouble, Typs.Bool);
|
|
||||||
var smallerType = new Curry(Typs.Double, Typs.Bool);
|
|
||||||
// We expect something that is able to handle PDoubles, but it is able to handle the wider doubles - should be fine
|
|
||||||
var unificationTable = biggerType.UnificationTable(smallerType);
|
|
||||||
Assert.NotNull(unificationTable);
|
|
||||||
unificationTable = smallerType.UnificationTable(biggerType);
|
|
||||||
Assert.Null(unificationTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Typechecker_EitherFunc_CorrectType()
|
|
||||||
{
|
|
||||||
var id = new Apply(Funcs.EitherFunc, Funcs.Id);
|
|
||||||
Assert.Equal(2, id.Types.Count());
|
|
||||||
|
|
||||||
var idconst = new Apply(id, Funcs.Const);
|
|
||||||
Assert.Equal(2, idconst.Types.Count());
|
|
||||||
|
|
||||||
var e =
|
|
||||||
new Apply(idconst, new Constant("a"));
|
|
||||||
Assert.Equal(2, e.Types.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void SpecializeToSmallest_Parse_SmallestType()
|
|
||||||
{
|
|
||||||
var smallest = Funcs.Parse.SpecializeToSmallestType();
|
|
||||||
Assert.Single(smallest.Types);
|
|
||||||
Assert.Equal(new Curry(Typs.String, Typs.PDouble), smallest.Types.First());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Unify_TwoSubtypes_DoesNotUnify()
|
|
||||||
{
|
|
||||||
var tags2double = new Curry(Typs.Tags, Typs.Double);
|
|
||||||
var tags2pdouble = new Curry(Typs.Tags, Typs.PDouble);
|
|
||||||
var unifA = tags2double.Unify(tags2pdouble, true);
|
|
||||||
Assert.Null(unifA);
|
|
||||||
var unifB = tags2pdouble.Unify(tags2double, true);
|
|
||||||
Assert.NotNull(unifB);
|
|
||||||
|
|
||||||
var unifC = tags2double.Unify(tags2pdouble);
|
|
||||||
Assert.NotNull(unifC);
|
|
||||||
var unifD = tags2pdouble.Unify(tags2double);
|
|
||||||
Assert.Null(unifD);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Specialize_WiderType_StillSmallerType()
|
|
||||||
{
|
|
||||||
var f = Funcs.Eq;
|
|
||||||
var strstrb = new Curry(
|
|
||||||
Typs.String,
|
|
||||||
new Curry(Typs.String, Typs.Bool));
|
|
||||||
var f0 = f.Specialize(strstrb);
|
|
||||||
Assert.Equal(new[] { strstrb }, f0.Types);
|
|
||||||
|
|
||||||
var strstrstr = new Curry(
|
|
||||||
Typs.String,
|
|
||||||
new Curry(Typs.String, Typs.String));
|
|
||||||
|
|
||||||
var f1 = f.Specialize(strstrstr);
|
|
||||||
|
|
||||||
Assert.Equal(new[] { strstrb, strstrstr }, f1.Types);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void SpecializeToCommonType()
|
|
||||||
{
|
|
||||||
var p0 = Funcs.Parse.Specialize(new Curry(Typs.String, Typs.PDouble));
|
|
||||||
var p1 = Funcs.Const.Apply(new Constant(1.0)).Specialize(
|
|
||||||
new Curry(new Var("a"), Typs.Double));
|
|
||||||
|
|
||||||
var exprs = new[] { p0, p1 };
|
|
||||||
var newTypes = exprs.SpecializeToCommonTypes(out var _);
|
|
||||||
Assert.Single(newTypes);
|
|
||||||
|
|
||||||
exprs = new[] { p1, p0 };
|
|
||||||
newTypes = exprs.SpecializeToCommonTypes(out var _);
|
|
||||||
Assert.Single(newTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ParseFunction_InvalidInput_NullOutput()
|
|
||||||
{
|
|
||||||
var f = Funcs.Parse;
|
|
||||||
var c = new Context();
|
|
||||||
var result = f.Evaluate(c, new Constant("abc"));
|
|
||||||
|
|
||||||
Assert.Null(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ParseFunction_Duration_TotalMinutes()
|
|
||||||
{
|
|
||||||
var f = Funcs.Parse;
|
|
||||||
var c = new Context();
|
|
||||||
var result = f.Evaluate(c, new Constant("01:15"));
|
|
||||||
|
|
||||||
Assert.Equal(75.0, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ApplyDefaultFunctionWithId_ApplicationIsSuccessfull()
|
|
||||||
{
|
|
||||||
var e = new Apply(new Apply(Funcs.Default, new Constant("a")), Funcs.Id);
|
|
||||||
Assert.Single(e.Types);
|
|
||||||
|
|
||||||
Assert.Equal("string -> string", e.Types.First().ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ApplyFirstMatchOf_FirstMatchIsTaken_50()
|
|
||||||
{
|
|
||||||
var tags0 = new Constant(new Dictionary<string, string>
|
|
||||||
{
|
{
|
||||||
{ "highway", "residential" },
|
var tagsAx = new Dictionary<string, string>
|
||||||
{ "maxspeed", "50" }
|
{
|
||||||
});
|
{"a", "b"},
|
||||||
|
{"x", "someRandomValue"}
|
||||||
|
};
|
||||||
|
|
||||||
var f = FirstMatchOfWithMaxspeedAndHighway();
|
var expr = new Apply(MustMatchJson(), new Constant(tagsAx)).Optimize();
|
||||||
var o = f.Evaluate(new Context(), tags0);
|
var result = expr.Evaluate(new Context());
|
||||||
Assert.Equal(50.0, o);
|
Assert.Equal("no", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string IfDottedConditionJson
|
||||||
|
= "{" +
|
||||||
|
"\"$ifdotted\": {\"$eq\": \"yes\"}," +
|
||||||
|
"\"then\":{\"$const\": \"a\"}," +
|
||||||
|
"\"else\": {\"$const\": \"b\"}" +
|
||||||
|
"}";
|
||||||
|
|
||||||
[Fact]
|
private string IfSimpleConditionJson
|
||||||
public void ApplyFirstMatchOf_FirstMatchIsTaken_ResidentialDefault()
|
= "{" +
|
||||||
{
|
"\"$if\": true," +
|
||||||
var tags0 = new Constant(new Dictionary<string, string>
|
"\"then\":\"thenResult\"," +
|
||||||
|
"\"else\": \"elseResult\"}";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestParsing_SimpleIf_CorrectExpression()
|
||||||
{
|
{
|
||||||
{ "highway", "residential" }
|
var c = new Context();
|
||||||
});
|
var ifExpr = JsonParser.ParseExpression(c, IfSimpleConditionJson);
|
||||||
|
|
||||||
var f = FirstMatchOfWithMaxspeedAndHighway();
|
Assert.Single(ifExpr.Types);
|
||||||
var o = f.Evaluate(new Context(), tags0);
|
Assert.Equal(ifExpr.Types.First(), Typs.String);
|
||||||
Assert.Equal(30, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
var resultT = ifExpr.Evaluate(c);
|
||||||
public void ApplyFirstMatchOf_NoMatchIfFound_Null()
|
Assert.Equal("thenResult", resultT);
|
||||||
{
|
resultT = ifExpr.Optimize().Evaluate(c);
|
||||||
var tags0 = new Constant(new Dictionary<string, string>
|
Assert.Equal("thenResult", resultT);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestEvaluate_DottedIf_CorrectExpression()
|
||||||
{
|
{
|
||||||
{ "highway", "unknown" }
|
var ifExpr = Funcs.IfDotted.Apply(
|
||||||
});
|
Funcs.Eq.Apply(new Constant("abc")),
|
||||||
|
Funcs.Const.Apply(new Constant("a")),
|
||||||
var f = FirstMatchOfWithMaxspeedAndHighway();
|
Funcs.Const.Apply(new Constant("b"))
|
||||||
var o = f.Evaluate(new Context(), tags0);
|
|
||||||
Assert.Equal(null, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IExpression FirstMatchOfWithMaxspeedAndHighway()
|
|
||||||
{
|
|
||||||
var order = new Constant(new ListType(Typs.String), new List<IExpression>
|
|
||||||
{
|
|
||||||
new Constant("maxspeed"),
|
|
||||||
new Constant("highway")
|
|
||||||
});
|
|
||||||
|
|
||||||
var mapping =
|
|
||||||
Funcs.StringStringToTags.Apply(
|
|
||||||
new Mapping(
|
|
||||||
new List<string> { "maxspeed", "highway" },
|
|
||||||
new List<IExpression>
|
|
||||||
{
|
|
||||||
Funcs.Parse,
|
|
||||||
new Mapping(
|
|
||||||
new List<string> { "residential", "primary" },
|
|
||||||
new List<IExpression> { new Constant(30), new Constant(90) }
|
|
||||||
)
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
return Funcs.FirstOf.Apply(order, mapping);
|
|
||||||
|
var c = new Context();
|
||||||
|
var ifResultMatch = ifExpr.Evaluate(c, new Constant("abc"));
|
||||||
|
Assert.Equal("a", ifResultMatch);
|
||||||
|
|
||||||
|
var ifResultNoMatch = ifExpr.Evaluate(c, new Constant("def"));
|
||||||
|
Assert.Equal("b", ifResultNoMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestParsing_DottedIf_CorrectExpression()
|
||||||
|
{
|
||||||
|
var c = new Context();
|
||||||
|
var ifExpr = JsonParser.ParseExpression(c, IfDottedConditionJson);
|
||||||
|
ifExpr = ifExpr.Optimize();
|
||||||
|
var resultT = ifExpr.Evaluate(c,
|
||||||
|
new Constant(Typs.String, "yes"));
|
||||||
|
var resultF = ifExpr.Evaluate(c,
|
||||||
|
new Constant(Typs.String, "no"));
|
||||||
|
Assert.Equal("a", resultT);
|
||||||
|
Assert.Equal("b", resultF);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string constString = "{\"$const\": \"a\"}";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_ConstString_TypeIsFree()
|
||||||
|
{
|
||||||
|
var e = JsonParser.ParseExpression(new Context(), constString);
|
||||||
|
Assert.Single(e.Types);
|
||||||
|
Assert.Equal(new Curry(new Var("d"), Typs.String), e.Types.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TypeInference_EitherIdConstConst_CorrectType()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* id : a -> a
|
||||||
|
* dot: (b -> c) -> (a -> b) -> a -> c
|
||||||
|
* const - throw away b: a -> b -> a
|
||||||
|
* eitherFunc: (a -> b) -> (c -> d) -> (a -> b)
|
||||||
|
* eitherFunc: (a -> b) -> (c -> d) -> (c -> d)
|
||||||
|
|
||||||
|
*
|
||||||
|
* All with free vars:
|
||||||
|
* id: a -> a
|
||||||
|
* dot: (b -> c) -> (x -> b) -> x -> c
|
||||||
|
* const: y -> z -> y
|
||||||
|
* eitherfunc: (d -> e) -> (f -> g) -> (d -> e)
|
||||||
|
* (d -> e) -> (f -> g) -> (f -> g)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (((eitherfunc id) dot) const)
|
||||||
|
*
|
||||||
|
* (eitherfunc id)
|
||||||
|
* [(d -> e) -> (f -> g) -> (d -> e)] (a -> a)
|
||||||
|
* [(d -> e) -> (f -> g) -> (f -> g)] (a -> a)
|
||||||
|
*
|
||||||
|
* Gives:
|
||||||
|
* d ~ a
|
||||||
|
* e ~ a
|
||||||
|
* thus:
|
||||||
|
* (f -> g) -> (a -> a)
|
||||||
|
* (f -> g) -> (f -> g)
|
||||||
|
*
|
||||||
|
* ((eitherfunc id) dot)
|
||||||
|
* [(f -> g) -> (a -> a)] ((b -> c) -> (x -> b) -> x -> c)
|
||||||
|
* [(f -> g) -> (f -> g)] (b -> c) -> (x -> b) -> (x -> c)
|
||||||
|
*
|
||||||
|
* Thus: (f -> g) ~ (b -> c) -> ((x -> b) -> x -> c)
|
||||||
|
* thus: f ~ (b -> c)
|
||||||
|
* g ~ ((x -> b) -> (x -> c))
|
||||||
|
* thus:
|
||||||
|
* (a -> a)
|
||||||
|
* (b -> c) -> ((x -> b) -> (x -> c))
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* (((eitherfunc id) dot) const):
|
||||||
|
* [(a -> a)] (y -> (z -> y))
|
||||||
|
* [(b -> c) -> ((x -> b) -> (x -> c))] (y -> (z -> y))
|
||||||
|
*
|
||||||
|
* Thus: case 1:
|
||||||
|
* a ~ (y -> (z -> y)
|
||||||
|
* Type is: (y -> z -> y) === typeof(const)
|
||||||
|
* case2:
|
||||||
|
* (b -> c) ~ (y -> (z -> y))
|
||||||
|
* thus: b ~ y
|
||||||
|
* c ~ (z -> y)
|
||||||
|
* ((x -> y) -> (x -> (z -> y))))
|
||||||
|
* = ((x -> y) -> x -> z -> y === mix of dot and const
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
var a = new Var("a");
|
||||||
|
var c = new Var("c");
|
||||||
|
var d = new Var("d");
|
||||||
|
|
||||||
|
|
||||||
|
var e = Funcs.Either(Funcs.Id, Funcs.Dot, Funcs.Const);
|
||||||
|
var types = e.Types.ToList();
|
||||||
|
Assert.Equal(Curry.ConstructFrom(c, c, d), types[0]);
|
||||||
|
Assert.Equal(Curry.ConstructFrom(
|
||||||
|
c, // RESULT TYPE
|
||||||
|
new Curry(a, c),
|
||||||
|
a, d
|
||||||
|
), types[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RenameVars_Constant_ConstantType()
|
||||||
|
{
|
||||||
|
// Funcs.Const.RenameVars(noUse: ["a","b","d","e","f"] should give something like 'c -> g -> c'
|
||||||
|
var a = new Var("a");
|
||||||
|
var b = new Var("b");
|
||||||
|
|
||||||
|
var c = new Var("c");
|
||||||
|
var d = new Var("d");
|
||||||
|
|
||||||
|
var e = new Var("e");
|
||||||
|
var f = new Var("f");
|
||||||
|
var newTypes = Funcs.Const.Types.RenameVars(new[]
|
||||||
|
{
|
||||||
|
new Curry(e, e),
|
||||||
|
new Curry(new Curry(b, f), new Curry(new Curry(a, b), new Curry(a, f)))
|
||||||
|
}).ToList();
|
||||||
|
Assert.Single(newTypes);
|
||||||
|
Assert.Equal(new Curry(c, new Curry(d, c)),
|
||||||
|
newTypes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildSubstitution_TagsToStringTagsToBool_ShouldUnify()
|
||||||
|
{
|
||||||
|
var biggerType = new Curry(Typs.Tags, Typs.String);
|
||||||
|
var smallerType = new Curry(Typs.Tags, Typs.Bool);
|
||||||
|
// The expected type (biggerType) on the left, the argument type on the right (as it should be)
|
||||||
|
var unificationTable = biggerType.UnificationTable(smallerType);
|
||||||
|
Assert.NotNull(unificationTable);
|
||||||
|
unificationTable = smallerType.UnificationTable(biggerType);
|
||||||
|
Assert.Null(unificationTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildSubstitution_TagsToDoubleTagsToPDouble_ShouldUnify()
|
||||||
|
{
|
||||||
|
var biggerType = new Curry(Typs.Tags, Typs.Double);
|
||||||
|
var smallerType = new Curry(Typs.Tags, Typs.PDouble);
|
||||||
|
var unificationTable = biggerType.UnificationTable(smallerType);
|
||||||
|
Assert.NotNull(unificationTable);
|
||||||
|
unificationTable = smallerType.UnificationTable(biggerType);
|
||||||
|
Assert.Null(unificationTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildSubstitution_DoubleToStringPDoubleToString_ShouldUnify()
|
||||||
|
{
|
||||||
|
var biggerType = new Curry(Typs.PDouble, Typs.Bool);
|
||||||
|
var smallerType = new Curry(Typs.Double, Typs.Bool);
|
||||||
|
// We expect something that is able to handle PDoubles, but it is able to handle the wider doubles - should be fine
|
||||||
|
var unificationTable = biggerType.UnificationTable(smallerType);
|
||||||
|
Assert.NotNull(unificationTable);
|
||||||
|
unificationTable = smallerType.UnificationTable(biggerType);
|
||||||
|
Assert.Null(unificationTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Typechecker_EitherFunc_CorrectType()
|
||||||
|
{
|
||||||
|
var id = new Apply(Funcs.EitherFunc, Funcs.Id);
|
||||||
|
Assert.Equal(2, id.Types.Count());
|
||||||
|
|
||||||
|
var idconst = new Apply(id, Funcs.Const);
|
||||||
|
Assert.Equal(2, idconst.Types.Count());
|
||||||
|
|
||||||
|
var e =
|
||||||
|
new Apply(idconst, new Constant("a"));
|
||||||
|
Assert.Equal(2, e.Types.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SpecializeToSmallest_Parse_SmallestType()
|
||||||
|
{
|
||||||
|
var smallest = Funcs.Parse.SpecializeToSmallestType();
|
||||||
|
Assert.Single(smallest.Types);
|
||||||
|
Assert.Equal(new Curry(Typs.String, Typs.PDouble), smallest.Types.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Unify_TwoSubtypes_DoesNotUnify()
|
||||||
|
{
|
||||||
|
var tags2double = new Curry(Typs.Tags, Typs.Double);
|
||||||
|
var tags2pdouble = new Curry(Typs.Tags, Typs.PDouble);
|
||||||
|
var unifA = tags2double.Unify(tags2pdouble, true);
|
||||||
|
Assert.Null(unifA);
|
||||||
|
var unifB = tags2pdouble.Unify(tags2double, true);
|
||||||
|
Assert.NotNull(unifB);
|
||||||
|
|
||||||
|
var unifC = tags2double.Unify(tags2pdouble, false);
|
||||||
|
Assert.NotNull(unifC);
|
||||||
|
var unifD = tags2pdouble.Unify(tags2double, false);
|
||||||
|
Assert.Null(unifD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Specialize_WiderType_StillSmallerType()
|
||||||
|
{
|
||||||
|
var f = Funcs.Eq;
|
||||||
|
var strstrb = new Curry(
|
||||||
|
Typs.String,
|
||||||
|
new Curry(Typs.String, Typs.Bool));
|
||||||
|
var f0 = f.Specialize(strstrb);
|
||||||
|
Assert.Equal(new[] {strstrb}, f0.Types);
|
||||||
|
|
||||||
|
var strstrstr = new Curry(
|
||||||
|
Typs.String,
|
||||||
|
new Curry(Typs.String, Typs.String));
|
||||||
|
|
||||||
|
var f1 = f.Specialize(strstrstr);
|
||||||
|
|
||||||
|
Assert.Equal(new[] {strstrb, strstrstr}, f1.Types);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SpecializeToCommonType()
|
||||||
|
{
|
||||||
|
var p0 = Funcs.Parse.Specialize(new Curry(Typs.String, Typs.PDouble));
|
||||||
|
var p1 = Funcs.Const.Apply(new Constant(1.0)).Specialize(
|
||||||
|
new Curry(new Var("a"), Typs.Double));
|
||||||
|
|
||||||
|
var exprs = new[] {p0, p1};
|
||||||
|
var newTypes = exprs.SpecializeToCommonTypes(out var _);
|
||||||
|
Assert.Single(newTypes);
|
||||||
|
|
||||||
|
exprs = new[] {p1, p0};
|
||||||
|
newTypes = exprs.SpecializeToCommonTypes(out var _);
|
||||||
|
Assert.Single(newTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseFunction_InvalidInput_NullOutput()
|
||||||
|
{
|
||||||
|
var f = Funcs.Parse;
|
||||||
|
var c = new Context();
|
||||||
|
var result = f.Evaluate(c, new Constant("abc"));
|
||||||
|
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseFunction_Duration_TotalMinutes()
|
||||||
|
{
|
||||||
|
var f = Funcs.Parse;
|
||||||
|
var c = new Context();
|
||||||
|
var result = f.Evaluate(c, new Constant("01:15"));
|
||||||
|
|
||||||
|
Assert.Equal(75.0, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyDefaultFunctionWithId_ApplicationIsSuccessfull()
|
||||||
|
{
|
||||||
|
var e = new Apply(new Apply(Funcs.Default, new Constant("a")), Funcs.Id);
|
||||||
|
Assert.Single(e.Types);
|
||||||
|
|
||||||
|
Assert.Equal("string -> string", e.Types.First().ToString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[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);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using AspectedRouting.IO.itinero1;
|
||||||
using AspectedRouting.IO.LuaSkeleton;
|
using AspectedRouting.IO.LuaSkeleton;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Functions;
|
using AspectedRouting.Language.Functions;
|
||||||
|
@ -12,11 +13,12 @@ namespace AspectedRouting.Test
|
||||||
public void ToLua_SimpleMapping_Table()
|
public void ToLua_SimpleMapping_Table()
|
||||||
{
|
{
|
||||||
var mapping = new Mapping(
|
var mapping = new Mapping(
|
||||||
new[] { "a", "b", "c" },
|
new[] {"a", "b", "c"},
|
||||||
new[] {
|
new[]
|
||||||
|
{
|
||||||
new Constant(5),
|
new Constant(5),
|
||||||
new Constant(6),
|
new Constant(6),
|
||||||
new Constant(7)
|
new Constant(7),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -32,11 +34,13 @@ namespace AspectedRouting.Test
|
||||||
public void ToLua_NestedMapping_Table()
|
public void ToLua_NestedMapping_Table()
|
||||||
{
|
{
|
||||||
var mapping = new Mapping(
|
var mapping = new Mapping(
|
||||||
new[] { "a" },
|
new[] {"a"},
|
||||||
new[] {
|
new[]
|
||||||
new Mapping(new[] { "b" },
|
{
|
||||||
new[] {
|
new Mapping(new[] {"b"},
|
||||||
new Constant(42)
|
new[]
|
||||||
|
{
|
||||||
|
new Constant(42),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -50,8 +54,10 @@ namespace AspectedRouting.Test
|
||||||
public void Sanity_EveryBasicFunction_HasDescription()
|
public void Sanity_EveryBasicFunction_HasDescription()
|
||||||
{
|
{
|
||||||
var missing = new List<string>();
|
var missing = new List<string>();
|
||||||
foreach (var (_, f) in Funcs.Builtins) {
|
foreach (var (_, f) in Funcs.Builtins)
|
||||||
if (string.IsNullOrEmpty(f.Description)) {
|
{
|
||||||
|
if (string.IsNullOrEmpty(f.Description))
|
||||||
|
{
|
||||||
missing.Add(f.Name);
|
missing.Add(f.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,13 +65,15 @@ namespace AspectedRouting.Test
|
||||||
Assert.True(0 == missing.Count,
|
Assert.True(0 == missing.Count,
|
||||||
"These functions do not have a description: " + string.Join(", ", missing));
|
"These functions do not have a description: " + string.Join(", ", missing));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Sanity_EveryBasicFunction_HasArgNames()
|
public void Sanity_EveryBasicFunction_HasArgNames()
|
||||||
{
|
{
|
||||||
var missing = new List<string>();
|
var missing = new List<string>();
|
||||||
foreach (var (_, f) in Funcs.Builtins) {
|
foreach (var (_, f) in Funcs.Builtins)
|
||||||
if (f.ArgNames == null) {
|
{
|
||||||
|
if (f.ArgNames == null)
|
||||||
|
{
|
||||||
missing.Add(f.Name);
|
missing.Add(f.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,18 @@ namespace AspectedRouting.Test
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void SimpleMapping_SimpleHighway_GivesResult()
|
public static void SimpleMapping_SimpleHighway_GivesResult()
|
||||||
{
|
{
|
||||||
var maxspeed = new Mapping(new[] { "residential", "living_street" },
|
var maxspeed = new Mapping(new[] {"residential", "living_street"},
|
||||||
new[] {
|
new[] {
|
||||||
new Constant(30),
|
new Constant(30),
|
||||||
new Constant(20)
|
new Constant(20)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
var resMaxspeed = maxspeed.Evaluate(new Context(), new Constant("residential"));
|
var resMaxspeed= maxspeed.Evaluate(new Context(), new Constant("residential"));
|
||||||
Assert.Equal(30, resMaxspeed);
|
Assert.Equal(30, resMaxspeed);
|
||||||
var livingStreetMaxspeed = maxspeed.Evaluate(new Context(), new Constant("living_street"));
|
var livingStreetMaxspeed= maxspeed.Evaluate(new Context(), new Constant("living_street"));
|
||||||
Assert.Equal(20, livingStreetMaxspeed);
|
Assert.Equal(20, livingStreetMaxspeed);
|
||||||
var undefinedSpeed = maxspeed.Evaluate(new Context(), new Constant("some_unknown_highway_type"));
|
var undefinedSpeed = maxspeed.Evaluate(new Context(), new Constant("some_unknown_highway_type"));
|
||||||
Assert.Null(undefinedSpeed);
|
Assert.Null(undefinedSpeed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,37 +10,37 @@ namespace AspectedRouting.Test
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MustMatch_SimpleInput()
|
public void MustMatch_SimpleInput()
|
||||||
{
|
{
|
||||||
var mapValue = new Mapping(new[] { "residential", "living_street" },
|
var mapValue = new Mapping(new[] {"residential", "living_street"},
|
||||||
new[] {
|
new[] {
|
||||||
new Constant("yes"),
|
new Constant("yes"),
|
||||||
new Constant("no")
|
new Constant("no")
|
||||||
});
|
});
|
||||||
var mapTag = new Mapping(new[] { "highway" }, new[] { mapValue });
|
var mapTag = new Mapping(new[] {"highway"}, new[] {mapValue});
|
||||||
var mm = Funcs.MustMatch
|
var mm = Funcs.MustMatch
|
||||||
.Apply(
|
.Apply(
|
||||||
new Constant(new[] { new Constant("highway") }),
|
new Constant(new[] {new Constant("highway")}),
|
||||||
Funcs.StringStringToTags.Apply(mapTag)
|
Funcs.StringStringToTags.Apply(mapTag)
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
var residential = mm.Apply(new Constant(new Dictionary<string, string> {
|
var residential = mm.Apply(new Constant(new Dictionary<string, string> {
|
||||||
{ "highway", "residential" }
|
{"highway", "residential"}
|
||||||
})).Evaluate(new Context());
|
})).Evaluate(new Context());
|
||||||
Assert.Equal("yes", residential);
|
Assert.Equal("yes", residential);
|
||||||
|
|
||||||
var living = mm.Apply(new Constant(new Dictionary<string, string> {
|
var living = mm.Apply(new Constant(new Dictionary<string, string> {
|
||||||
{ "highway", "living_street" }
|
{"highway", "living_street"}
|
||||||
})).Evaluate(new Context());
|
})).Evaluate(new Context());
|
||||||
Assert.Equal("no", living);
|
Assert.Equal("no", living);
|
||||||
|
|
||||||
var unknown = mm.Apply(new Constant(new Dictionary<string, string> {
|
var unknown = mm.Apply(new Constant(new Dictionary<string, string> {
|
||||||
{ "highway", "unknown_type" }
|
{"highway", "unknown_type"}
|
||||||
})).Evaluate(new Context());
|
})).Evaluate(new Context());
|
||||||
Assert.Equal("yes", unknown);
|
Assert.Equal("yes", unknown);
|
||||||
|
|
||||||
var missing = mm.Apply(new Constant(new Dictionary<string, string> {
|
var missing = mm.Apply(new Constant(new Dictionary<string, string> {
|
||||||
{ "proposed:highway", "unknown_type" }
|
{"proposed:highway", "unknown_type"}
|
||||||
})).Evaluate(new Context());
|
})).Evaluate(new Context());
|
||||||
Assert.Equal("no", missing);
|
Assert.Equal("no", missing);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AspectedRouting.IO.LuaSkeleton;
|
using AspectedRouting.IO.LuaSkeleton;
|
||||||
using AspectedRouting.IO.LuaSnippets;
|
using AspectedRouting.IO.LuaSnippets;
|
||||||
|
@ -8,113 +7,85 @@ using AspectedRouting.Language.Functions;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace AspectedRouting.Test.Snippets;
|
namespace AspectedRouting.Test.Snippets
|
||||||
|
|
||||||
public class SnippetTests
|
|
||||||
{
|
{
|
||||||
[Fact]
|
public class SnippetTests
|
||||||
public void DefaultSnippet_SimpleDefault_GetsLua()
|
|
||||||
{
|
{
|
||||||
var gen = new DefaultSnippet();
|
[Fact]
|
||||||
var lua = new LuaSkeleton(new Context(), true);
|
public void DefaultSnippet_SimpleDefault_GetsLua()
|
||||||
var code = gen.Convert(lua, "result", new List<IExpression>
|
|
||||||
{
|
{
|
||||||
new Constant("the_default_value"),
|
var gen = new DefaultSnippet();
|
||||||
Funcs.Id,
|
var lua = new LuaSkeleton(new Context(), true);
|
||||||
new Constant("value")
|
var code = gen.Convert(lua, "result", new List<IExpression> {
|
||||||
});
|
new Constant("the_default_value"),
|
||||||
Assert.Contains("if (result == nil) then\n result = \"the_default_value\"", code);
|
Funcs.Id,
|
||||||
}
|
new Constant("value")
|
||||||
|
});
|
||||||
|
Assert.Contains("if (result == nil) then\n result = \"the_default_value\"", code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void FirstOfSnippet_SimpleFirstOf_GetLua()
|
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"),
|
var gen = new FirstMatchOfSnippet();
|
||||||
new Constant("access")
|
var lua = new LuaSkeleton(new Context(), true);
|
||||||
});
|
|
||||||
|
|
||||||
// Func: (Tags -> [a])
|
// FirstMatchOf: [a] -> (Tags -> [a]) -> Tags -> a
|
||||||
var func = new Apply(
|
|
||||||
Funcs.StringStringToTags,
|
// Order: [string]
|
||||||
new Mapping(
|
var order = new Constant(new List<IExpression> {
|
||||||
new[] { "bicycle", "access" },
|
new Constant("bicycle"),
|
||||||
new IExpression[]
|
new Constant("access")
|
||||||
{
|
});
|
||||||
Funcs.Id,
|
|
||||||
Funcs.Id
|
// 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(
|
||||||
var tags = new LuaLiteral(new[] { Typs.Tags }, "tags");
|
"if (tags[\"access\"] ~= nil) then\n result = tags[\"access\"]\n \nend\nif (tags[\"bicycle\"] ~= nil) then\n result = tags[\"bicycle\"]\n \nend\n",
|
||||||
|
code);
|
||||||
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]
|
[Fact]
|
||||||
public void SimpleMappingSnippet_SimpleMapping_GeneratesLua()
|
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 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 =
|
var expected =
|
||||||
"local v\nv = tags.oneway\n\nif (v == \"1\") then\n result = \"with\"\nelseif (v == \"-1\") then\n result = \"against\"\nend";
|
"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);
|
Assert.Equal(expected, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ListDotWithHead_GeneratesLua()
|
|
||||||
{
|
|
||||||
// (dot head) (stringToTags (mapping speed $ parse))
|
|
||||||
var eSub = Funcs.Dot.Apply(Funcs.Head,
|
|
||||||
new Constant(new[]
|
|
||||||
{
|
|
||||||
Funcs.Head.Apply(Funcs.StringStringToTags.Apply(
|
|
||||||
new Mapping(new List<string> { "_speed" }, new[] { Funcs.Parse }))),
|
|
||||||
Funcs.Const.Apply(new Constant(Typs.Double, 42))
|
|
||||||
})
|
|
||||||
);
|
|
||||||
var condition = Funcs.Dot.Apply(Funcs.Head, Funcs.StringStringToTags.Apply(
|
|
||||||
new Mapping(new[] { "route" }, new[] { Funcs.Eq.Apply(new Constant("ferry")) })));
|
|
||||||
var e =
|
|
||||||
Funcs.IfDotted.Apply(condition, eSub);
|
|
||||||
e = e.Apply(new LuaLiteral(Typs.Tags, "tags")).Finalize().Optimize(out _);
|
|
||||||
var ctx = new Context();
|
|
||||||
var lua = new LuaSkeleton(ctx, true);
|
|
||||||
var code = IO.LuaSnippets.Snippets.Convert(lua, "varname", e);
|
|
||||||
Console.WriteLine(code);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,10 +18,11 @@ namespace AspectedRouting.Test
|
||||||
"{\"name\": \"legal_maxspeed_be\",\"description\": \"Gives, for each type of highway, which the default legal maxspeed is in Belgium. This file is intended to be reused for in all vehicles, from pedestrian to car. In some cases, a legal maxspeed is not really defined (e.g. on footways). In that case, a socially acceptable speed should be taken (e.g.: a bicycle on a pedestrian path will go say around 12km/h)\",\"unit\": \"km/h\",\"$max\": {\"maxspeed\": \"$parse\",\"highway\": {\"residential\": 30},\"ferry\":5}}";
|
"{\"name\": \"legal_maxspeed_be\",\"description\": \"Gives, for each type of highway, which the default legal maxspeed is in Belgium. This file is intended to be reused for in all vehicles, from pedestrian to car. In some cases, a legal maxspeed is not really defined (e.g. on footways). In that case, a socially acceptable speed should be taken (e.g.: a bicycle on a pedestrian path will go say around 12km/h)\",\"unit\": \"km/h\",\"$max\": {\"maxspeed\": \"$parse\",\"highway\": {\"residential\": 30},\"ferry\":5}}";
|
||||||
|
|
||||||
var aspect = JsonParser.AspectFromJson(null, json, null);
|
var aspect = JsonParser.AspectFromJson(null, json, null);
|
||||||
var tags = new Dictionary<string, string> {
|
var tags = new Dictionary<string, string>
|
||||||
{ "maxspeed", "42" },
|
{
|
||||||
{ "highway", "residential" },
|
{"maxspeed", "42"},
|
||||||
{ "ferry", "yes" }
|
{"highway", "residential"},
|
||||||
|
{"ferry", "yes"}
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.Equal("tags -> pdouble", string.Join(", ", aspect.Types));
|
Assert.Equal("tags -> pdouble", string.Join(", ", aspect.Types));
|
||||||
|
@ -39,10 +40,11 @@ namespace AspectedRouting.Test
|
||||||
var aspect = JsonParser.AspectFromJson(null, json, null);
|
var aspect = JsonParser.AspectFromJson(null, json, null);
|
||||||
|
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
new Dictionary<string, HashSet<string>> {
|
new Dictionary<string, HashSet<string>>
|
||||||
{ "maxspeed", new HashSet<string>() },
|
{
|
||||||
{ "highway", new HashSet<string> { "residential" } },
|
{"maxspeed", new HashSet<string>()},
|
||||||
{ "ferry", new HashSet<string>() }
|
{"highway", new HashSet<string> {"residential"}},
|
||||||
|
{"ferry", new HashSet<string>()}
|
||||||
},
|
},
|
||||||
aspect.PossibleTags());
|
aspect.PossibleTags());
|
||||||
}
|
}
|
||||||
|
@ -77,7 +79,7 @@ namespace AspectedRouting.Test
|
||||||
public void EitherFunc_SpecializeToString_Const()
|
public void EitherFunc_SpecializeToString_Const()
|
||||||
{
|
{
|
||||||
var a = new Constant("a");
|
var a = new Constant("a");
|
||||||
|
|
||||||
var mconst = new Apply(new Apply(Funcs.EitherFunc, Funcs.Id), Funcs.Const);
|
var mconst = new Apply(new Apply(Funcs.EitherFunc, Funcs.Id), Funcs.Const);
|
||||||
var specialized = new Apply(mconst, a).Specialize(Typs.String);
|
var specialized = new Apply(mconst, a).Specialize(Typs.String);
|
||||||
|
|
||||||
|
@ -123,7 +125,7 @@ namespace AspectedRouting.Test
|
||||||
public void MaxTest()
|
public void MaxTest()
|
||||||
{
|
{
|
||||||
var ls = new Constant(new ListType(Typs.Double),
|
var ls = new Constant(new ListType(Typs.Double),
|
||||||
new[] { 1.1, 2.0, 3.0 }.Select(d => (object)d));
|
new[] {1.1, 2.0, 3.0}.Select(d => (object) d));
|
||||||
Assert.Equal("[1.1, 2, 3] : list (double)",
|
Assert.Equal("[1.1, 2, 3] : list (double)",
|
||||||
ls.Evaluate(null).Pretty() + " : " + string.Join(", ", ls.Types));
|
ls.Evaluate(null).Pretty() + " : " + string.Join(", ", ls.Types));
|
||||||
var mx = Funcs.Max.Apply(ls);
|
var mx = Funcs.Max.Apply(ls);
|
||||||
|
@ -162,7 +164,7 @@ namespace AspectedRouting.Test
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestStringGeneration()
|
public void TestStringGeneration()
|
||||||
{
|
{
|
||||||
var v = Var.Fresh(new HashSet<string> { "$a", "$b" });
|
var v = Var.Fresh(new HashSet<string> {"$a", "$b"});
|
||||||
Assert.Equal("$c", v.Name);
|
Assert.Equal("$c", v.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +176,9 @@ namespace AspectedRouting.Test
|
||||||
var app = new Apply(
|
var app = new Apply(
|
||||||
new Apply(
|
new Apply(
|
||||||
new Apply(Funcs.Id, Funcs.Id), Funcs.Id), a);
|
new Apply(Funcs.Id, Funcs.Id), Funcs.Id), a);
|
||||||
var (f, args) = app.DeconstructApply().Value;
|
var (f, args ) = app.DeconstructApply().Value;
|
||||||
Assert.Equal(Funcs.Id.Name, ((Function)f).Name);
|
Assert.Equal(Funcs.Id.Name, ((Function) f).Name);
|
||||||
Assert.Equal(new List<IExpression> { Funcs.Id, Funcs.Id, a }.Select(e => e.ToString()),
|
Assert.Equal(new List<IExpression> {Funcs.Id, Funcs.Id, a}.Select(e => e.ToString()),
|
||||||
args.Select(e => e.ToString()));
|
args.Select(e => e.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,8 @@ namespace AspectedRouting.Test
|
||||||
new Curry(Typs.Tags, Typs.Double), x
|
new Curry(Typs.Tags, Typs.Double), x
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WidestCommonGround_StringAndString_String()
|
public void WidestCommonGround_StringAndString_String()
|
||||||
{
|
{
|
||||||
|
|
21
AspectedRouting.sln.DotSettings.user
Normal file
21
AspectedRouting.sln.DotSettings.user
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=3112587d_002D1c06_002D4ad3_002Da845_002D73105d4b723a/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" Name="DefaultSnippet_SimpleDefault_GetsLua" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||||
|
<TestAncestor>
|
||||||
|
<TestId>xUnit::A1309041-8AAE-42D7-A886-94C9FFC6A28C::.NETCoreApp,Version=v3.1::AspectedRouting.Test.Snippets.SnippetTests</TestId>
|
||||||
|
<TestId>xUnit::A1309041-8AAE-42D7-A886-94C9FFC6A28C::.NETCoreApp,Version=v3.1::AspectedRouting.Test.TypingTests.SpecializeToCommonTypes_X2PDouble_Y2Double_Gives_X2Double</TestId>
|
||||||
|
</TestAncestor>
|
||||||
|
</SessionState></s:String>
|
||||||
|
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=5e89d9f5_002D24ed_002D4ea2_002Da7ea_002Dcc7faea6d057/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" Name="JoinApply_Id" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||||
|
<TestAncestor>
|
||||||
|
<TestId>xUnit::A1309041-8AAE-42D7-A886-94C9FFC6A28C::.NETCoreApp,Version=v3.1::AspectedRouting.Test.TypingTests.JoinApply_Id</TestId>
|
||||||
|
<TestId>xUnit::A1309041-8AAE-42D7-A886-94C9FFC6A28C::.NETCoreApp,Version=v3.1::AspectedRouting.Test.FunctionsTest.ApplyDefaultFunctionWithId_ApplicationIsSuccessfull</TestId>
|
||||||
|
</TestAncestor>
|
||||||
|
</SessionState></s:String>
|
||||||
|
|
||||||
|
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=a6a74f48_002D8456_002D43c7_002Dbbee_002Dd3da33a8a4be/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="Integration_TestExamples" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||||
|
<Project Location="/home/pietervdvn/git/AspectedRouting/AspectedRouting.Test" Presentation="&lt;AspectedRouting.Test&gt;" />
|
||||||
|
</SessionState></s:String>
|
||||||
|
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=d2e3d58f_002Debff_002D4fb5_002D8d18_002Deafe85f4773d/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" Name="SpecializeToCommonTypes_ValueAndFuncType_ShouldFail" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||||
|
<Project Location="/home/pietervdvn/git/AspectedRouting/AspectedRouting.Test" Presentation="&lt;AspectedRouting.Test&gt;" />
|
||||||
|
</SessionState></s:String>
|
||||||
|
</wpf:ResourceDictionary>
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<LangVersion>8</LangVersion>
|
<LangVersion>8</LangVersion>
|
||||||
<AssemblyName>AspectedRouting</AssemblyName>
|
<AssemblyName>AspectedRouting</AssemblyName>
|
||||||
<RootNamespace>AspectedRouting</RootNamespace>
|
<RootNamespace>AspectedRouting</RootNamespace>
|
||||||
|
@ -13,9 +13,6 @@
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="Examples\**">
|
<None Update="Examples\**">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="Format.md">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Typ;
|
|
||||||
using Type = AspectedRouting.Language.Typ.Type;
|
using Type = AspectedRouting.Language.Typ.Type;
|
||||||
|
|
||||||
namespace AspectedRouting.IO.LuaSkeleton
|
namespace AspectedRouting.IO.LuaSkeleton
|
||||||
|
@ -10,17 +9,19 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
public class LuaLiteral : IExpression
|
public class LuaLiteral : IExpression
|
||||||
{
|
{
|
||||||
public readonly string Lua;
|
public readonly string Lua;
|
||||||
|
public IEnumerable<Type> Types { get; }
|
||||||
|
|
||||||
public LuaLiteral(Type type, string lua) : this(new[] { type }, lua) { }
|
public LuaLiteral(Type type, string lua):this(new [] {type}, lua)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public LuaLiteral(IEnumerable<Type> types, string lua)
|
public LuaLiteral(IEnumerable<Type> types, string lua)
|
||||||
{
|
{
|
||||||
Lua = lua;
|
Lua = lua;
|
||||||
Types = types;
|
Types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Type> Types { get; }
|
|
||||||
|
|
||||||
public object Evaluate(Context c, params IExpression[] arguments)
|
public object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -31,46 +32,25 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
||||||
{
|
{
|
||||||
var passed = Types.Where(allowedTypes);
|
var passed = this.Types.Where(allowedTypes);
|
||||||
if (passed.Any())
|
if (passed.Any()) {
|
||||||
{
|
return new LuaLiteral(passed, this.Lua);
|
||||||
return new LuaLiteral(passed, Lua);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression Optimize(out bool somethingChanged)
|
public IExpression Optimize()
|
||||||
{
|
{
|
||||||
somethingChanged = false;
|
return this;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Visit(Func<IExpression, bool> f)
|
public void Visit(Func<IExpression, bool> f)
|
||||||
{
|
{
|
||||||
f(this);
|
throw new NotImplementedException();
|
||||||
}
|
|
||||||
|
|
||||||
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}\")";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,8 +6,8 @@ namespace AspectedRouting.IO.itinero1
|
||||||
{
|
{
|
||||||
public class LuaParameterPrinter
|
public class LuaParameterPrinter
|
||||||
{
|
{
|
||||||
private readonly ProfileMetaData _profile;
|
private ProfileMetaData _profile;
|
||||||
private readonly LuaSkeleton.LuaSkeleton _skeleton;
|
private LuaSkeleton.LuaSkeleton _skeleton;
|
||||||
|
|
||||||
public LuaParameterPrinter(ProfileMetaData profile, LuaSkeleton.LuaSkeleton skeleton)
|
public LuaParameterPrinter(ProfileMetaData profile, LuaSkeleton.LuaSkeleton skeleton)
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,8 @@ namespace AspectedRouting.IO.itinero1
|
||||||
|
|
||||||
public string GenerateDefaultParameters()
|
public string GenerateDefaultParameters()
|
||||||
{
|
{
|
||||||
var impl = new List<string> {
|
var impl = new List<string>()
|
||||||
|
{
|
||||||
"function default_parameters()",
|
"function default_parameters()",
|
||||||
" local parameters = {}",
|
" local parameters = {}",
|
||||||
DeclareParametersFor(_profile.DefaultParameters),
|
DeclareParametersFor(_profile.DefaultParameters),
|
||||||
|
@ -30,13 +31,18 @@ namespace AspectedRouting.IO.itinero1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a piece of code of the following format:
|
/// Generates a piece of code of the following format:
|
||||||
/// parameters["x"] = a;
|
///
|
||||||
/// parameters["y"] = b:
|
/// parameters["x"] = a;
|
||||||
/// ...
|
/// parameters["y"] = b:
|
||||||
/// Where x=a and y=b are defined in the profile
|
/// ...
|
||||||
/// Dependencies are added.
|
///
|
||||||
/// Note that the caller should still add `local paramaters = default_parameters()`
|
/// Where x=a and y=b are defined in the profile
|
||||||
|
///
|
||||||
|
/// Dependencies are added.
|
||||||
|
///
|
||||||
|
/// Note that the caller should still add `local paramaters = default_parameters()`
|
||||||
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="behaviour"></param>
|
/// <param name="behaviour"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Dynamic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using AspectedRouting.IO.itinero1;
|
using AspectedRouting.IO.itinero1;
|
||||||
|
@ -15,16 +13,6 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
{
|
{
|
||||||
public partial class LuaSkeleton
|
public partial class LuaSkeleton
|
||||||
{
|
{
|
||||||
|
|
||||||
internal string ToLuaWithTags(IExpression bare)
|
|
||||||
{
|
|
||||||
if (bare == null)
|
|
||||||
{
|
|
||||||
throw new NullReferenceException("bare is null");
|
|
||||||
}
|
|
||||||
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)
|
internal string ToLua(IExpression bare, string key = "nil", bool forceFirstArgInDot = false)
|
||||||
{
|
{
|
||||||
var collectedMapping = new List<IExpression>();
|
var collectedMapping = new List<IExpression>();
|
||||||
|
@ -38,12 +26,11 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
, UnApply(
|
, UnApply(
|
||||||
IsFunc(Funcs.StringStringToTags),
|
IsFunc(Funcs.StringStringToTags),
|
||||||
Assign(collectedMapping))
|
Assign(collectedMapping))
|
||||||
).Invoke(bare))
|
).Invoke(bare)) {
|
||||||
{
|
|
||||||
AddDep(Funcs.FirstOf.Name);
|
AddDep(Funcs.FirstOf.Name);
|
||||||
return "first_match_of(\n" +
|
return "first_match_of(\n" +
|
||||||
" " + ToLua(order.First(), key) + ",\n" +
|
" " + ToLua(order.First(), key) + ",\n" +
|
||||||
("\n" + MappingToLua((Mapping)collectedMapping.First())).Indent().Indent() +
|
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
|
||||||
",\n tags, result)";
|
",\n tags, result)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,48 +41,52 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
, UnApply(
|
, UnApply(
|
||||||
IsFunc(Funcs.StringStringToTags),
|
IsFunc(Funcs.StringStringToTags),
|
||||||
Assign(collectedMapping))
|
Assign(collectedMapping))
|
||||||
).Invoke(bare))
|
).Invoke(bare)) {
|
||||||
{
|
|
||||||
AddDep(Funcs.MustMatch.Name);
|
AddDep(Funcs.MustMatch.Name);
|
||||||
return "must_match(" +
|
return "must_match(" +
|
||||||
" " + ToLua(order.First(), key) + "," +
|
" " + ToLua(order.First(), key) + "," +
|
||||||
("\n" + MappingToLua((Mapping)collectedMapping.First())).Indent().Indent() +
|
("\n" + MappingToLua((Mapping) collectedMapping.First())).Indent().Indent() +
|
||||||
",\n tags, result)";
|
",\n tags, result)";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UnApply(
|
if (UnApply(
|
||||||
IsFunc(Funcs.MemberOf),
|
IsFunc(Funcs.MemberOf),
|
||||||
Any
|
Any
|
||||||
).Invoke(bare))
|
).Invoke(bare)) {
|
||||||
{
|
|
||||||
AddDep("memberOf");
|
AddDep("memberOf");
|
||||||
return "memberOf(funcName, parameters, tags, result)";
|
return "memberOf(funcName, parameters, tags, result)";
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
var name = new List<string>();
|
var collectedList = new List<IExpression>();
|
||||||
var arg = new List<IExpression>();
|
var func = new List<IExpression>();
|
||||||
if (UnApply(
|
if (
|
||||||
IsFunctionCall(name),
|
UnApply(
|
||||||
Assign(arg)
|
UnApply(IsFunc(Funcs.Dot), Assign(func)),
|
||||||
).Invoke(bare))
|
UnApply(IsFunc(Funcs.ListDot),
|
||||||
{
|
Assign(collectedList))).Invoke(bare)) {
|
||||||
var called = _context.DefinedFunctions[name.First()];
|
var exprs = (IEnumerable<IExpression>) ((Constant) collectedList.First()).Evaluate(_context);
|
||||||
if (called.ProfileInternal)
|
var luaExprs = new List<string>();
|
||||||
{
|
var funcName = func.First().ToString().TrimStart('$');
|
||||||
return called.Name;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDependenciesFor(called);
|
if (expr.Types.First() is Curry curry
|
||||||
AddFunction(called);
|
&& curry.ArgType.Equals(Typs.Tags)) {
|
||||||
var usesParams = called.ExpressionImplementation.UsedParameters().Any();
|
var lua = ToLua(expr, key);
|
||||||
if (usesParams)
|
luaExprs.Add(lua);
|
||||||
{
|
|
||||||
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();
|
collectedMapping.Clear();
|
||||||
var dottedFunction = new List<IExpression>();
|
var dottedFunction = new List<IExpression>();
|
||||||
dottedFunction.Clear();
|
dottedFunction.Clear();
|
||||||
|
@ -107,10 +98,9 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
UnApply(
|
UnApply(
|
||||||
IsFunc(Funcs.StringStringToTags),
|
IsFunc(Funcs.StringStringToTags),
|
||||||
Assign(collectedMapping))).Invoke(bare)
|
Assign(collectedMapping))).Invoke(bare)
|
||||||
)
|
) {
|
||||||
{
|
var mapping = (Mapping) collectedMapping.First();
|
||||||
var mapping = (Mapping)collectedMapping.First();
|
var baseFunc = (Function) dottedFunction.First();
|
||||||
var baseFunc = (Function)dottedFunction.First();
|
|
||||||
AddDep(baseFunc.Name);
|
AddDep(baseFunc.Name);
|
||||||
AddDep("table_to_list");
|
AddDep("table_to_list");
|
||||||
|
|
||||||
|
@ -124,44 +114,32 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
// The expression might be a function which still expects a string (the value from the tag) as argument
|
// The expression might be a function which still expects a string (the value from the tag) as argument
|
||||||
if (!(bare is Mapping) &&
|
if (!(bare is Mapping) &&
|
||||||
bare.Types.First() is Curry curr &&
|
bare.Types.First() is Curry curr &&
|
||||||
curr.ArgType.Equals(Typs.String))
|
curr.ArgType.Equals(Typs.String)) {
|
||||||
{
|
|
||||||
var applied = new Apply(bare, new Constant(curr.ArgType, ("tags", "\"" + key + "\"")));
|
var applied = new Apply(bare, new Constant(curr.ArgType, ("tags", "\"" + key + "\"")));
|
||||||
return ToLua(applied.Optimize(out _), key);
|
return ToLua(applied.Optimize(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The expression might consist of multiple nested functions
|
// The expression might consist of multiple nested functions
|
||||||
var fArgs = bare.DeconstructApply();
|
var fArgs = bare.DeconstructApply();
|
||||||
if (fArgs != null)
|
if (fArgs != null) {
|
||||||
{
|
|
||||||
var (f, args) = fArgs.Value;
|
var (f, args) = fArgs.Value;
|
||||||
|
|
||||||
if (f is Constant constant)
|
if(f is Constant constant) {
|
||||||
{
|
|
||||||
return ConstantToLua(constant);
|
return ConstantToLua(constant);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(f is Function baseFunc))
|
if (!(f is Function baseFunc)) {
|
||||||
{
|
|
||||||
throw new ArgumentException("Not a function: " + f);
|
throw new ArgumentException("Not a function: " + f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseFunc.Name.Equals(Funcs.Id.Name))
|
if (baseFunc.Name.Equals(Funcs.Id.Name)) {
|
||||||
{
|
|
||||||
// This is an ugly hack
|
// This is an ugly hack
|
||||||
return ToLua(args.First());
|
return ToLua(args.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseFunc.Name.Equals(Funcs.Dot.Name))
|
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]);
|
return ToLua(args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +153,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
AddDep(baseFunc.Name);
|
AddDep(baseFunc.Name);
|
||||||
|
|
||||||
var argExpressions = new List<string>();
|
var argExpressions = new List<string>();
|
||||||
foreach (var arg in args)
|
foreach (var arg in args) {
|
||||||
{
|
|
||||||
argExpressions.Add(ToLua(arg, key));
|
argExpressions.Add(ToLua(arg, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,35 +162,30 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
|
|
||||||
|
|
||||||
var collected = new List<IExpression>();
|
var collected = new List<IExpression>();
|
||||||
switch (bare)
|
switch (bare) {
|
||||||
{
|
|
||||||
case LuaLiteral lua:
|
case LuaLiteral lua:
|
||||||
return lua.Lua;
|
return lua.Lua;
|
||||||
case FunctionCall fc:
|
case FunctionCall fc:
|
||||||
var called = _context.DefinedFunctions[fc.CalledFunctionName];
|
var called = _context.DefinedFunctions[fc.CalledFunctionName];
|
||||||
if (called.ProfileInternal)
|
if (called.ProfileInternal) {
|
||||||
{
|
|
||||||
return called.Name;
|
return called.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDependenciesFor(called);
|
AddDependenciesFor(called);
|
||||||
AddFunction(called);
|
AddFunction(called);
|
||||||
return $"{fc.CalledFunctionName.AsLuaIdentifier()}(tags, parameters)";
|
return $"{fc.CalledFunctionName.AsLuaIdentifier()}(parameters, tags, result)";
|
||||||
case Constant c:
|
case Constant c:
|
||||||
return ConstantToLua(c);
|
return ConstantToLua(c);
|
||||||
case Mapping m:
|
case Mapping m:
|
||||||
return MappingToLua(m).Indent();
|
return MappingToLua(m).Indent();
|
||||||
case Function f:
|
case Function f:
|
||||||
var fName = f.Name.TrimStart('$');
|
var fName = f.Name.TrimStart('$');
|
||||||
if (Funcs.Builtins.ContainsKey(fName))
|
if (Funcs.Builtins.ContainsKey(fName)) {
|
||||||
{
|
|
||||||
AddDep(f.Name);
|
AddDep(f.Name);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
var definedFunc = _context.DefinedFunctions[fName];
|
var definedFunc = _context.DefinedFunctions[fName];
|
||||||
if (definedFunc.ProfileInternal)
|
if (definedFunc.ProfileInternal) {
|
||||||
{
|
|
||||||
return f.Name;
|
return f.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,31 +207,27 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
public string MappingToLua(Mapping m)
|
public string MappingToLua(Mapping m)
|
||||||
{
|
{
|
||||||
var isConstant = true;
|
var isConstant = true;
|
||||||
var contents = m.StringToResultFunctions.Select(kv =>
|
var contents = m.StringToResultFunctions.Select(kv => {
|
||||||
{
|
var (key, expr) = kv;
|
||||||
var (key, expr) = kv;
|
var left = "[\"" + key + "\"]";
|
||||||
var left = "[\"" + key + "\"]";
|
|
||||||
|
|
||||||
if (Regex.IsMatch(key, "^[a-zA-Z][_a-zA-Z-9]*$"))
|
if (Regex.IsMatch(key, "^[a-zA-Z][_a-zA-Z-9]*$")) {
|
||||||
{
|
left = key;
|
||||||
left = key;
|
}
|
||||||
|
|
||||||
|
var luaExpr = ToLua(expr, key);
|
||||||
|
if (luaExpr.Contains("tags")) {
|
||||||
|
isConstant = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return left + " = " + luaExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
var luaExpr = ToLua(expr, key);
|
|
||||||
if (luaExpr.Contains("tags"))
|
|
||||||
{
|
|
||||||
isConstant = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return left + " = " + luaExpr;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
var mapping =
|
var mapping =
|
||||||
"{\n " +
|
"{\n " +
|
||||||
string.Join(",\n ", contents) +
|
string.Join(",\n ", contents) +
|
||||||
"\n}";
|
"\n}";
|
||||||
if (_staticTables && isConstant)
|
if (_staticTables && isConstant) {
|
||||||
{
|
|
||||||
return AddConstant(mapping);
|
return AddConstant(mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,17 +241,16 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private string ConstantToLua(Constant c)
|
private string ConstantToLua(Constant c)
|
||||||
{
|
{
|
||||||
var o = c.Get();
|
var o = c.Evaluate(_context);
|
||||||
switch (o)
|
switch (o) {
|
||||||
{
|
|
||||||
case LuaLiteral lua:
|
case LuaLiteral lua:
|
||||||
return lua.Lua;
|
return lua.Lua;
|
||||||
case IExpression e:
|
case IExpression e:
|
||||||
return ToLua(e);
|
return ConstantToLua(new Constant(e.Types.First(), e.Evaluate(null)));
|
||||||
case int i:
|
case int i:
|
||||||
return i.ToString(CultureInfo.InvariantCulture);
|
return "" + i;
|
||||||
case double d:
|
case double d:
|
||||||
return d.ToString(CultureInfo.InvariantCulture);
|
return "" + d;
|
||||||
case string s:
|
case string s:
|
||||||
return '"' + s.Replace("\"", "\\\"") + '"';
|
return '"' + s.Replace("\"", "\\\"") + '"';
|
||||||
case null:
|
case null:
|
||||||
|
@ -291,12 +258,10 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
case ValueTuple<string, string> unpack:
|
case ValueTuple<string, string> unpack:
|
||||||
return unpack.Item1 + "[" + unpack.Item2 + "]";
|
return unpack.Item1 + "[" + unpack.Item2 + "]";
|
||||||
case IEnumerable<object> ls:
|
case IEnumerable<object> ls:
|
||||||
var t = ((ListType)c.Types.First()).InnerType;
|
var t = ((ListType) c.Types.First()).InnerType;
|
||||||
return "{" + string.Join(", ", ls.Select(obj =>
|
return "{" + string.Join(", ", ls.Select(obj => {
|
||||||
{
|
|
||||||
var objInConstant = new Constant(t, obj);
|
var objInConstant = new Constant(t, obj);
|
||||||
if (obj is Constant asConstant)
|
if (obj is Constant asConstant) {
|
||||||
{
|
|
||||||
objInConstant = asConstant;
|
objInConstant = asConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.IO.itinero1;
|
using AspectedRouting.IO.itinero1;
|
||||||
|
@ -13,8 +12,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
{
|
{
|
||||||
public void AddFunction(AspectMetadata meta)
|
public void AddFunction(AspectMetadata meta)
|
||||||
{
|
{
|
||||||
if (_alreadyAddedFunctions.Contains(meta.Name))
|
if (_alreadyAddedFunctions.Contains(meta.Name)) {
|
||||||
{
|
|
||||||
// already added
|
// already added
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -29,55 +27,49 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
|
|
||||||
var funcNameDeclaration = "";
|
var funcNameDeclaration = "";
|
||||||
|
|
||||||
meta.Visit(e =>
|
meta.Visit(e => {
|
||||||
{
|
if (e is Function f && f.Name.Equals(Funcs.MemberOf.Name)) {
|
||||||
if (e is Function f && f.Name.Equals(Funcs.MemberOf.Name))
|
|
||||||
{
|
|
||||||
funcNameDeclaration = $"\n local funcName = \"{meta.Name.AsLuaIdentifier()}\"";
|
funcNameDeclaration = $"\n local funcName = \"{meta.Name.AsLuaIdentifier()}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
var expression = Funcs.Either(Funcs.Id, Funcs.Const, meta.ExpressionImplementation)
|
var expression = 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;
|
var ctx = Context;
|
||||||
_context = _context.WithAspectName(meta.Name);
|
_context = _context.WithAspectName(meta.Name);
|
||||||
|
|
||||||
var body = "";
|
var body = "";
|
||||||
if (_useSnippets)
|
if (_useSnippets) {
|
||||||
{
|
if (expression.Types.First() is Curry c) {
|
||||||
|
expression = expression.Apply(new LuaLiteral(Typs.Tags, "tags"));
|
||||||
|
}
|
||||||
|
|
||||||
body = Utils.Lines(
|
body = Utils.Lines(
|
||||||
" local r = nil",
|
" local r = nil",
|
||||||
" " + Snippets.Convert(this, "r", expression).Indent(),
|
" " + Snippets.Convert(this, "r", expression).Indent(),
|
||||||
" return r"
|
" return r"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
body = " return " + ToLua(expression);
|
body = " return " + ToLua(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var impl = Utils.Lines(
|
var impl = Utils.Lines(
|
||||||
"--[[",
|
"--[[",
|
||||||
meta.Description,
|
meta.Description,
|
||||||
"",
|
"",
|
||||||
"Unit: " + meta.Unit,
|
"Unit: " + meta.Unit,
|
||||||
"Created by " + meta.Author,
|
"Created by " + meta.Author,
|
||||||
|
"Originally defined in " + meta.Filepath,
|
||||||
"Uses tags: " + string.Join(", ", possibleTags.Keys),
|
"Uses tags: " + string.Join(", ", possibleTags.Keys),
|
||||||
"Used parameters: " + string.Join(", ", usedParams),
|
"Used parameters: " + string.Join(", ", usedParams),
|
||||||
"Number of combintations: " + numberOfCombinations,
|
"Number of combintations: " + numberOfCombinations,
|
||||||
"Returns values: ",
|
"Returns values: ",
|
||||||
"]]",
|
"]]",
|
||||||
"function " + meta.Name.AsLuaIdentifier() + "(tags, parameters)" + funcNameDeclaration,
|
"function " + meta.Name.AsLuaIdentifier() + "(parameters, tags, result)" + funcNameDeclaration,
|
||||||
body,
|
body,
|
||||||
"end"
|
"end"
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
|
|
||||||
public Context Context => _context;
|
public Context Context => _context;
|
||||||
|
|
||||||
public LuaSkeleton(Context context, bool useSnippets, bool staticTables = false)
|
public LuaSkeleton(Context context, bool useSnippets, bool staticTables = false)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_useSnippets = useSnippets;
|
_useSnippets = useSnippets;
|
||||||
|
@ -42,14 +42,11 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
|
|
||||||
internal void AddDep(string name)
|
internal void AddDep(string name)
|
||||||
{
|
{
|
||||||
if (name.StartsWith("mapping"))
|
if (name.StartsWith("mapping")) {
|
||||||
{
|
|
||||||
Console.Error.WriteLine(">>>");
|
|
||||||
throw new Exception("A mapping was added as dependency - this is a bug");
|
throw new Exception("A mapping was added as dependency - this is a bug");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name.Contains("stringToTags"))
|
if (name.Contains("stringToTags")) {
|
||||||
{
|
|
||||||
AddDep("table_to_list");
|
AddDep("table_to_list");
|
||||||
}
|
}
|
||||||
_dependencies.Add(name);
|
_dependencies.Add(name);
|
||||||
|
@ -68,14 +65,11 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
public void AddDependenciesFor(IExpression e)
|
public void AddDependenciesFor(IExpression e)
|
||||||
{
|
{
|
||||||
var (_, functionNames) = e.InList().DirectlyAndInderectlyCalled(_context);
|
var (_, functionNames) = e.InList().DirectlyAndInderectlyCalled(_context);
|
||||||
foreach (var functionName in functionNames)
|
foreach (var functionName in functionNames) {
|
||||||
{
|
if (_context.DefinedFunctions.TryGetValue(functionName, out var aspectMeta)) {
|
||||||
if (_context.DefinedFunctions.TryGetValue(functionName, out var aspectMeta))
|
|
||||||
{
|
|
||||||
AddFunction(aspectMeta);
|
AddFunction(aspectMeta);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
AddDep(functionName);
|
AddDep(functionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,15 +79,12 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
{
|
{
|
||||||
var imps = new List<string>();
|
var imps = new List<string>();
|
||||||
|
|
||||||
foreach (var name in _dependencies)
|
foreach (var name in _dependencies) {
|
||||||
{
|
|
||||||
var path = $"IO/lua/{name}.lua";
|
var path = $"IO/lua/{name}.lua";
|
||||||
if (File.Exists(path))
|
if (File.Exists(path)) {
|
||||||
{
|
|
||||||
imps.Add(File.ReadAllText(path));
|
imps.Add(File.ReadAllText(path));
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
throw new FileNotFoundException(path);
|
throw new FileNotFoundException(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,8 +106,7 @@ namespace AspectedRouting.IO.LuaSkeleton
|
||||||
private readonly Dictionary<string, uint> counters = new Dictionary<string, uint>();
|
private readonly Dictionary<string, uint> counters = new Dictionary<string, uint>();
|
||||||
public string FreeVar(string key)
|
public string FreeVar(string key)
|
||||||
{
|
{
|
||||||
if (!counters.ContainsKey(key))
|
if (!counters.ContainsKey(key)) {
|
||||||
{
|
|
||||||
counters[key] = 0;
|
counters[key] = 0;
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
@ -7,20 +6,20 @@ namespace AspectedRouting.IO.itinero1
|
||||||
{
|
{
|
||||||
public static class LuaStringExtensions
|
public static class LuaStringExtensions
|
||||||
{
|
{
|
||||||
|
|
||||||
public static string ToLuaTable(this Dictionary<string, string> tags)
|
public static string ToLuaTable(this Dictionary<string, string> tags)
|
||||||
{
|
{
|
||||||
var contents = tags.Select(kv =>
|
var contents = tags.Select(kv =>
|
||||||
{
|
{
|
||||||
var (key, value) = kv;
|
var (key, value) = kv;
|
||||||
var left = "[\"" + key .ToString(CultureInfo.InvariantCulture)+ "\"]";
|
var left = "[\"" + key + "\"]";
|
||||||
|
|
||||||
if (Regex.IsMatch(key, "^[a-zA-Z][_a-zA-Z-9]*$"))
|
if (Regex.IsMatch(key, "^[a-zA-Z][_a-zA-Z-9]*$"))
|
||||||
{
|
{
|
||||||
left = key;
|
left = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{left.ToString(CultureInfo.InvariantCulture)} = \"{value.ToString(CultureInfo.InvariantCulture)}\"";
|
return $"{left} = \"{value}\"";
|
||||||
});
|
});
|
||||||
return "{" + string.Join(", ", contents) + "}";
|
return "{" + string.Join(", ", contents) + "}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.Tests;
|
using AspectedRouting.Tests;
|
||||||
|
|
||||||
|
@ -14,17 +13,17 @@ namespace AspectedRouting.IO.itinero1
|
||||||
_skeleton = skeleton;
|
_skeleton = skeleton;
|
||||||
unitTestRunners.ForEach(_skeleton.AddDep);
|
unitTestRunners.ForEach(_skeleton.AddDep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public string GenerateFullTestSuite(List<BehaviourTestSuite> profileTests, List<AspectTestSuite> aspectTests, bool invertPriority = false)
|
public string GenerateFullTestSuite(List<BehaviourTestSuite> profileTests, List<AspectTestSuite> aspectTests, bool invertPriority = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
_skeleton.AddDep("inv");
|
_skeleton.AddDep("inv");
|
||||||
_skeleton.AddDep("double_compare");
|
_skeleton.AddDep("double_compare");
|
||||||
|
|
||||||
|
|
||||||
var aspectTestSuite =
|
var aspectTestSuite =
|
||||||
string.Join("\n\n",
|
string.Join("\n\n",
|
||||||
aspectTests
|
aspectTests
|
||||||
.Where(x => x != null)
|
.Where(x => x != null)
|
||||||
.Select(
|
.Select(
|
||||||
|
@ -82,8 +81,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
foreach (var key in keysToCheck)
|
foreach (var key in keysToCheck)
|
||||||
{
|
{
|
||||||
var newKey = key.Replace(".", "_");
|
var newKey = key.Replace(".", "_");
|
||||||
if (newKey == key)
|
if (newKey == key) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tags[newKey] = tags[key];
|
tags[newKey] = tags[key];
|
||||||
|
@ -95,10 +93,9 @@ namespace AspectedRouting.IO.itinero1
|
||||||
tags.Remove("#" + paramName);
|
tags.Remove("#" + paramName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedPriority = expected.Priority.ToString(CultureInfo.InvariantCulture);
|
var expectedPriority = "" + expected.Priority;
|
||||||
if (invertPriority)
|
if (invertPriority) {
|
||||||
{
|
expectedPriority = $"inv({expectedPriority})";
|
||||||
expectedPriority = $"inv({expectedPriority.ToString(CultureInfo.InvariantCulture)})";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates something like:
|
// Generates something like:
|
||||||
|
@ -107,7 +104,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
$"unit_test_profile(behaviour_{testSuite.Profile.Name.AsLuaIdentifier()}_{testSuite.BehaviourName.AsLuaIdentifier()}, " +
|
$"unit_test_profile(behaviour_{testSuite.Profile.Name.AsLuaIdentifier()}_{testSuite.BehaviourName.AsLuaIdentifier()}, " +
|
||||||
$"\"{testSuite.BehaviourName}\", " +
|
$"\"{testSuite.BehaviourName}\", " +
|
||||||
$"{index}, " +
|
$"{index}, " +
|
||||||
$"{{access = \"{D(expected.Access)}\", speed = {expected.Speed.ToString(CultureInfo.InvariantCulture)}, oneway = \"{D(expected.Oneway)}\", priority = {expectedPriority} }}, " +
|
$"{{access = \"{D(expected.Access)}\", speed = {expected.Speed}, oneway = \"{D(expected.Oneway)}\", priority = {expectedPriority} }}, " +
|
||||||
tags.ToLuaTable() +
|
tags.ToLuaTable() +
|
||||||
")";
|
")";
|
||||||
}
|
}
|
||||||
|
@ -121,7 +118,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
var tests =
|
var tests =
|
||||||
testSuite.Tests
|
testSuite.Tests
|
||||||
.Select((test, i) => GenerateAspectUnitTestCall(fName, i, test.expected, test.tags))
|
.Select((test, i) => GenerateAspectUnitTestCall(fName, i, test.expected, test.tags))
|
||||||
|
@ -152,7 +149,8 @@ namespace AspectedRouting.IO.itinero1
|
||||||
|
|
||||||
_skeleton.AddDep("unitTest");
|
_skeleton.AddDep("unitTest");
|
||||||
_skeleton.AddDep("debug_table");
|
_skeleton.AddDep("debug_table");
|
||||||
return $"unit_test({functionToApplyName.AsLuaIdentifier()}, \"{functionToApplyName}\", {index.ToString(CultureInfo.InvariantCulture)}, \"{expected.ToString(CultureInfo.InvariantCulture)}\", {parameters.ToLuaTable()}, {tags.ToLuaTable()})";
|
return
|
||||||
|
$"unit_test({functionToApplyName.AsLuaIdentifier()}, \"{functionToApplyName}\", {index}, \"{expected}\", {parameters.ToLuaTable()}, {tags.ToLuaTable()})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,13 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
var defaultValue = args[0];
|
var defaultValue = args[0];
|
||||||
var func = args[1];
|
var func = args[1];
|
||||||
var funcArg = args[2];
|
var funcArg = args[2];
|
||||||
|
|
||||||
return Snippets.Convert(lua, assignTo, func.Apply(funcArg))
|
return Snippets.Convert(lua, assignTo, func.Apply(funcArg))
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ "if (" + assignTo + " == nil) then\n"
|
+"if ("+assignTo+" == nil) then\n"
|
||||||
+ " " + assignTo + " = " + lua.ToLua(defaultValue) + "\n"
|
+ " " + assignTo + " = " + lua.ToLua(defaultValue)+"\n"
|
||||||
+ "end";
|
+"end";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,8 +15,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
{
|
{
|
||||||
var c = lua.Context;
|
var c = lua.Context;
|
||||||
|
|
||||||
if (!(args[0].Evaluate(c) is List<IExpression> order))
|
if (!(args[0].Evaluate(c) is List<IExpression> order)) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,19 +23,16 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
if (!UnApply(
|
if (!UnApply(
|
||||||
IsFunc(Funcs.StringStringToTags),
|
IsFunc(Funcs.StringStringToTags),
|
||||||
IsMapping(mappings)
|
IsMapping(mappings)
|
||||||
).Invoke(args[1]))
|
).Invoke(args[1])) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mappings.Count != 1)
|
if (mappings.Count != 1) {
|
||||||
{
|
|
||||||
throw new Exception("Multiple possible implementations at this point - should not happen");
|
throw new Exception("Multiple possible implementations at this point - should not happen");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mappings.Count == 0)
|
if (mappings.Count == 0) {
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
var mapping = mappings.First();
|
var mapping = mappings.First();
|
||||||
var tags = args[2];
|
var tags = args[2];
|
||||||
|
@ -44,35 +40,30 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
var varName = "tags";
|
var varName = "tags";
|
||||||
|
|
||||||
var result = "";
|
var result = "";
|
||||||
if (tags is LuaLiteral literal)
|
if (tags is LuaLiteral literal) {
|
||||||
{
|
|
||||||
varName = literal.Lua;
|
varName = literal.Lua;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
result += Snippets.Convert(lua, "tags", tags);
|
result += Snippets.Convert(lua, "tags", tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We _reverse_ the order, so that the _most_ important one is at the _bottom_
|
// We _reverse_ the order, so that the _most_ important one is at the _bottom_
|
||||||
// The most important one will then _overwrite_ the result value
|
// The most important one will then _overwrite_ the result value
|
||||||
order.Reverse();
|
order.Reverse();
|
||||||
foreach (var t in order)
|
foreach (var t in order) {
|
||||||
{
|
if (!(t.Evaluate(c) is string key)) {
|
||||||
if (!(t.Evaluate(c) is string key))
|
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var func = mapping.StringToResultFunctions[key];
|
var func = mapping.StringToResultFunctions[key];
|
||||||
|
|
||||||
result += "if (" + varName + "[\"" + key + "\"] ~= nil) then\n";
|
result += "if (" + varName + "[\"" + key + "\"] ~= nil) then\n";
|
||||||
result += " " + Snippets.Convert(lua, assignTo, func.Apply(new LuaLiteral(Typs.String, "tags[\"" + key + "\"]"))).Indent();
|
result += " "+Snippets.Convert(lua, assignTo, func.Apply(new LuaLiteral(Typs.String, "tags[\""+key+"\"]"))).Indent();
|
||||||
result += "\n";
|
result += "\n";
|
||||||
result += "end\n";
|
result += "end\n";
|
||||||
// note: we do not do an 'elseif' as we have to fallthrough
|
// note: we do not do an 'elseif' as we have to fallthrough
|
||||||
if (result.Contains("tags[\"nil\"]"))
|
if (result.Contains("tags[\"nil\"]")) {
|
||||||
{
|
Console.WriteLine("EUHM");
|
||||||
Console.WriteLine("Warning: FirstMatchOf has a 'nil' in the indexes due to expression " + t.ToString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,32 +20,28 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
UnApply(IsFunc(Funcs.StringStringToTags),
|
UnApply(IsFunc(Funcs.StringStringToTags),
|
||||||
IsMapping(mappings)),
|
IsMapping(mappings)),
|
||||||
Assign(actualArgs)
|
Assign(actualArgs)
|
||||||
).Invoke(args[0]))
|
).Invoke(args[0])) {
|
||||||
{
|
|
||||||
var actualArg = actualArgs.First();
|
var actualArg = actualArgs.First();
|
||||||
var mapping = mappings.First();
|
var mapping = mappings.First();
|
||||||
|
|
||||||
if (mapping.StringToResultFunctions.Count != 1)
|
if (mapping.StringToResultFunctions.Count != 1) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (key, func) = mapping.StringToResultFunctions.ToList().First();
|
var (key, func) = mapping.StringToResultFunctions.ToList().First();
|
||||||
var result = "";
|
var result = "";
|
||||||
var tags = "";
|
var tags = "";
|
||||||
if (actualArg is LuaLiteral l)
|
if (actualArg is LuaLiteral l) {
|
||||||
{
|
|
||||||
tags = l.Lua;
|
tags = l.Lua;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
tags = lua.FreeVar("tags");
|
tags = lua.FreeVar("tags");
|
||||||
result += "local " + tags + "\n";
|
result += "local " + tags+"\n";
|
||||||
result += Snippets.Convert(lua, tags, actualArg);
|
result += Snippets.Convert(lua, tags, actualArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var v = lua.FreeVar("value");
|
var v = lua.FreeVar("value");
|
||||||
result += "local " + v + " = " + tags + "[\"" + key + "\"]\n";
|
result += "local " + v + " = " + tags + "[\"" + key + "\"]\n";
|
||||||
result += Snippets.Convert(lua, assignTo, func.Apply(new LuaLiteral(Typs.String, v)));
|
result += Snippets.Convert(lua, assignTo, func.Apply(new LuaLiteral(Typs.String, v)));
|
||||||
|
|
|
@ -11,27 +11,25 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
|
|
||||||
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
||||||
{
|
{
|
||||||
var fCond = args[0].Optimize(out _);
|
var fCond = args[0].Optimize();
|
||||||
var fValue = args[1];
|
var fValue = args[1];
|
||||||
IExpression fElse = null;
|
IExpression fElse = null;
|
||||||
var arg = args[2];
|
var arg = args[2];
|
||||||
if (args.Count == 4)
|
if (args.Count == 4) {
|
||||||
{
|
|
||||||
arg = args[3];
|
arg = args[3];
|
||||||
fElse = args[2];
|
fElse = args[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = lua.FreeVar("cond");
|
var c = lua.FreeVar("cond");
|
||||||
var result = "";
|
var result = "";
|
||||||
result += "local " + c + "\n";
|
result += "local " + c+"\n";
|
||||||
var condApplied = fCond.Apply(arg);
|
var condApplied = fCond.Apply(arg);
|
||||||
var isString = condApplied.Types.First().Equals(Typs.String);
|
var isString = condApplied.Types.First().Equals(Typs.String);
|
||||||
result += Snippets.Convert(lua, c, condApplied) + "\n";
|
result += Snippets.Convert(lua, c, condApplied)+"\n";
|
||||||
result += $"if ( {c} or {c} == \"yes\" ) then \n";
|
result += $"if ( {c} or {c} == \"yes\" ) then \n";
|
||||||
result += " " + Snippets.Convert(lua, assignTo, fValue.Apply(arg)).Indent();
|
result += " " + Snippets.Convert(lua, assignTo, fValue.Apply(arg)).Indent() ;
|
||||||
|
|
||||||
if (fElse != null)
|
if (fElse != null) {
|
||||||
{
|
|
||||||
result += "else\n";
|
result += "else\n";
|
||||||
result += " " + Snippets.Convert(lua, assignTo, fElse.Apply(arg)).Indent();
|
result += " " + Snippets.Convert(lua, assignTo, fElse.Apply(arg)).Indent();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
using static AspectedRouting.Language.Deconstruct;
|
|
||||||
|
|
||||||
namespace AspectedRouting.IO.LuaSnippets
|
namespace AspectedRouting.IO.LuaSnippets
|
||||||
{
|
{
|
||||||
|
@ -13,58 +11,29 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
|
|
||||||
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
||||||
{
|
{
|
||||||
var cond = args[0].Optimize(out _);
|
var cond = args[0].Optimize();
|
||||||
var ifTrue = args[1];
|
var ifTrue = args[1];
|
||||||
IExpression ifElse = null;
|
IExpression ifElse = null;
|
||||||
if (args.Count == 3)
|
if (args.Count == 3) {
|
||||||
{
|
|
||||||
ifElse = args[2];
|
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) {
|
||||||
var fa = new List<IExpression>();
|
result += "else\n";
|
||||||
if (UnApply(
|
result += " " + Snippets.Convert(lua, assignTo, ifElse).Indent();
|
||||||
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";
|
||||||
var c = lua.FreeVar("cond");
|
return result;
|
||||||
var result = "";
|
|
||||||
result += "local " + c + "\n";
|
|
||||||
|
|
||||||
var isString = cond.Types.First().Equals(Typs.String);
|
|
||||||
result += Snippets.Convert(lua, c, cond) + "\n";
|
|
||||||
result += $"if ( {c} == true 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
{
|
{
|
||||||
|
|
||||||
var result = Snippets.Convert(lua, assignTo, args[0]);
|
var result = Snippets.Convert(lua, assignTo, args[0]);
|
||||||
result += " " + assignTo + " = 1 / " + assignTo;
|
result += " "+ assignTo +" = 1 / " + assignTo;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,150 +21,99 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
|
|
||||||
public override string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, List<IExpression> args)
|
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
|
// 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
|
// 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 mappings = new List<Mapping>();
|
var mappingArg = arg.First();
|
||||||
var arg = new List<IExpression>();
|
if (!Equals(mappingArg.Types.First(), Typs.Tags)) {
|
||||||
if (args.Count == 1 && UnApply(UnApply(
|
return null;
|
||||||
IsFunc(Funcs.StringStringToTags),
|
|
||||||
IsMapping(mappings)),
|
|
||||||
Assign(arg)
|
|
||||||
).Invoke(args[0]))
|
|
||||||
{
|
|
||||||
var mapping = mappings.First();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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>();
|
string tags;
|
||||||
if (args.Count == 1 && UnApply(
|
if (mappingArg is LuaLiteral literal) {
|
||||||
UnApply(IsFunc(Funcs.ListDot),
|
tags = literal.Lua;
|
||||||
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")));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
result += "\n\n if (" + m + " ~= nil) then\n " + Combine(assignTo, m) + "\n end\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
var constantArgs = new List<Constant>();
|
).Invoke(listToMultiply)) {
|
||||||
if (args.Count == 1 && IsConstant(constantArgs).Invoke(args[0]))
|
var listDotArg = arg.First();
|
||||||
{
|
if (!(listDotArgs.First().Evaluate(lua.Context) is List<IExpression> functionsToApply)) {
|
||||||
if (!(constantArgs.First().Get() is List<IExpression> listItems))
|
return null;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,11 +137,9 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
IsFunc(Funcs.StringStringToTags),
|
IsFunc(Funcs.StringStringToTags),
|
||||||
IsMapping(mappings)
|
IsMapping(mappings)
|
||||||
)
|
)
|
||||||
).Invoke(app))
|
).Invoke(app)) {
|
||||||
{
|
|
||||||
var mapping = mappings.First();
|
var mapping = mappings.First();
|
||||||
if (mapping.StringToResultFunctions.Count == 1)
|
if (mapping.StringToResultFunctions.Count == 1) {
|
||||||
{
|
|
||||||
var kv = mapping.StringToResultFunctions.ToList().First();
|
var kv = mapping.StringToResultFunctions.ToList().First();
|
||||||
return (kv.Key, kv.Value);
|
return (kv.Key, kv.Value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Function ImplementsFunction;
|
public readonly Function ImplementsFunction;
|
||||||
|
|
||||||
protected LuaSnippet(Function implements)
|
protected LuaSnippet(Function implements)
|
||||||
{
|
{
|
||||||
ImplementsFunction = implements;
|
ImplementsFunction = implements;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
public MaxSnippet() : base(Funcs.Max, "nil") { }
|
public MaxSnippet() : base(Funcs.Max, "nil") { }
|
||||||
public override string Combine(string assignTo, string value)
|
public override string Combine(string assignTo, string value)
|
||||||
{
|
{
|
||||||
return Utils.Lines("if ( " + assignTo + " == nil or" + assignTo + " < " + value + " ) then",
|
return Utils.Lines("if ( "+ assignTo + " == nil or" + assignTo + " < " + value + " ) then",
|
||||||
" " + assignTo + " = " + value,
|
" " + assignTo + " = " + value,
|
||||||
"end");
|
"end");
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,10 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
|
|
||||||
var tags = "";
|
var tags = "";
|
||||||
var result = "";
|
var result = "";
|
||||||
if (tagsToken is LuaLiteral lit)
|
if (tagsToken is LuaLiteral lit) {
|
||||||
{
|
|
||||||
tags = lit.Lua;
|
tags = lit.Lua;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
tags = lua.FreeVar("tags");
|
tags = lua.FreeVar("tags");
|
||||||
result += "local " + tags + "\n";
|
result += "local " + tags + "\n";
|
||||||
result += Snippets.Convert(lua, tags, tagsToken);
|
result += Snippets.Convert(lua, tags, tagsToken);
|
||||||
|
|
|
@ -17,19 +17,17 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
var result = "";
|
var result = "";
|
||||||
var neededKeys = lua.FreeVar("neededKeys");
|
var neededKeys = lua.FreeVar("neededKeys");
|
||||||
var tags = "";
|
var tags = "";
|
||||||
if (tagsExpr is LuaLiteral literal)
|
if (tagsExpr is LuaLiteral literal) {
|
||||||
{
|
|
||||||
tags = literal.Lua;
|
tags = literal.Lua;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
tags = lua.FreeVar("tags");
|
||||||
tags = lua.FreeVar("tags");
|
result += $"local {tags}";
|
||||||
result += $"local {tags}";
|
result += Snippets.Convert(lua, tags, tagsExpr);
|
||||||
result += Snippets.Convert(lua, tags, tagsExpr);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result += $"local {neededKeys}\n";
|
result += $"local {neededKeys}\n";
|
||||||
result += Snippets.Convert(lua, neededKeys, neededKeysExpr);
|
result += Snippets.Convert(lua, neededKeys, neededKeysExpr);
|
||||||
var key = lua.FreeVar("key");
|
var key = lua.FreeVar("key");
|
||||||
|
@ -38,7 +36,7 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
result += $" local {value} = {tags}[{key}]\n";
|
result += $" local {value} = {tags}[{key}]\n";
|
||||||
result += $" if ({value} == nil) then\n";
|
result += $" if ({value} == nil) then\n";
|
||||||
result += $" -- The value is nil, so mustmatch probably fails...\n";
|
result += $" -- The value is nil, so mustmatch probably fails...\n";
|
||||||
|
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,9 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
var vLua = new LuaLiteral(Typs.String, v);
|
var vLua = new LuaLiteral(Typs.String, v);
|
||||||
|
|
||||||
var mappings = new List<string>();
|
var mappings = new List<string>();
|
||||||
foreach (var kv in _mapping.StringToResultFunctions)
|
foreach (var kv in _mapping.StringToResultFunctions) {
|
||||||
{
|
|
||||||
var f = kv.Value;
|
var f = kv.Value;
|
||||||
if (f.Types.First() is Curry)
|
if (f.Types.First() is Curry) {
|
||||||
{
|
|
||||||
f = f.Apply(vLua);
|
f = f.Apply(vLua);
|
||||||
}
|
}
|
||||||
mappings.Add("if (" + v + " == \"" + kv.Key + "\") then\n " + assignTo + " = " + lua.ToLua(f));
|
mappings.Add("if (" + v + " == \"" + kv.Key + "\") then\n " + assignTo + " = " + lua.ToLua(f));
|
||||||
|
|
|
@ -33,44 +33,37 @@ namespace AspectedRouting.IO.LuaSnippets
|
||||||
public static string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, IExpression e)
|
public static string Convert(LuaSkeleton.LuaSkeleton lua, string assignTo, IExpression e)
|
||||||
{
|
{
|
||||||
|
|
||||||
var opt = e.Optimize(out _);
|
var opt = e.Optimize();
|
||||||
// Note that optimization might optimize to a _subtype_ of the original expresion - which is fine!
|
// Note that optimization might optimize to a _subtype_ of the original expresion - which is fine!
|
||||||
var origType = e.Types.First();
|
var origType = e.Types.First();
|
||||||
var optType = opt.Types.First();
|
var optType = opt.Types.First();
|
||||||
if (!origType.Equals(optType) && !origType.IsSuperSet(optType))
|
if (!origType.Equals(optType) && !origType.IsSuperSet(optType)) {
|
||||||
{
|
|
||||||
throw new Exception("Optimization went wrong!");
|
throw new Exception("Optimization went wrong!");
|
||||||
}
|
}
|
||||||
e = opt;
|
e = opt;
|
||||||
var deconstructed = e.DeconstructApply();
|
var deconstructed = e.DeconstructApply();
|
||||||
|
|
||||||
|
if (deconstructed != null){
|
||||||
|
|
||||||
if (deconstructed != null)
|
if (deconstructed.Value.f is Mapping m) {
|
||||||
{
|
|
||||||
|
|
||||||
if (deconstructed.Value.f is Mapping m)
|
|
||||||
{
|
|
||||||
return new SimpleMappingSnippet(m).Convert(lua, assignTo, deconstructed.Value.args);
|
return new SimpleMappingSnippet(m).Convert(lua, assignTo, deconstructed.Value.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deconstructed.Value.f is Function f
|
if (deconstructed.Value.f is Function f
|
||||||
&& SnippetsIndex.TryGetValue(f.Name, out var snippet))
|
&& SnippetsIndex.TryGetValue(f.Name, out var snippet)) {
|
||||||
{
|
|
||||||
var optimized = snippet.Convert(lua, assignTo, deconstructed.Value.args);
|
var optimized = snippet.Convert(lua, assignTo, deconstructed.Value.args);
|
||||||
if (optimized != null)
|
if (optimized != null) {
|
||||||
{
|
|
||||||
return optimized + "\n";
|
return optimized + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
return assignTo + " = " + lua.ToLua(e) + "\n";
|
return assignTo + " = " + lua.ToLua(e)+"\n";
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception err) {
|
||||||
{
|
|
||||||
return "print(\"ERROR COMPILER BUG\");\n";
|
return "print(\"ERROR COMPILER BUG\");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,7 @@ namespace AspectedRouting.IO
|
||||||
{
|
{
|
||||||
public static void GenerateHelpText(string saveTo = null)
|
public static void GenerateHelpText(string saveTo = null)
|
||||||
{
|
{
|
||||||
var format = File.ReadAllText("Format.md");
|
var helpText = TypeOverview +
|
||||||
var helpText = format + "\n\n" + TypeOverview +
|
|
||||||
FunctionOverview;
|
FunctionOverview;
|
||||||
|
|
||||||
if (saveTo == null)
|
if (saveTo == null)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.IO.LuaSkeleton;
|
using AspectedRouting.IO.LuaSkeleton;
|
||||||
using AspectedRouting.IO.LuaSnippets;
|
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Functions;
|
using AspectedRouting.Language.Functions;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
|
@ -15,10 +14,10 @@ namespace AspectedRouting.IO.itinero1
|
||||||
private string GenerateMainProfileFunction()
|
private string GenerateMainProfileFunction()
|
||||||
{
|
{
|
||||||
|
|
||||||
var access = _skeleton.ToLuaWithTags(_profile.Access);
|
var access = _skeleton.ToLua(_profile.Access);
|
||||||
var oneway = _skeleton.ToLuaWithTags(_profile.Oneway);
|
var oneway = _skeleton.ToLua(_profile.Oneway);
|
||||||
var speed = _skeleton.ToLuaWithTags(_profile.Speed);
|
var speed = _skeleton.ToLua(_profile.Speed);
|
||||||
|
|
||||||
var impl = string.Join("\n",
|
var impl = string.Join("\n",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
@ -28,6 +27,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
"Comfort is calculated as well, based on the parameters which are padded in",
|
"Comfort is calculated as well, based on the parameters which are padded in",
|
||||||
"",
|
"",
|
||||||
"Created by " + _profile.Author,
|
"Created by " + _profile.Author,
|
||||||
|
"Originally defined in " + _profile.Filename,
|
||||||
"]]",
|
"]]",
|
||||||
"function " + _profile.Name + "(parameters, tags, result)",
|
"function " + _profile.Name + "(parameters, tags, result)",
|
||||||
"",
|
"",
|
||||||
|
@ -54,22 +54,18 @@ namespace AspectedRouting.IO.itinero1
|
||||||
impl +=
|
impl +=
|
||||||
"\n local priority = 0\n ";
|
"\n local priority = 0\n ";
|
||||||
|
|
||||||
var tags = new LuaLiteral(Typs.Tags, "tags");
|
|
||||||
foreach (var (parameterName, expression) in _profile.Priority)
|
foreach (var (parameterName, expression) in _profile.Priority)
|
||||||
{
|
{
|
||||||
var paramInLua = _skeleton.ToLua(new Parameter(parameterName));
|
var paramInLua = _skeleton.ToLua(new Parameter(parameterName));
|
||||||
|
|
||||||
|
|
||||||
var expr = Funcs.Either(Funcs.Id, Funcs.Const, expression).Apply(tags)
|
var exprInLua = _skeleton.ToLua(expression.Optimize(), forceFirstArgInDot: true);
|
||||||
.SpecializeToSmallestType()
|
var resultTypes = expression.Types.Select(t => t.Uncurry().Last());
|
||||||
.PruneTypes(t => !(t is Curry))
|
if (resultTypes.Any(t => t.Name.Equals(Typs.Bool.Name)))
|
||||||
.Optimize(out _);
|
|
||||||
|
|
||||||
if (expr.Types.Any(t => t.Name.Equals(Typs.Bool.Name)))
|
|
||||||
{
|
{
|
||||||
expr = Funcs.Parse.Apply(expr).SpecializeToSmallestType();
|
_skeleton. AddDep("parse");
|
||||||
|
exprInLua = "parse(" + exprInLua + ")";
|
||||||
}
|
}
|
||||||
var exprInLua = _skeleton.ToLua(expr);
|
|
||||||
|
|
||||||
impl += "\n " + string.Join("\n ",
|
impl += "\n " + string.Join("\n ",
|
||||||
$"if({paramInLua} ~= 0) then",
|
$"if({paramInLua} ~= 0) then",
|
||||||
|
@ -78,14 +74,8 @@ namespace AspectedRouting.IO.itinero1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var scalingFactor = Funcs.Default.Apply(new Constant(Typs.Double, 1.0), _profile.ScalingFactor, tags);
|
|
||||||
|
|
||||||
impl += string.Join("\n",
|
impl += string.Join("\n",
|
||||||
" -- Calculate the scaling factor",
|
|
||||||
" local scalingfactor",
|
|
||||||
Snippets.Convert(_skeleton, "scalingfactor", scalingFactor.SpecializeToSmallestType()),
|
|
||||||
"",
|
|
||||||
"priority = priority * scalingfactor",
|
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
" if (priority <= 0) then",
|
" if (priority <= 0) then",
|
||||||
|
@ -107,10 +97,10 @@ namespace AspectedRouting.IO.itinero1
|
||||||
"end"
|
"end"
|
||||||
);
|
);
|
||||||
|
|
||||||
return impl;
|
return impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private (string functionName, string implementation) GenerateBehaviourFunction(
|
private (string functionName, string implementation) GenerateBehaviourFunction(
|
||||||
string behaviourName,
|
string behaviourName,
|
||||||
Dictionary<string, IExpression> behaviourParameters)
|
Dictionary<string, IExpression> behaviourParameters)
|
||||||
|
@ -119,15 +109,9 @@ namespace AspectedRouting.IO.itinero1
|
||||||
var functionName = referenceName.AsLuaIdentifier();
|
var functionName = referenceName.AsLuaIdentifier();
|
||||||
behaviourParameters.TryGetValue("description", out var description);
|
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");
|
_skeleton.AddDep("remove_relation_prefix");
|
||||||
var impl = string.Join("\n",
|
var impl = string.Join("\n",
|
||||||
"behaviour_" + functionName + "_used_keys = create_set({" + string.Join(", ", usedkeys) + "})",
|
"",
|
||||||
"--[[",
|
"--[[",
|
||||||
description,
|
description,
|
||||||
"]]",
|
"]]",
|
||||||
|
@ -141,7 +125,6 @@ namespace AspectedRouting.IO.itinero1
|
||||||
impl += _parameterPrinter.DeclareParametersFor(behaviourParameters);
|
impl += _parameterPrinter.DeclareParametersFor(behaviourParameters);
|
||||||
|
|
||||||
impl += " " + _profile.Name + "(parameters, tags, result)\n";
|
impl += " " + _profile.Name + "(parameters, tags, result)\n";
|
||||||
impl += " copy_tags(tags, result.attributes_to_keep, behaviour_" + functionName + "_used_keys)\n";
|
|
||||||
impl += "end\n";
|
impl += "end\n";
|
||||||
return (functionName, impl);
|
return (functionName, impl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
{
|
{
|
||||||
public partial class LuaPrinter1
|
public partial class LuaPrinter1
|
||||||
{
|
{
|
||||||
|
|
||||||
private (string implementation, HashSet<string> extraKeys) GenerateMembershipPreprocessor()
|
private (string implementation, HashSet<string> extraKeys) GenerateMembershipPreprocessor()
|
||||||
{
|
{
|
||||||
// Extra keys are the names of introduced tag-keys, e.g. '_relation:bicycle_fastest:cycle_highway'
|
// Extra keys are the names of introduced tag-keys, e.g. '_relation:bicycle_fastest:cycle_highway'
|
||||||
|
@ -44,7 +44,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
" legacy_relation_preprocessor(relation_tags, result)"
|
" legacy_relation_preprocessor(relation_tags, result)"
|
||||||
};
|
};
|
||||||
_skeleton.AddDep("legacy");
|
_skeleton.AddDep("legacy");
|
||||||
|
|
||||||
foreach (var (calledInFunction, expr) in memberships)
|
foreach (var (calledInFunction, expr) in memberships)
|
||||||
{
|
{
|
||||||
func.Add($"\n\n -- {calledInFunction} ---");
|
func.Add($"\n\n -- {calledInFunction} ---");
|
||||||
|
@ -57,7 +57,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
func.Add("");
|
func.Add("");
|
||||||
func.Add(" subresult.attributes_to_keep = {}");
|
func.Add(" subresult.attributes_to_keep = {}");
|
||||||
func.Add(" parameters = default_parameters()");
|
func.Add(" parameters = default_parameters()");
|
||||||
func.Add($" matched = {preProcName}(relation_tags, parameters)");
|
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
||||||
func.Add(" if (matched) then");
|
func.Add(" if (matched) then");
|
||||||
var tagKey = "_relation:" + calledInFunction.AsLuaIdentifier();
|
var tagKey = "_relation:" + calledInFunction.AsLuaIdentifier();
|
||||||
extraKeys.Add(tagKey);
|
extraKeys.Add(tagKey);
|
||||||
|
@ -90,7 +90,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
func.Add(" parameters = default_parameters()");
|
func.Add(" parameters = default_parameters()");
|
||||||
func.Add(_parameterPrinter.DeclareParametersFor(parameters.Where(kv => usedParameters.Contains(kv.Key))
|
func.Add(_parameterPrinter.DeclareParametersFor(parameters.Where(kv => usedParameters.Contains(kv.Key))
|
||||||
.ToDictionary(kv => kv.Key, kv => kv.Value)));
|
.ToDictionary(kv => kv.Key, kv => kv.Value)));
|
||||||
func.Add($" matched = {preProcName}(relation_tags, parameters)");
|
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
||||||
func.Add(" if (matched) then");
|
func.Add(" if (matched) then");
|
||||||
tagKey = "_relation:" + behaviourName.AsLuaIdentifier() + ":" + calledInFunction.AsLuaIdentifier();
|
tagKey = "_relation:" + behaviourName.AsLuaIdentifier() + ":" + calledInFunction.AsLuaIdentifier();
|
||||||
extraKeys.Add(tagKey);
|
extraKeys.Add(tagKey);
|
||||||
|
|
|
@ -27,19 +27,18 @@ namespace AspectedRouting.IO.itinero1
|
||||||
_aspectTestSuites = aspectTestSuites?.Where(suite => suite != null)
|
_aspectTestSuites = aspectTestSuites?.Where(suite => suite != null)
|
||||||
?.Select(testSuite => testSuite.WithoutRelationTests())?.ToList();
|
?.Select(testSuite => testSuite.WithoutRelationTests())?.ToList();
|
||||||
_profileTests = profileTests;
|
_profileTests = profileTests;
|
||||||
_skeleton = new LuaSkeleton.LuaSkeleton(context, true);
|
_skeleton = new LuaSkeleton.LuaSkeleton(context, false);
|
||||||
_parameterPrinter = new LuaParameterPrinter(profile, _skeleton);
|
_parameterPrinter = new LuaParameterPrinter(profile, _skeleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToLua()
|
public string ToLua()
|
||||||
{
|
{
|
||||||
_skeleton.AddDep("spoken_instructions");
|
_skeleton.AddDep("spoken_instructions");
|
||||||
|
|
||||||
var (membershipFunction, extraKeys) = GenerateMembershipPreprocessor();
|
var (membershipFunction, extraKeys) = GenerateMembershipPreprocessor();
|
||||||
var (profileOverview, behaviourFunctions) = GenerateProfileFunctions();
|
var (profileOverview, behaviourFunctions) = GenerateProfileFunctions();
|
||||||
var mainFunction = GenerateMainProfileFunction();
|
var mainFunction = GenerateMainProfileFunction();
|
||||||
var tests = new LuaTestPrinter(_skeleton, new List<string> { "unitTest", "unitTestProfile" })
|
var tests = new LuaTestPrinter(_skeleton, new List<string>{"unitTest","unitTestProfile"}).GenerateFullTestSuite(_profileTests, _aspectTestSuites);
|
||||||
.GenerateFullTestSuite(_profileTests, _aspectTestSuites);
|
|
||||||
|
|
||||||
|
|
||||||
var keys = _profile.AllExpressions(_context).PossibleTags().Keys
|
var keys = _profile.AllExpressions(_context).PossibleTags().Keys
|
||||||
|
@ -49,10 +48,10 @@ namespace AspectedRouting.IO.itinero1
|
||||||
|
|
||||||
var header = new List<string>
|
var header = new List<string>
|
||||||
{
|
{
|
||||||
$"-- Itinero 1.0-profile, generated by AspectedRouting.",
|
$"-- Itinero 1.0-profile, generated by AspectedRouting. Last source file change is {_profile.LastChange:s}",
|
||||||
$"name = \"{_profile.Name}\"",
|
$"name = \"{_profile.Name}\"",
|
||||||
"normalize = false",
|
"normalize = false",
|
||||||
"vehicle_types = {" + string.Join(", ", _profile.VehicleTyps.Select(s => "\"" + s + "\"")) + "}",
|
"vehicle_type = {" + string.Join(", ", _profile.VehicleTyps.Select(s => "\"" + s + "\"")) + "}",
|
||||||
// meta_whitelist is defined in the profile file, these are tags that are included in the generated route, but are not relevant for determining weights
|
// meta_whitelist is defined in the profile file, these are tags that are included in the generated route, but are not relevant for determining weights
|
||||||
"meta_whitelist = {\n"
|
"meta_whitelist = {\n"
|
||||||
+ string.Join("\n , ", _profile.Metadata.Select(s => "\"" + s + "\""))
|
+ string.Join("\n , ", _profile.Metadata.Select(s => "\"" + s + "\""))
|
||||||
|
@ -63,15 +62,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
"",
|
"",
|
||||||
profileOverview,
|
profileOverview,
|
||||||
"",
|
"",
|
||||||
_parameterPrinter.GenerateDefaultParameters(),
|
_parameterPrinter.GenerateDefaultParameters()
|
||||||
"",
|
|
||||||
"function create_set(list)",
|
|
||||||
" local set = {}",
|
|
||||||
" for _, l in ipairs(list) do " +
|
|
||||||
" set[l] = true" +
|
|
||||||
" end",
|
|
||||||
" return set",
|
|
||||||
"end"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,7 +106,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
var behaviourImplementations = new List<string>();
|
var behaviourImplementations = new List<string>();
|
||||||
foreach (var (behaviourName, behaviourParameters) in _profile.Behaviours)
|
foreach (var (behaviourName, behaviourParameters) in _profile.Behaviours)
|
||||||
{
|
{
|
||||||
var (functionName, implementation) = GenerateBehaviourFunction(behaviourName, behaviourParameters);
|
var (functionName, implementation ) = GenerateBehaviourFunction(behaviourName, behaviourParameters);
|
||||||
behaviourImplementations.Add(implementation);
|
behaviourImplementations.Add(implementation);
|
||||||
profiles.Add(
|
profiles.Add(
|
||||||
string.Join(",\n ",
|
string.Join(",\n ",
|
||||||
|
@ -151,8 +142,6 @@ namespace AspectedRouting.IO.itinero1
|
||||||
"test_all()",
|
"test_all()",
|
||||||
"if (not failed_tests and not failed_profile_tests) then",
|
"if (not failed_tests and not failed_profile_tests) then",
|
||||||
" print(\"Tests OK\")",
|
" print(\"Tests OK\")",
|
||||||
"else",
|
|
||||||
" error(\"Some tests failed\")",
|
|
||||||
"end"
|
"end"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.IO.LuaSkeleton;
|
|
||||||
using AspectedRouting.IO.LuaSnippets;
|
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Functions;
|
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
|
|
||||||
namespace AspectedRouting.IO.itinero2
|
namespace AspectedRouting.IO.itinero2
|
||||||
|
@ -15,43 +11,56 @@ namespace AspectedRouting.IO.itinero2
|
||||||
private string GenerateFactorFunction()
|
private string GenerateFactorFunction()
|
||||||
{
|
{
|
||||||
var parameters = new Dictionary<string, IExpression>();
|
var parameters = new Dictionary<string, IExpression>();
|
||||||
foreach (var (name, value) in _profile.DefaultParameters) parameters[name] = value;
|
foreach (var (name, value) in _profile.DefaultParameters)
|
||||||
|
{
|
||||||
|
parameters[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var (name, value) in _profile.Behaviours[_behaviourName]) parameters[name] = value;
|
foreach (var (name, value) in _profile.Behaviours[_behaviourName])
|
||||||
|
{
|
||||||
|
parameters[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var aspects = new List<string>();
|
var aspects = new List<string>();
|
||||||
var tags = new LuaLiteral(Typs.Tags, "tags");
|
|
||||||
foreach (var (paramName, expr) in _profile.Priority)
|
foreach (var (paramName, expr) in _profile.Priority)
|
||||||
{
|
{
|
||||||
var weightExpr = parameters[paramName].Evaluate(_context);
|
var weightExpr = parameters[paramName].Evaluate(_context);
|
||||||
if (!(weightExpr is double weight)) continue;
|
if (!(weightExpr is double weight))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (weight == 0) continue;
|
if (weight == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// The expression might still have multiple typings,
|
// The expression might still have multiple typings,
|
||||||
// which take inputs different from 'Tags', so we specialize the expr first
|
// which take inputs different from 'Tags', so we specialize the expr first
|
||||||
var appliedExpr = Funcs.Either(Funcs.Id, Funcs.Const, expr)
|
var exprSpecialized = expr;
|
||||||
.Apply(tags)
|
var resultType = expr.Types.First();
|
||||||
.PruneTypes(tp => !(tp is Curry));
|
if (exprSpecialized.Types.Count() >=2) {
|
||||||
var exprSpecialized = appliedExpr.Optimize(out _);
|
exprSpecialized = expr.Specialize(new Curry(Typs.Tags, new Var("a")));
|
||||||
|
if (exprSpecialized == null) {
|
||||||
if (exprSpecialized.Types.First().Equals(Typs.Bool) ||
|
throw new Exception("Could not specialize expression to type tags -> $a");
|
||||||
exprSpecialized.Types.First().Equals(Typs.String))
|
}
|
||||||
{
|
resultType = (exprSpecialized.Types.First() as Curry).ResultType;
|
||||||
_skeleton.AddDep("parse");
|
|
||||||
exprSpecialized = Funcs.Parse.Apply(exprSpecialized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var exprInLua = _skeleton.ToLua(exprSpecialized);
|
var exprInLua = _skeleton.ToLua(exprSpecialized);
|
||||||
if (exprInLua.Contains("constRight") || exprInLua.Contains("firstArg"))
|
if (resultType.Equals(Typs.Bool) || resultType.Equals(Typs.String))
|
||||||
throw new Exception("Not optimized properly:" + exprSpecialized.Repr());
|
{
|
||||||
aspects.Add(weight.ToString(CultureInfo.InvariantCulture) + " * " + exprInLua.ToString(CultureInfo.InvariantCulture));
|
_skeleton.AddDep("parse");
|
||||||
|
exprInLua = "parse(" + exprInLua + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
aspects.Add(weight + " * " + exprInLua);
|
||||||
}
|
}
|
||||||
|
|
||||||
var scalingFactor = Funcs.Default.Apply(new Constant(Typs.Double, 1.0), _profile.ScalingFactor, tags)
|
Console.WriteLine(aspects.Lined());
|
||||||
.SpecializeToSmallestType();
|
var code = new List<string>()
|
||||||
var code = new List<string>
|
|
||||||
{
|
{
|
||||||
"--[[",
|
"--[[",
|
||||||
"Generates the factor according to the priorities and the parameters for this behaviour",
|
"Generates the factor according to the priorities and the parameters for this behaviour",
|
||||||
|
@ -60,64 +69,12 @@ namespace AspectedRouting.IO.itinero2
|
||||||
"function calculate_priority(parameters, tags, result, access, oneway, speed)",
|
"function calculate_priority(parameters, tags, result, access, oneway, speed)",
|
||||||
" local distance = 1",
|
" local distance = 1",
|
||||||
" local priority = \n " + string.Join(" +\n ", aspects),
|
" local priority = \n " + string.Join(" +\n ", aspects),
|
||||||
"",
|
" return priority",
|
||||||
"local scalingfactor",
|
|
||||||
Snippets.Convert(_skeleton, "scalingfactor", scalingFactor),
|
|
||||||
" return priority * scalingfactor",
|
|
||||||
"end"
|
"end"
|
||||||
};
|
};
|
||||||
return code.Lined();
|
return code.Lined();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenerateTurnCostFunction()
|
|
||||||
{
|
|
||||||
var vehicleTypes = _profile.VehicleTyps;
|
|
||||||
_skeleton.AddDep("containedIn");
|
|
||||||
_skeleton.AddDep("str_split");
|
|
||||||
_skeleton.AddDep("calculate_turn_cost_factor");
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the turn cost factor for relation attributes or obstacles.
|
|
||||||
Keep in mind that there are no true relations in the routerDB anymore, instead the attributes are copied onto a turn cost object.
|
|
||||||
This turn cost object has a set of sequence of edges and is applied onto the vertex.0
|
|
||||||
|
|
||||||
Obstacles such as bollards are converted into a turn cost as well.
|
|
||||||
calculate_turn_cost_factor will be called for this bollard too to calculate the weight.
|
|
||||||
|
|
||||||
If result.factor = -1 if passing is not possible - this is more or less equal to an infinite cost
|
|
||||||
If result.factor = 0 if no weight/passing is possible
|
|
||||||
If result.factor is positive, that is the cost.
|
|
||||||
|
|
||||||
There is no forward or backward, so this should always be the same for the same attributes
|
|
||||||
*/
|
|
||||||
var parameters = _profile.Behaviours[_behaviourName];
|
|
||||||
var tags = new LuaLiteral(Typs.Tags, "attributes");
|
|
||||||
var hasAccess = _profile.ObstacleAccess.Apply(tags).SpecializeToSmallestType().Optimize(out _);
|
|
||||||
var code = new List<string>
|
|
||||||
{
|
|
||||||
"--[[ Function called by itinero2 on every turn restriction relation", " ]]",
|
|
||||||
"function turn_cost_factor(attributes, result)",
|
|
||||||
" local parameters = default_parameters()",
|
|
||||||
_parameterPrinter.DeclareParametersFor(parameters),
|
|
||||||
"local has_access",
|
|
||||||
Snippets.Convert(_skeleton, "has_access", hasAccess),
|
|
||||||
"if ( has_access == \"no\" or has_access == \"false\") then",
|
|
||||||
" result.factor = -1",
|
|
||||||
"else",
|
|
||||||
Snippets.Convert(_skeleton, "result.factor", _profile.ObstacleCost.Apply(tags).SpecializeToSmallestType().Optimize(out _)),
|
|
||||||
"end",
|
|
||||||
|
|
||||||
" -- not known by the profile or invalid value - use the default implementation",
|
|
||||||
" if (result.factor == nil) then",
|
|
||||||
" result.factor = calculate_turn_cost_factor(attributes, vehicle_types)",
|
|
||||||
" end",
|
|
||||||
"end",
|
|
||||||
""
|
|
||||||
};
|
|
||||||
return code.Lined();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GenerateMainFunction()
|
private string GenerateMainFunction()
|
||||||
{
|
{
|
||||||
var parameters = _profile.Behaviours[_behaviourName];
|
var parameters = _profile.Behaviours[_behaviourName];
|
||||||
|
@ -128,7 +85,6 @@ There is no forward or backward, so this should always be the same for the same
|
||||||
|
|
||||||
_skeleton.AddDep("eq");
|
_skeleton.AddDep("eq");
|
||||||
_skeleton.AddDep("remove_relation_prefix");
|
_skeleton.AddDep("remove_relation_prefix");
|
||||||
_skeleton.AddDep("debug_table");
|
|
||||||
var code = new List<string>
|
var code = new List<string>
|
||||||
{
|
{
|
||||||
"--[[",
|
"--[[",
|
||||||
|
@ -152,7 +108,7 @@ There is no forward or backward, so this should always be the same for the same
|
||||||
" local parameters = default_parameters()",
|
" local parameters = default_parameters()",
|
||||||
_parameterPrinter.DeclareParametersFor(parameters),
|
_parameterPrinter.DeclareParametersFor(parameters),
|
||||||
"",
|
"",
|
||||||
" local oneway = " + _skeleton.ToLuaWithTags(_profile.Oneway).Indent(),
|
" local oneway = " + _skeleton.ToLua(_profile.Oneway),
|
||||||
" tags.oneway = oneway",
|
" tags.oneway = oneway",
|
||||||
" -- An aspect describing oneway should give either 'both', 'against' or 'width'",
|
" -- An aspect describing oneway should give either 'both', 'against' or 'width'",
|
||||||
|
|
||||||
|
@ -160,7 +116,7 @@ There is no forward or backward, so this should always be the same for the same
|
||||||
"",
|
"",
|
||||||
" -- forward calculation. We set the meta tag '_direction' to 'width' to indicate that we are going forward. The other functions will pick this up",
|
" -- 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\"",
|
" tags[\"_direction\"] = \"with\"",
|
||||||
" local access_forward = " + _skeleton.ToLuaWithTags(_profile.Access).Indent(),
|
" local access_forward = " + _skeleton.ToLua(_profile.Access),
|
||||||
" if(oneway == \"against\") then",
|
" if(oneway == \"against\") then",
|
||||||
" -- no 'oneway=both' or 'oneway=with', so we can only go back over this segment",
|
" -- 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...",
|
" -- we overwrite the 'access_forward'-value with no; whatever it was...",
|
||||||
|
@ -168,7 +124,7 @@ There is no forward or backward, so this should always be the same for the same
|
||||||
" end",
|
" end",
|
||||||
" if(access_forward ~= nil and access_forward ~= \"no\" and access_forward ~= false) then",
|
" if(access_forward ~= nil and access_forward ~= \"no\" and access_forward ~= false) then",
|
||||||
" tags.access = access_forward -- might be relevant, e.g. for 'access=dismount' for bicycles",
|
" tags.access = access_forward -- might be relevant, e.g. for 'access=dismount' for bicycles",
|
||||||
" result.forward_speed = " + _skeleton.ToLuaWithTags(_profile.Speed).Indent(),
|
" result.forward_speed = " + _skeleton.ToLua(_profile.Speed).Indent(),
|
||||||
" tags.speed = result.forward_speed",
|
" tags.speed = result.forward_speed",
|
||||||
" local priority = calculate_priority(parameters, tags, result, access_forward, oneway, result.forward_speed)",
|
" local priority = calculate_priority(parameters, tags, result, access_forward, oneway, result.forward_speed)",
|
||||||
" if (priority <= 0) then",
|
" if (priority <= 0) then",
|
||||||
|
@ -180,7 +136,7 @@ There is no forward or backward, so this should always be the same for the same
|
||||||
"",
|
"",
|
||||||
" -- backward calculation",
|
" -- backward calculation",
|
||||||
" tags[\"_direction\"] = \"against\" -- indicate the backward direction to priority calculation",
|
" tags[\"_direction\"] = \"against\" -- indicate the backward direction to priority calculation",
|
||||||
" local access_backward = " + _skeleton.ToLuaWithTags(_profile.Access).Indent(),
|
" local access_backward = " + _skeleton.ToLua(_profile.Access),
|
||||||
" if(oneway == \"with\") then",
|
" if(oneway == \"with\") then",
|
||||||
" -- no 'oneway=both' or 'oneway=against', so we can only go forward over this segment",
|
" -- 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...",
|
" -- we overwrite the 'access_forward'-value with no; whatever it was...",
|
||||||
|
@ -188,7 +144,7 @@ There is no forward or backward, so this should always be the same for the same
|
||||||
" end",
|
" end",
|
||||||
" if(access_backward ~= nil and access_backward ~= \"no\" and access_backward ~= false) then",
|
" if(access_backward ~= nil and access_backward ~= \"no\" and access_backward ~= false) then",
|
||||||
" tags.access = access_backward",
|
" tags.access = access_backward",
|
||||||
" result.backward_speed = " + _skeleton.ToLuaWithTags(_profile.Speed).Indent(),
|
" result.backward_speed = " + _skeleton.ToLua(_profile.Speed).Indent(),
|
||||||
" tags.speed = result.backward_speed",
|
" tags.speed = result.backward_speed",
|
||||||
" local priority = calculate_priority(parameters, tags, result, access_backward, oneway, result.backward_speed)",
|
" local priority = calculate_priority(parameters, tags, result, access_backward, oneway, result.backward_speed)",
|
||||||
" if (priority <= 0) then",
|
" if (priority <= 0) then",
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.IO.itinero1;
|
using AspectedRouting.IO.itinero1;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Expression;
|
using AspectedRouting.Language.Expression;
|
||||||
using AspectedRouting.Language.Functions;
|
|
||||||
using AspectedRouting.Tests;
|
using AspectedRouting.Tests;
|
||||||
|
|
||||||
namespace AspectedRouting.IO.itinero2
|
namespace AspectedRouting.IO.itinero2
|
||||||
|
@ -28,7 +28,7 @@ namespace AspectedRouting.IO.itinero2
|
||||||
private readonly string _behaviourName;
|
private readonly string _behaviourName;
|
||||||
private readonly IEnumerable<BehaviourTestSuite> _behaviourTestSuite;
|
private readonly IEnumerable<BehaviourTestSuite> _behaviourTestSuite;
|
||||||
private readonly Context _context;
|
private readonly Context _context;
|
||||||
private readonly bool _includeTests;
|
private readonly DateTime _lastChangeTime;
|
||||||
private readonly LuaParameterPrinter _parameterPrinter;
|
private readonly LuaParameterPrinter _parameterPrinter;
|
||||||
private readonly ProfileMetaData _profile;
|
private readonly ProfileMetaData _profile;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ namespace AspectedRouting.IO.itinero2
|
||||||
public LuaPrinter2(ProfileMetaData profile, string behaviourName,
|
public LuaPrinter2(ProfileMetaData profile, string behaviourName,
|
||||||
Context context,
|
Context context,
|
||||||
List<AspectTestSuite> aspectTests, IEnumerable<BehaviourTestSuite> behaviourTestSuite,
|
List<AspectTestSuite> aspectTests, IEnumerable<BehaviourTestSuite> behaviourTestSuite,
|
||||||
bool includeTests = true)
|
DateTime lastChangeTime)
|
||||||
{
|
{
|
||||||
_skeleton = new LuaSkeleton.LuaSkeleton(context, true);
|
_skeleton = new LuaSkeleton.LuaSkeleton(context, true);
|
||||||
_profile = profile;
|
_profile = profile;
|
||||||
|
@ -46,14 +46,45 @@ namespace AspectedRouting.IO.itinero2
|
||||||
_context = context;
|
_context = context;
|
||||||
_aspectTests = aspectTests;
|
_aspectTests = aspectTests;
|
||||||
_behaviourTestSuite = behaviourTestSuite;
|
_behaviourTestSuite = behaviourTestSuite;
|
||||||
_includeTests = includeTests;
|
_lastChangeTime = lastChangeTime;
|
||||||
_parameterPrinter = new LuaParameterPrinter(_profile, _skeleton);
|
_parameterPrinter = new LuaParameterPrinter(_profile, _skeleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string TestRunner()
|
public string ToLua()
|
||||||
{
|
{
|
||||||
return new List<string>
|
var profileDescr = _profile.Behaviours[_behaviourName]["description"].Evaluate(_context).ToString();
|
||||||
{
|
var header =
|
||||||
|
new List<string> {
|
||||||
|
$"name = \"{_profile.Name}.{_behaviourName}\"",
|
||||||
|
$"generationDate = \"{_lastChangeTime:s}\"",
|
||||||
|
$"description = \"{profileDescr} ({_profile.Description})\""
|
||||||
|
};
|
||||||
|
|
||||||
|
var testPrinter = new LuaTestPrinter(_skeleton,
|
||||||
|
new List<string> {"unitTestProfile2"});
|
||||||
|
var tests = testPrinter.GenerateFullTestSuite(
|
||||||
|
_behaviourTestSuite.ToList(),
|
||||||
|
new List<AspectTestSuite>(),
|
||||||
|
true);
|
||||||
|
var all = new List<string> {
|
||||||
|
header.Lined(),
|
||||||
|
"",
|
||||||
|
GenerateMainFunction(),
|
||||||
|
"",
|
||||||
|
GenerateFactorFunction(),
|
||||||
|
"",
|
||||||
|
_parameterPrinter.GenerateDefaultParameters(),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
string.Join("\n\n", _skeleton.GenerateFunctions()),
|
||||||
|
"",
|
||||||
|
string.Join("\n\n", _skeleton.GenerateDependencies()), // Should be AFTER generating the main function!
|
||||||
|
"",
|
||||||
|
string.Join("\n\n", _skeleton.GenerateConstants()),
|
||||||
|
"",
|
||||||
|
tests,
|
||||||
|
"",
|
||||||
|
|
||||||
"if (itinero == nil) then",
|
"if (itinero == nil) then",
|
||||||
" itinero = {}",
|
" itinero = {}",
|
||||||
" itinero.log = print",
|
" itinero.log = print",
|
||||||
|
@ -69,56 +100,7 @@ namespace AspectedRouting.IO.itinero2
|
||||||
"test_all()",
|
"test_all()",
|
||||||
"if (not failed_tests and not failed_profile_tests and print ~= nil) then",
|
"if (not failed_tests and not failed_profile_tests and print ~= nil) then",
|
||||||
$" print(\"Tests OK ({_profile.Name}.{_behaviourName})\")",
|
$" print(\"Tests OK ({_profile.Name}.{_behaviourName})\")",
|
||||||
"else",
|
|
||||||
" error(\"Some tests failed\")",
|
|
||||||
"end"
|
"end"
|
||||||
}.Lined();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ToLua()
|
|
||||||
{
|
|
||||||
var profileDescr = _profile.Behaviours[_behaviourName]["description"].Evaluate(_context).ToString();
|
|
||||||
var header =
|
|
||||||
new List<string>
|
|
||||||
{
|
|
||||||
$"name = \"{_profile.Name}.{_behaviourName}\"",
|
|
||||||
$"description = \"{profileDescr} ({_profile.Description})\"",
|
|
||||||
"",
|
|
||||||
"-- The hierarchy of types that this vehicle is; mostly used to check access restrictions",
|
|
||||||
"vehicle_types = " +
|
|
||||||
_skeleton.ToLua(new Constant(_profile.VehicleTyps.Select(v => new Constant(v)).ToArray()))
|
|
||||||
};
|
|
||||||
|
|
||||||
var tests = "";
|
|
||||||
if (_includeTests) {
|
|
||||||
var testPrinter = new LuaTestPrinter(_skeleton,
|
|
||||||
new List<string> { "unitTestProfile2" });
|
|
||||||
tests = testPrinter.GenerateFullTestSuite(
|
|
||||||
_behaviourTestSuite.ToList(),
|
|
||||||
new List<AspectTestSuite>(),
|
|
||||||
true) + "\n\n" + TestRunner();
|
|
||||||
}
|
|
||||||
|
|
||||||
var all = new List<string>
|
|
||||||
{
|
|
||||||
header.Lined(),
|
|
||||||
"",
|
|
||||||
GenerateMainFunction(),
|
|
||||||
"",
|
|
||||||
GenerateFactorFunction(),
|
|
||||||
"",
|
|
||||||
GenerateTurnCostFunction(),
|
|
||||||
"",
|
|
||||||
_parameterPrinter.GenerateDefaultParameters(),
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
string.Join("\n\n", _skeleton.GenerateFunctions()),
|
|
||||||
"",
|
|
||||||
string.Join("\n\n", _skeleton.GenerateDependencies()), // Should be AFTER generating the main function!
|
|
||||||
"",
|
|
||||||
string.Join("\n\n", _skeleton.GenerateConstants()),
|
|
||||||
"",
|
|
||||||
tests
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return all.Lined();
|
return all.Lined();
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# What about relations in Itinero 2.0?
|
|
||||||
|
|
||||||
Relations have moved to the preprocessor, where they do put a tag on the members of the relation. This is done with a TagsFilter
|
|
|
@ -24,12 +24,9 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.Write("Parsing " + fileName + "... ");
|
Console.WriteLine("Parsing " + fileName);
|
||||||
|
|
||||||
var aspect = doc.RootElement.ParseAspect(fileName, c);
|
return doc.RootElement.ParseAspect(fileName, c);
|
||||||
|
|
||||||
Console.WriteLine($"\rAspect {aspect.Name} has type {string.Join(",", aspect.ExpressionImplementation.Types)}");
|
|
||||||
return aspect;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -93,29 +90,16 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
filepath + " is not a valid profile; it does not contain the obligated parameter " + name);
|
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(
|
var vehicleTypes = GetTopProperty("vehicletypes").EnumerateArray().Select(
|
||||||
el => el.GetString()).ToList();
|
el => el.GetString()).ToList();
|
||||||
var metadata = GetTopProperty("metadata").EnumerateArray().Select(
|
var metadata = GetTopProperty("metadata").EnumerateArray().Select(
|
||||||
el => el.GetString()).ToList();
|
el => el.GetString()).ToList();
|
||||||
|
|
||||||
|
|
||||||
var access = ParseProfileProperty(e, contextWithParameters, "access").Finalize();
|
var access = ParseProfileProperty(e, context, "access").Finalize();
|
||||||
var oneway = ParseProfileProperty(e, contextWithParameters, "oneway").Finalize();
|
var oneway = ParseProfileProperty(e, context, "oneway").Finalize();
|
||||||
var speed = ParseProfileProperty(e, contextWithParameters, "speed").Finalize();
|
var speed = ParseProfileProperty(e, context, "speed").Finalize();
|
||||||
var scalingFactor = ParseProfileProperty(e, contextWithParameters, "scalingfactor", Funcs.Const.Apply(new Constant(1))).Finalize();
|
|
||||||
var obstacle_access = ParseProfileProperty(e, contextWithParameters, "obstacleaccess", Funcs.Const.Apply(new Constant(new Var("any"), null))).Finalize();
|
|
||||||
var obstacle_cost = ParseProfileProperty(e, contextWithParameters, "obstaclecost", Funcs.Const.Apply(new Constant(new Var("any0"), null))).Finalize();
|
|
||||||
|
|
||||||
IExpression TagsApplied(IExpression x)
|
IExpression TagsApplied(IExpression x)
|
||||||
{
|
{
|
||||||
|
@ -168,22 +152,22 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
author,
|
author,
|
||||||
filepath?.DirectoryName ?? "unknown",
|
filepath?.DirectoryName ?? "unknown",
|
||||||
vehicleTypes,
|
vehicleTypes,
|
||||||
defaultParameters,
|
e.GetProperty("defaults").ParseParameters(),
|
||||||
profiles,
|
profiles,
|
||||||
access,
|
access,
|
||||||
oneway,
|
oneway,
|
||||||
speed,
|
speed,
|
||||||
obstacle_access, obstacle_cost,
|
|
||||||
weights,
|
weights,
|
||||||
scalingFactor,
|
|
||||||
metadata,
|
metadata,
|
||||||
lastChange
|
lastChange
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly IExpression _mconst = Funcs.EitherFunc.Apply(Funcs.Id, Funcs.Const);
|
private static readonly IExpression _mconst =
|
||||||
|
new Apply(new Apply(Funcs.EitherFunc, Funcs.Id), Funcs.Const);
|
||||||
|
|
||||||
private static readonly IExpression _mappingWrapper = Funcs.EitherFunc.Apply(Funcs.Id, Funcs.StringStringToTags);
|
private static readonly IExpression _mappingWrapper =
|
||||||
|
new Apply(new Apply(Funcs.EitherFunc, Funcs.Id), Funcs.StringStringToTags);
|
||||||
|
|
||||||
private static IExpression ParseMapping(IEnumerable<JsonProperty> allArgs, Context context)
|
private static IExpression ParseMapping(IEnumerable<JsonProperty> allArgs, Context context)
|
||||||
{
|
{
|
||||||
|
@ -217,7 +201,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
{
|
{
|
||||||
var simpleMapping = new Mapping(keys, exprs);
|
var simpleMapping = new Mapping(keys, exprs);
|
||||||
|
|
||||||
var wrapped = _mappingWrapper.Apply(simpleMapping);
|
var wrapped = (IExpression) new Apply(_mappingWrapper, simpleMapping);
|
||||||
if (keys.Count == 1)
|
if (keys.Count == 1)
|
||||||
{
|
{
|
||||||
// We can interpret this directly without going through a list
|
// We can interpret this directly without going through a list
|
||||||
|
@ -264,7 +248,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
var exprs = e.EnumerateArray().Select(json =>
|
var exprs = e.EnumerateArray().Select(json =>
|
||||||
Funcs.Either(Funcs.Id, Funcs.Const, json.ParseExpression(context)))
|
Funcs.Either(Funcs.Id, Funcs.Const, json.ParseExpression(context)))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var list = new Constant(exprs);
|
var list = new Constant(exprs);
|
||||||
return Funcs.Either(Funcs.Id, Funcs.ListDot, list);
|
return Funcs.Either(Funcs.Id, Funcs.ListDot, list);
|
||||||
}
|
}
|
||||||
|
@ -311,20 +295,13 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
if (s.StartsWith("#"))
|
if (s.StartsWith("#"))
|
||||||
{
|
{
|
||||||
// This is a parameter, the type of it is free
|
// 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);
|
return new Parameter(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Constant(s);
|
return new Constant(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.ValueKind == JsonValueKind.Null)
|
if (e.ValueKind == JsonValueKind.Null) {
|
||||||
{
|
|
||||||
return new Constant(new Var("a"), null);
|
return new Constant(new Var("a"), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +355,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
|
|
||||||
|
|
||||||
foreach (var argName in func.ArgNames.GetRange(1, func.ArgNames.Count - 1))
|
foreach (var argName in func.ArgNames.GetRange(1, func.ArgNames.Count - 1))
|
||||||
// We skip the first argument, that one is already added
|
// We skip the first argument, that one is already added
|
||||||
{
|
{
|
||||||
args.Add(allExprs[argName]);
|
args.Add(allExprs[argName]);
|
||||||
}
|
}
|
||||||
|
@ -408,7 +385,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
if (!prop.Name.StartsWith("$")) continue;
|
if (!prop.Name.StartsWith("$")) continue;
|
||||||
|
|
||||||
|
|
||||||
var f = (IExpression)Funcs.BuiltinByName(prop.Name);
|
var f = (IExpression) Funcs.BuiltinByName(prop.Name);
|
||||||
if (f == null || f.Types.Count() == 0)
|
if (f == null || f.Types.Count() == 0)
|
||||||
{
|
{
|
||||||
throw new KeyNotFoundException($"The builtin function {prop.Name} was not found");
|
throw new KeyNotFoundException($"The builtin function {prop.Name} was not found");
|
||||||
|
@ -437,7 +414,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
// It gets an extra argument injected
|
// It gets an extra argument injected
|
||||||
var neededKeys = fArg.PossibleTags().Keys.ToList();
|
var neededKeys = fArg.PossibleTags().Keys.ToList();
|
||||||
var neededKeysArg = new Constant(new ListType(Typs.String), neededKeys);
|
var neededKeysArg = new Constant(new ListType(Typs.String), neededKeys);
|
||||||
f = f.Apply(new[] { neededKeysArg });
|
f = f.Apply(new[] {neededKeysArg});
|
||||||
}
|
}
|
||||||
|
|
||||||
var appliedDot = new Apply(new Apply(Funcs.Dot, f), fArg);
|
var appliedDot = new Apply(new Apply(Funcs.Dot, f), fArg);
|
||||||
|
@ -527,7 +504,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
$"filename is {filepath}, declared name is {name}");
|
$"filename is {filepath}, declared name is {name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var keys = (IEnumerable<string>)expr.PossibleTags()?.Keys ?? new List<string>();
|
var keys = (IEnumerable<string>) expr.PossibleTags()?.Keys ?? new List<string>();
|
||||||
foreach (var key in keys)
|
foreach (var key in keys)
|
||||||
{
|
{
|
||||||
if (!key.Trim().Equals(key))
|
if (!key.Trim().Equals(key))
|
||||||
|
@ -536,6 +513,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"Aspect {name} has type {string.Join(",", expr.Types)}");
|
||||||
return new AspectMetadata(
|
return new AspectMetadata(
|
||||||
expr,
|
expr,
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -1,83 +1,60 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Functions;
|
using AspectedRouting.Language.Functions;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("AspectedRouting.Test")]
|
|
||||||
namespace AspectedRouting.IO.jsonParser
|
namespace AspectedRouting.IO.jsonParser
|
||||||
{
|
{
|
||||||
public static partial class JsonParser
|
public static partial class JsonParser
|
||||||
{
|
{
|
||||||
internal static IExpression ParseProfileProperty(JsonElement e, Context c, string property, IExpression defaultExpression = null)
|
private static IExpression ParseProfileProperty(JsonElement e, Context c, string property)
|
||||||
{
|
{
|
||||||
if (!e.TryGetProperty(property, out var prop))
|
if (!e.TryGetProperty(property, out var prop)) {
|
||||||
{
|
throw new ArgumentException("Not a valid profile: the declaration expression for '" + property +
|
||||||
if (defaultExpression == null)
|
"' is missing");
|
||||||
{
|
|
||||||
throw new ArgumentException("Not a valid profile: the declaration expression for '" + property +
|
|
||||||
"' is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.Error.WriteLine("WARNING: no expression defined for " + property + ", using the default instead");
|
|
||||||
return defaultExpression;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
var expr = ParseExpression(prop, c);
|
var expr = ParseExpression(prop, c);
|
||||||
if (!expr.Types.Any())
|
if (!expr.Types.Any()) {
|
||||||
{
|
|
||||||
throw new Exception($"Could not parse field {property}, no valid typing for expression found");
|
throw new Exception($"Could not parse field {property}, no valid typing for expression found");
|
||||||
}
|
}
|
||||||
|
|
||||||
expr = expr.Optimize(out _);
|
expr = expr.Optimize();
|
||||||
expr = Funcs.Either(Funcs.Id, Funcs.Const, expr);
|
expr = Funcs.Either(Funcs.Id, Funcs.Const, expr);
|
||||||
var specialized = expr.Specialize(new Curry(Typs.Tags, new Var("a")));
|
var specialized = expr.Specialize(new Curry(Typs.Tags, new Var("a")));
|
||||||
|
|
||||||
if (specialized == null)
|
if (specialized == null) {
|
||||||
{
|
|
||||||
throw new ArgumentException("The expression for " + property +
|
throw new ArgumentException("The expression for " + property +
|
||||||
" hasn't the right type of 'Tags -> a'; it has types " +
|
" hasn't the right type of 'Tags -> a'; it has types " +
|
||||||
string.Join(",", expr.Types) + "\n" + expr.TypeBreakdown());
|
string.Join(",", expr.Types) + "\n" + expr.TypeBreakdown());
|
||||||
}
|
}
|
||||||
|
|
||||||
var pruned = specialized.PruneTypes(type =>
|
var pruned = specialized.PruneTypes(type => {
|
||||||
{
|
if (!(type is Curry c)) {
|
||||||
if (!(type is Curry c))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Equals(c.ArgType, Typs.Tags))
|
if (!Equals(c.ArgType, Typs.Tags)) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (c.ResultType is Curry)
|
if (c.ResultType is Curry) {
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c.ResultType is ListType)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (pruned.SpecializeToSmallestType().Types.Count() != 1)
|
if (pruned.SpecializeToSmallestType().Types.Count() != 1) {
|
||||||
{
|
|
||||||
throw new ArgumentException("The expression for " + property +
|
throw new ArgumentException("The expression for " + property +
|
||||||
" hasn't the right type of 'Tags -> a'; it has multiple types " +
|
" hasn't the right type of 'Tags -> a'; it has multiple types " +
|
||||||
string.Join(",", pruned.Types) + "\n" + pruned.TypeBreakdown());
|
string.Join(",", pruned.Types) + "\n" + pruned.TypeBreakdown());
|
||||||
}
|
}
|
||||||
|
|
||||||
return pruned.Optimize(out _);
|
return pruned.Optimize();
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc) {
|
||||||
{
|
|
||||||
throw new Exception("While parsing the property " + property, exc);
|
throw new Exception("While parsing the property " + property, exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,25 +62,20 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
private static Dictionary<string, IExpression> ParseParameters(this JsonElement e)
|
private static Dictionary<string, IExpression> ParseParameters(this JsonElement e)
|
||||||
{
|
{
|
||||||
var ps = new Dictionary<string, IExpression>();
|
var ps = new Dictionary<string, IExpression>();
|
||||||
foreach (var obj in e.EnumerateObject())
|
foreach (var obj in e.EnumerateObject()) {
|
||||||
{
|
|
||||||
var nm = obj.Name.TrimStart('#');
|
var nm = obj.Name.TrimStart('#');
|
||||||
if (nm == "")
|
if (nm == "") {
|
||||||
{
|
|
||||||
// This is a comment - not a parameter!
|
// This is a comment - not a parameter!
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (obj.Value.ValueKind)
|
switch (obj.Value.ValueKind) {
|
||||||
{
|
|
||||||
case JsonValueKind.String:
|
case JsonValueKind.String:
|
||||||
var v = obj.Value.ToString();
|
var v = obj.Value.ToString();
|
||||||
if (v.Equals("yes") || v.Equals("no"))
|
if (v.Equals("yes") || v.Equals("no")) {
|
||||||
{
|
|
||||||
ps[nm] = new Constant(Typs.Bool, v);
|
ps[nm] = new Constant(Typs.Bool, v);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
ps[nm] = new Constant(v);
|
ps[nm] = new Constant(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +106,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
|
|
||||||
private static string Get(this JsonElement json, string key)
|
private static string Get(this JsonElement json, string key)
|
||||||
{
|
{
|
||||||
if (json.TryGetProperty(key, out var p))
|
if (json.TryGetProperty(key, out var p)) {
|
||||||
{
|
|
||||||
return p.GetString();
|
return p.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,8 +115,7 @@ namespace AspectedRouting.IO.jsonParser
|
||||||
|
|
||||||
private static string TryGet(this JsonElement json, string key)
|
private static string TryGet(this JsonElement json, string key)
|
||||||
{
|
{
|
||||||
if (json.TryGetProperty(key, out var p))
|
if (json.TryGetProperty(key, out var p)) {
|
||||||
{
|
|
||||||
return p.GetString();
|
return p.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
--[[
|
|
||||||
|
|
||||||
|
|
||||||
Returns '0' if the turn is allowed and '-1' if the turn is forbidden.
|
|
||||||
Only used by itinero 2.0.
|
|
||||||
|
|
||||||
The itinero 2.0 profile outputs a `turn_cost_factor` which immediately calls this one (see LuaPrinter2.MainFunction).
|
|
||||||
|
|
||||||
Dependencies: str_split, containedIn
|
|
||||||
]]
|
|
||||||
function calculate_turn_cost_factor(attributes, vehicle_types)
|
|
||||||
|
|
||||||
if (attributes["type"] ~= "restriction") then
|
|
||||||
-- not a turn restriction; no cost to turn,
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, vehicle_type in pairs(vehicle_types) do
|
|
||||||
if (attributes["restriction:"..vehicle_type] ~= nil) then
|
|
||||||
-- There is a turn restriction specifically for one of our vehicle types!
|
|
||||||
return -1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (attributes["restriction"] == nil) then
|
|
||||||
-- Not a turn restriction; no cost to turn
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
if (attributes["except"] ~= nil) then
|
|
||||||
local except_types = str_split(attributes["except"],";")
|
|
||||||
for _, vehicle_type in pairs(vehicle_types) do
|
|
||||||
if (containedIn(except_types, vehicle_type)) then
|
|
||||||
-- This vehicle is exempt from this turn restriction
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return -1
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
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
|
|
|
@ -1,5 +0,0 @@
|
||||||
function create_set(list)
|
|
||||||
local set = {}
|
|
||||||
for _, l in ipairs(list) do set[l] = true end
|
|
||||||
return set
|
|
||||||
end
|
|
|
@ -14,6 +14,6 @@ function if_then_else_dotted(conditionf, thnf, elsef, arg)
|
||||||
if (condition) then
|
if (condition) then
|
||||||
return applyIfNeeded(thnf, arg)
|
return applyIfNeeded(thnf, arg)
|
||||||
else
|
else
|
||||||
return applyIfNeeded(elsef, arg) -- if no third parameter is given, 'else' will be nil
|
return applyIfNeeded(elsef, arg) -- if no third parameter is given, 'els' will be nil
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,3 +0,0 @@
|
||||||
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'
|
-- Now that we know for sure that every key matches, we add them all to the 'attributes_to_keep'
|
||||||
if (result == nil) then
|
if (result == nil) then
|
||||||
-- euhm, well, seems like we don't care about the attributes_to_keep; early return!
|
-- euhm, well, seems like we don't are about the attributes_to_keep; early return!
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
for _, key in ipairs(needed_keys) do
|
for _, key in ipairs(needed_keys) do
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
--[[
|
|
||||||
Splits a string on the specified character, e.g.
|
|
||||||
str_split("abc;def;ghi", ";") will result in a table ["abc","def","ghi"]
|
|
||||||
]]
|
|
||||||
function str_split (inputstr, sep)
|
|
||||||
if sep == nil then
|
|
||||||
sep = "%s"
|
|
||||||
end
|
|
||||||
local t={}
|
|
||||||
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
|
|
||||||
table.insert(t, str)
|
|
||||||
end
|
|
||||||
return t
|
|
||||||
end
|
|
|
@ -10,15 +10,11 @@ function table_to_list(tags, result, factor_table)
|
||||||
local f = mapping[v]
|
local f = mapping[v]
|
||||||
if (f ~= nil) then
|
if (f ~= nil) then
|
||||||
table.insert(list, f);
|
table.insert(list, f);
|
||||||
if (result.attributes_to_keep ~= nil) then
|
result.attributes_to_keep[key] = v
|
||||||
result.attributes_to_keep[key] = v
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.insert(list, mapping);
|
table.insert(list, mapping);
|
||||||
if (result.attributes_to_keep ~= nil) then
|
result.attributes_to_keep[key] = v
|
||||||
result.attributes_to_keep[key] = v
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
#! /bin/bash
|
|
||||||
|
|
||||||
echo "" > temp.lua
|
|
||||||
|
|
||||||
for f in `ls`
|
|
||||||
do
|
|
||||||
if [[ $f != "temp.lua" && $f != "test.sh" && $f != "not.lua" ]]
|
|
||||||
then
|
|
||||||
cat $f >> temp.lua
|
|
||||||
echo -e "\n\n" >> temp.lua
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
cat << TESTCODE >> temp.lua
|
|
||||||
|
|
||||||
print("------------ TESTS --------------")
|
|
||||||
|
|
||||||
function expect(expected, actual)
|
|
||||||
if (actual ~= expected) then
|
|
||||||
print("Expected "..expected.." but got "..actual)
|
|
||||||
else
|
|
||||||
print("OK")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(-1, calculate_turn_cost_factor({["type"] = "restriction", restriction = "no_left_turn"}, {}))
|
|
||||||
expect(0, calculate_turn_cost_factor({["type"] = "restriction", restriction = "no_left_turn", except="bicycle;cargo_bike"}, {"bicycle"}))
|
|
||||||
TESTCODE
|
|
||||||
|
|
||||||
lua temp.lua
|
|
|
@ -5,7 +5,8 @@ function unit_test(f, fname, index, expected, parameters, tags)
|
||||||
failed_tests = true
|
failed_tests = true
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local actual = f(tags)
|
local result = {attributes_to_keep = {}}
|
||||||
|
local actual = f(parameters, tags, result)
|
||||||
if(expected == "null" and actual == nil) then
|
if(expected == "null" and actual == nil) then
|
||||||
-- OK!
|
-- OK!
|
||||||
elseif(tonumber(actual) and tonumber(expected) and math.abs(tonumber(actual) - tonumber(expected)) < 0.1) then
|
elseif(tonumber(actual) and tonumber(expected) and math.abs(tonumber(actual) - tonumber(expected)) < 0.1) then
|
||||||
|
|
|
@ -1,245 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using AspectedRouting.Language;
|
|
||||||
using AspectedRouting.Language.Expression;
|
|
||||||
using AspectedRouting.Tests;
|
|
||||||
|
|
||||||
namespace AspectedRouting.IO.md
|
|
||||||
{
|
|
||||||
internal class MarkDownSection
|
|
||||||
{
|
|
||||||
private readonly List<string> parts = new List<string>();
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Join("\n\n", parts);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTitle(string title, int level)
|
|
||||||
{
|
|
||||||
var str = "";
|
|
||||||
for (var i = 0; i < level; i++)
|
|
||||||
{
|
|
||||||
str += "#";
|
|
||||||
}
|
|
||||||
|
|
||||||
str += " " + title;
|
|
||||||
parts.Add(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(params string[] paragraph)
|
|
||||||
{
|
|
||||||
parts.Add(string.Join("\n", paragraph));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddList(List<string> items)
|
|
||||||
{
|
|
||||||
parts.Add(string.Join("\n", items.Select(i => " - " + i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class ProfileToMD
|
|
||||||
{
|
|
||||||
private readonly string _behaviour;
|
|
||||||
private readonly Context _c;
|
|
||||||
private readonly ProfileMetaData _profile;
|
|
||||||
private readonly MarkDownSection md = new MarkDownSection();
|
|
||||||
|
|
||||||
public ProfileToMD(ProfileMetaData profile, string behaviour, Context c)
|
|
||||||
{
|
|
||||||
_profile = profile;
|
|
||||||
_behaviour = behaviour;
|
|
||||||
_c = c.WithAspectName(behaviour);
|
|
||||||
_c.DefinedFunctions["speed"] = new AspectMetadata(profile.Speed, "speed", "The speed this vehicle is going",
|
|
||||||
"", "km/h", "", true);
|
|
||||||
if (!profile.Behaviours.ContainsKey(behaviour))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Profile does not contain behaviour " + behaviour);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private decimal R(double d)
|
|
||||||
{
|
|
||||||
return Math.Round((decimal)d, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates an entry with `speed`, `priority` for the profile
|
|
||||||
*/
|
|
||||||
public string TableEntry(string msg, Dictionary<string, string> tags, ProfileResult? reference,
|
|
||||||
bool nullOnSame = false)
|
|
||||||
{
|
|
||||||
var profile = _profile.Run(_c, _behaviour, tags);
|
|
||||||
if (!reference.HasValue)
|
|
||||||
{
|
|
||||||
return "| " + msg + " | " + profile.Speed + " | " + profile.Priority + " | ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reference.Equals(profile) && nullOnSame)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "| " + msg + " | " + R(profile.Speed) + " | " +
|
|
||||||
R(profile.Speed / reference.Value.Speed) + " | " +
|
|
||||||
R(profile.Priority) + " | " + R(profile.Priority / reference.Value.Priority) + " | " +
|
|
||||||
profile.Access + " | " + profile.Oneway;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTagsTable(ProfileResult reference, Dictionary<string, HashSet<string>> usedTags)
|
|
||||||
{
|
|
||||||
var p = _profile;
|
|
||||||
var b = _profile.Behaviours[_behaviour];
|
|
||||||
|
|
||||||
var tableEntries = new List<string>();
|
|
||||||
foreach (var (key, vals) in usedTags)
|
|
||||||
{
|
|
||||||
var values = vals;
|
|
||||||
if (values.Count == 0 && key == "maxspeed")
|
|
||||||
{
|
|
||||||
tableEntries.Add($" | {key}=* (example values below)");
|
|
||||||
values = new HashSet<string> {
|
|
||||||
"20", "30", "50", "70", "90", "120", "150"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.Count == 0)
|
|
||||||
{
|
|
||||||
tableEntries.Add($" | {key}=*");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var value in values)
|
|
||||||
{
|
|
||||||
var tags = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
[key] = value
|
|
||||||
};
|
|
||||||
var entry = TableEntry($"{key}={value} ", tags, reference);
|
|
||||||
if (entry == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
tableEntries.Add(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
md.Add("| Tags | Speed (km/h) | speedfactor | Priority | priorityfactor | access | oneway | ",
|
|
||||||
"| ---- | ------------ | ----------- | -------- | --------------- | ----- | ------ |",
|
|
||||||
string.Join("\n", tableEntries));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<string, IExpression> TagsWithPriorityInfluence()
|
|
||||||
{
|
|
||||||
|
|
||||||
var p = _profile;
|
|
||||||
var parameters = _profile.ParametersFor(_behaviour);
|
|
||||||
var withInfluence = new Dictionary<string, IExpression>();
|
|
||||||
|
|
||||||
foreach (var kv in p.Priority)
|
|
||||||
{
|
|
||||||
if (parameters[kv.Key].Equals(0.0) || parameters[kv.Key].Equals(0))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
withInfluence[kv.Key] = kv.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return withInfluence;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string MainFormula()
|
|
||||||
{
|
|
||||||
var p = _profile;
|
|
||||||
var b = _profile.Behaviours[_behaviour];
|
|
||||||
|
|
||||||
var overridenParams = new HashSet<string>();
|
|
||||||
var paramValues = new Dictionary<string, object>();
|
|
||||||
foreach (var kv in p.DefaultParameters)
|
|
||||||
{
|
|
||||||
paramValues[kv.Key] = kv.Value.Evaluate(_c);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var kv in b)
|
|
||||||
{
|
|
||||||
paramValues[kv.Key] = kv.Value.Evaluate(_c);
|
|
||||||
overridenParams.Add(kv.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
var mainFormulaParts = p.Priority.Select(delegate (KeyValuePair<string, IExpression> kv)
|
|
||||||
{
|
|
||||||
var key = kv.Key;
|
|
||||||
var param = paramValues[key];
|
|
||||||
if (param.Equals(0) || param.Equals(0.0))
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overridenParams.Contains(key))
|
|
||||||
{
|
|
||||||
param = "**" + param + "**";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var called = kv.Value.DirectlyCalled();
|
|
||||||
return param + " * `" + string.Join("", called.calledFunctionNames) + "`";
|
|
||||||
});
|
|
||||||
|
|
||||||
var mainFormula = string.Join(" + ", mainFormulaParts.Where(p => p != ""));
|
|
||||||
return mainFormula;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
var p = _profile;
|
|
||||||
var b = _profile.Behaviours[_behaviour];
|
|
||||||
md.AddTitle($"[{_profile.Name}](./{_profile.Name}.md).{_behaviour}", 1);
|
|
||||||
|
|
||||||
md.Add(p.Description);
|
|
||||||
|
|
||||||
if (b.ContainsKey("description"))
|
|
||||||
{
|
|
||||||
md.Add(b["description"].Evaluate(_c).ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
md.Add("This profile is calculated as following (non-default keys are bold):", MainFormula());
|
|
||||||
|
|
||||||
var residentialTags = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
["highway"] = "residential"
|
|
||||||
};
|
|
||||||
|
|
||||||
md.Add("| Tags | Speed (km/h) | Priority",
|
|
||||||
"| ---- | ----- | ---------- | ",
|
|
||||||
TableEntry("Residential highway (reference)", residentialTags, null));
|
|
||||||
var reference = _profile.Run(_c, _behaviour, residentialTags);
|
|
||||||
md.AddTitle("Tags influencing priority", 2);
|
|
||||||
md.Add(
|
|
||||||
"Priority is what influences which road to take. The routeplanner will search a way where `1/priority` is minimal.");
|
|
||||||
addTagsTable(reference, TagsWithPriorityInfluence().Values.PossibleTagsRecursive(_c));
|
|
||||||
|
|
||||||
md.AddTitle("Tags influencing speed", 2);
|
|
||||||
md.Add(
|
|
||||||
"Speed is used to calculate how long the trip will take, but does _not_ influence which route is taken. Some profiles do use speed as a factor in priority too - in this case, these tags will be mentioned above too.");
|
|
||||||
addTagsTable(reference, _profile.Speed.PossibleTagsRecursive(_c));
|
|
||||||
|
|
||||||
md.AddTitle("Tags influencing access", 2);
|
|
||||||
md.Add("These tags influence whether or not this road can be taken with this vehicle or behaviour");
|
|
||||||
addTagsTable(reference, _profile.Access.PossibleTagsRecursive(_c));
|
|
||||||
md.AddTitle("Tags influencing oneway", 2);
|
|
||||||
md.Add("These tags influence whether or not this road can be taken in all directions or not");
|
|
||||||
addTagsTable(reference, _profile.Oneway.PossibleTagsRecursive(_c));
|
|
||||||
|
|
||||||
|
|
||||||
return md.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
Generating a good route for travellers is hard; especially for cyclists. They can be very picky and the driving style
|
Generating a good route for travellers is hard; especially for cyclists. They can be very picky and the driving style and purposes are diverse. Think about:
|
||||||
and purposes are diverse. Think about:
|
|
||||||
|
|
||||||
- A lightweight food delivery driver, who wants to be at their destination as soon as possible
|
- A lightweight food delivery driver, who wants to be at their destination as soon as possible
|
||||||
- A cargo bike, possibly with a cart or electrically supported, doing heavy delivery
|
- A cargo bike, possibly with a cart or electrically supported, doing heavy delivery
|
||||||
|
@ -11,18 +10,13 @@ and purposes are diverse. Think about:
|
||||||
- Grandma cycling along a canal on sunday afternoon
|
- Grandma cycling along a canal on sunday afternoon
|
||||||
- Someone bringing their kids to school
|
- Someone bringing their kids to school
|
||||||
|
|
||||||
It is clear that these persona's on top have very different wishes for their route. A road with a high car pressure
|
It is clear that these persona's on top have very different wishes for their route. A road with a high car pressure won't pose a problem for the food delivery, whereas grandma wouldn't even think about going there. And this is without mentioning the speed these cyclists drive, where they are allowed to drive, ...
|
||||||
won't pose a problem for the food delivery, whereas grandma wouldn't even think about going there. And this is without
|
|
||||||
mentioning the speed these cyclists drive, where they are allowed to drive, ...
|
|
||||||
|
|
||||||
Generating a cycle route for these persons is thus clearly far from simply picking the shortest possible path. On top of
|
Generating a cycle route for these persons is thus clearly far from simply picking the shortest possible path. On top of that, a consumer expects the route calculations to be both customizable and to be blazingly fast.
|
||||||
that, a consumer expects the route calculations to be both customizable and to be blazingly fast.
|
|
||||||
|
|
||||||
In order to simplify the generation of these routing profiles, this repository introduces _aspected routing_.
|
In order to simplify the generation of these routing profiles, this repository introduces _aspected routing_.
|
||||||
|
|
||||||
In _aspected routing_, one does not try to tackle the routing problem all at once, but one tries to dissassemble the
|
In _aspected routing_, one does not try to tackle the routing problem all at once, but one tries to dissassemble the preferences of the travellers into multiple, orthogonal aspects. These aspects can then be combined in a linear way, giving a fast and flexible system.
|
||||||
preferences of the travellers into multiple, orthogonal aspects. These aspects can then be combined in a linear way,
|
|
||||||
giving a fast and flexible system.
|
|
||||||
|
|
||||||
Some aspects can be:
|
Some aspects can be:
|
||||||
|
|
||||||
|
@ -44,12 +38,9 @@ Even though this repository is heavily inspired on OpenStreetMap, it can be gene
|
||||||
|
|
||||||
## Road network assumptions
|
## Road network assumptions
|
||||||
|
|
||||||
The only assumptions made are that roads have a **length** and a collection of **tags**, this is a dictionary mapping
|
The only assumptions made are that roads have a **length** and a collection of **tags**, this is a dictionary mapping strings onto strings. These tags encode the properties of the road (e.g. road classification, name, surface, ...)
|
||||||
strings onto strings. These tags encode the properties of the road (e.g. road classification, name, surface, ...)
|
|
||||||
|
|
||||||
OpenStreetMap also has a concept of **relations**. A special function is available for that. However, in a preprocessing
|
OpenStreetMap also has a concept of **relations**. A special function is available for that. However, in a preprocessing step, the relations that a road is a member of, are converted into tags on every way with a `_network:i:key=value` format, where `i` is the number of the relation, and `key`=`value` is a tag present on the relation.
|
||||||
step, the relations that a road is a member of, are converted into tags on every way with a `_network:i:key=value`
|
|
||||||
format, where `i` is the number of the relation, and `key`=`value` is a tag present on the relation.
|
|
||||||
|
|
||||||
## Describing an aspect
|
## Describing an aspect
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
- string
|
- string
|
||||||
- tags
|
- tags
|
||||||
- bool
|
- bool
|
||||||
|
|
||||||
## Builtin functions
|
## Builtin functions
|
||||||
|
|
||||||
- eq
|
- eq
|
||||||
|
@ -38,6 +37,7 @@
|
||||||
- eitherFunc
|
- eitherFunc
|
||||||
- stringToTags
|
- stringToTags
|
||||||
|
|
||||||
|
|
||||||
### Function overview
|
### Function overview
|
||||||
|
|
||||||
#### eq
|
#### eq
|
||||||
|
@ -49,6 +49,8 @@ $a | $a | string |
|
||||||
|
|
||||||
Returns 'yes' if both values _are_ the same
|
Returns 'yes' if both values _are_ the same
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -62,6 +64,7 @@ end
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### notEq
|
#### notEq
|
||||||
|
|
||||||
a | b | returns |
|
a | b | returns |
|
||||||
|
@ -72,6 +75,8 @@ bool | bool |
|
||||||
|
|
||||||
OVerloaded function, either boolean not or returns 'yes' if the two passed in values are _not_ the same;
|
OVerloaded function, either boolean not or returns 'yes' if the two passed in values are _not_ the same;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -88,6 +93,7 @@ function notEq(a, b)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### not
|
#### not
|
||||||
|
|
||||||
a | b | returns |
|
a | b | returns |
|
||||||
|
@ -98,6 +104,8 @@ bool | bool |
|
||||||
|
|
||||||
OVerloaded function, either boolean not or returns 'yes' if the two passed in values are _not_ the same;
|
OVerloaded function, either boolean not or returns 'yes' if the two passed in values are _not_ the same;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -114,6 +122,7 @@ function notEq(a, b)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### inv
|
#### inv
|
||||||
|
|
||||||
d | returns |
|
d | returns |
|
||||||
|
@ -123,6 +132,8 @@ double | double |
|
||||||
|
|
||||||
Calculates `1/d`
|
Calculates `1/d`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -131,6 +142,7 @@ function inv(n)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### default
|
#### default
|
||||||
|
|
||||||
defaultValue | f | returns |
|
defaultValue | f | returns |
|
||||||
|
@ -139,6 +151,8 @@ $a | $b -> $a | $b | $a |
|
||||||
|
|
||||||
Calculates function `f` for the given argument. If the result is `null`, the default value is returned instead
|
Calculates function `f` for the given argument. If the result is `null`, the default value is returned instead
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -150,6 +164,7 @@ function default(defaultValue, realValue)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### parse
|
#### parse
|
||||||
|
|
||||||
s | returns |
|
s | returns |
|
||||||
|
@ -159,6 +174,8 @@ string | pdouble |
|
||||||
|
|
||||||
Parses a string into a numerical value
|
Parses a string into a numerical value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -191,6 +208,7 @@ function parse(string)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### to_string
|
#### to_string
|
||||||
|
|
||||||
obj | returns |
|
obj | returns |
|
||||||
|
@ -199,6 +217,8 @@ $a | string |
|
||||||
|
|
||||||
Converts a value into a human readable string
|
Converts a value into a human readable string
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -207,6 +227,7 @@ function to_string(o)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### concat
|
#### concat
|
||||||
|
|
||||||
a | b | returns |
|
a | b | returns |
|
||||||
|
@ -215,6 +236,8 @@ string | string | string |
|
||||||
|
|
||||||
Concatenates two strings
|
Concatenates two strings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -223,6 +246,7 @@ function concat(a, b)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### containedIn
|
#### containedIn
|
||||||
|
|
||||||
list | a | returns |
|
list | a | returns |
|
||||||
|
@ -231,6 +255,8 @@ list ($a) | $a | bool |
|
||||||
|
|
||||||
Given a list of values, checks if the argument is contained in the list.
|
Given a list of values, checks if the argument is contained in the list.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -245,6 +271,7 @@ function containedIn(list, a)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### min
|
#### min
|
||||||
|
|
||||||
list | returns |
|
list | returns |
|
||||||
|
@ -257,6 +284,8 @@ list (bool) | bool |
|
||||||
|
|
||||||
Out of a list of values, gets the smallest value. IN case of a list of bools, this acts as `and`
|
Out of a list of values, gets the smallest value. IN case of a list of bools, this acts as `and`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -274,6 +303,7 @@ function min(list)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### and
|
#### and
|
||||||
|
|
||||||
list | returns |
|
list | returns |
|
||||||
|
@ -286,6 +316,8 @@ list (bool) | bool |
|
||||||
|
|
||||||
Out of a list of values, gets the smallest value. IN case of a list of bools, this acts as `and`
|
Out of a list of values, gets the smallest value. IN case of a list of bools, this acts as `and`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -303,6 +335,7 @@ function min(list)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### max
|
#### max
|
||||||
|
|
||||||
list | returns |
|
list | returns |
|
||||||
|
@ -315,6 +348,8 @@ list (bool) | bool |
|
||||||
|
|
||||||
Returns the biggest value in the list. For a list of booleans, this acts as 'or'
|
Returns the biggest value in the list. For a list of booleans, this acts as 'or'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -332,6 +367,7 @@ function max(list)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### or
|
#### or
|
||||||
|
|
||||||
list | returns |
|
list | returns |
|
||||||
|
@ -344,6 +380,8 @@ list (bool) | bool |
|
||||||
|
|
||||||
Returns the biggest value in the list. For a list of booleans, this acts as 'or'
|
Returns the biggest value in the list. For a list of booleans, this acts as 'or'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -361,6 +399,7 @@ function max(list)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### sum
|
#### sum
|
||||||
|
|
||||||
list | returns |
|
list | returns |
|
||||||
|
@ -373,6 +412,8 @@ list (bool) | int |
|
||||||
|
|
||||||
Sums all the numbers in the given list. If the list contains bool, `yes` or `true` will be considered to equal `1`
|
Sums all the numbers in the given list. If the list contains bool, `yes` or `true` will be considered to equal `1`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -388,6 +429,7 @@ function sum(list)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### multiply
|
#### multiply
|
||||||
|
|
||||||
list | returns |
|
list | returns |
|
||||||
|
@ -400,6 +442,8 @@ list (bool) | bool |
|
||||||
|
|
||||||
Multiplies all the values in a given list. On a list of booleans, this acts as 'and' or 'all'
|
Multiplies all the values in a given list. On a list of booleans, this acts as 'and' or 'all'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -412,6 +456,7 @@ function multiply(list)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### firstMatchOf
|
#### firstMatchOf
|
||||||
|
|
||||||
s | returns |
|
s | returns |
|
||||||
|
@ -420,6 +465,8 @@ list (string) | tags -> list ($a) | tags | $a |
|
||||||
|
|
||||||
Parses a string into a numerical value
|
Parses a string into a numerical value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -445,15 +492,18 @@ function first_match_of(tags, result, order_of_keys, table)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### mustMatch
|
#### mustMatch
|
||||||
|
|
||||||
neededKeys (filled in by parser) | f | returns |
|
neededKeys (filled in by parser) | f | returns |
|
||||||
--- | --- | --- |
|
--- | --- | --- |
|
||||||
list (string) | tags -> list (bool) | tags | bool |
|
list (string) | tags -> list (bool) | tags | bool |
|
||||||
|
|
||||||
Every key that is used in the subfunction must be present. If, on top, a value is present with a mapping, every
|
Every key that is used in the subfunction must be present.
|
||||||
key/value will be executed and must return a value that is not 'no' or 'false' Note that this is a privileged builtin
|
If, on top, a value is present with a mapping, every key/value will be executed and must return a value that is not 'no' or 'false'
|
||||||
function, as the parser will automatically inject the keys used in the called function.
|
Note that this is a privileged builtin function, as the parser will automatically inject the keys used in the called function.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
|
@ -522,6 +572,7 @@ function must_match(tags, result, needed_keys, table)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### memberOf
|
#### memberOf
|
||||||
|
|
||||||
f | tags | returns |
|
f | tags | returns |
|
||||||
|
@ -535,18 +586,15 @@ In order to use this for itinero 1.0, the membership _must_ be the top level exp
|
||||||
Conceptually, when the aspect is executed for a way, every relation will be used as argument in the subfunction `f`
|
Conceptually, when the aspect is executed for a way, every relation will be used as argument in the subfunction `f`
|
||||||
If this subfunction returns 'true', the entire aspect will return true.
|
If this subfunction returns 'true', the entire aspect will return true.
|
||||||
|
|
||||||
In the lua implementation for itinero 1.0, this is implemented slightly different: a
|
In the lua implementation for itinero 1.0, this is implemented slightly different: a flag `_relation:<aspect_name>="yes"` will be set if the aspect matches on every way for where this aspect matches.
|
||||||
flag `_relation:<aspect_name>="yes"` will be set if the aspect matches on every way for where this aspect matches.
|
However, this plays poorly with parameters (e.g.: what if we want to cycle over a highway which is part of a certain cycling network with a certain `#network_name`?) Luckily, parameters can only be simple values. To work around this problem, an extra tag is introduced for _every single profile_:`_relation:<profile_name>:<aspect_name>=yes'. The subfunction is thus executed `countOr(relations) * countOf(profiles)` time, yielding `countOf(profiles)` tags. The profile function then picks the tags for himself and strips the `<profile_name>:` away from the key.
|
||||||
However, this plays poorly with parameters (e.g.: what if we want to cycle over a highway which is part of a certain
|
|
||||||
cycling network with a certain `#network_name`?) Luckily, parameters can only be simple values. To work around this
|
|
||||||
problem, an extra tag is introduced for _every single
|
|
||||||
profile_:`_relation:<profile_name>:<aspect_name>=yes'. The subfunction is thus executed `countOr(relations) * countOf(
|
|
||||||
profiles)` time, yielding `countOf(
|
|
||||||
profiles)` tags. The profile function then picks the tags for himself and strips the `<profile_name>:` away from the
|
|
||||||
key.
|
|
||||||
|
|
||||||
In the test.csv, one can simply use `_relation:<aspect_name>=yes` to mimic relations in your tests
|
In the test.csv, one can simply use `_relation:<aspect_name>=yes` to mimic relations in your tests
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -562,6 +610,7 @@ function member_of(calledIn, parameters, tags, result)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### if_then_else
|
#### if_then_else
|
||||||
|
|
||||||
condition | then | else | returns |
|
condition | then | else | returns |
|
||||||
|
@ -569,8 +618,9 @@ condition | then | else | returns |
|
||||||
bool | $a | $a | $a |
|
bool | $a | $a | $a |
|
||||||
bool | $a | $a |
|
bool | $a | $a |
|
||||||
|
|
||||||
Selects either one of the branches, depending on the condition.If the `else` branch is not set, `null` is returned in
|
Selects either one of the branches, depending on the condition.If the `else` branch is not set, `null` is returned in the condition is false.
|
||||||
the condition is false.
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
|
@ -584,6 +634,7 @@ function if_then_else(condition, thn, els)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### if
|
#### if
|
||||||
|
|
||||||
condition | then | else | returns |
|
condition | then | else | returns |
|
||||||
|
@ -591,8 +642,9 @@ condition | then | else | returns |
|
||||||
bool | $a | $a | $a |
|
bool | $a | $a | $a |
|
||||||
bool | $a | $a |
|
bool | $a | $a |
|
||||||
|
|
||||||
Selects either one of the branches, depending on the condition.If the `else` branch is not set, `null` is returned in
|
Selects either one of the branches, depending on the condition.If the `else` branch is not set, `null` is returned in the condition is false.
|
||||||
the condition is false.
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
|
@ -606,6 +658,7 @@ function if_then_else(condition, thn, els)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### id
|
#### id
|
||||||
|
|
||||||
a | returns |
|
a | returns |
|
||||||
|
@ -614,6 +667,8 @@ $a | $a |
|
||||||
|
|
||||||
Returns the argument unchanged - the identity function. Seems useless at first sight, but useful in parsing
|
Returns the argument unchanged - the identity function. Seems useless at first sight, but useful in parsing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -622,6 +677,7 @@ function id(v)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### const
|
#### const
|
||||||
|
|
||||||
a | b | returns |
|
a | b | returns |
|
||||||
|
@ -630,6 +686,8 @@ $a | $b | $a |
|
||||||
|
|
||||||
Small utility function, which takes two arguments `a` and `b` and returns `a`. Used extensively to insert freedom
|
Small utility function, which takes two arguments `a` and `b` and returns `a`. Used extensively to insert freedom
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
@ -638,6 +696,7 @@ function const(a, b)
|
||||||
end
|
end
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### constRight
|
#### constRight
|
||||||
|
|
||||||
a | b | returns |
|
a | b | returns |
|
||||||
|
@ -646,20 +705,24 @@ $a | $b | $b |
|
||||||
|
|
||||||
Small utility function, which takes two arguments `a` and `b` and returns `b`. Used extensively to insert freedom
|
Small utility function, which takes two arguments `a` and `b` and returns `b`. Used extensively to insert freedom
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### dot
|
#### dot
|
||||||
|
|
||||||
f | g | a | returns |
|
f | g | a | returns |
|
||||||
--- | --- | --- | --- |
|
--- | --- | --- | --- |
|
||||||
$b -> $c | $a -> $b | $a | $c |
|
$b -> $c | $a -> $b | $a | $c |
|
||||||
|
|
||||||
Higher order function: converts `f (g a)` into `(dot f g) a`. In other words, this fuses `f` and `g` in a new function,
|
Higher order function: converts `f (g a)` into `(dot f g) a`. In other words, this fuses `f` and `g` in a new function, which allows the argument to be lifted out of the expression
|
||||||
which allows the argument to be lifted out of the expression
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
|
@ -667,14 +730,16 @@ Lua implementation:
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### listDot
|
#### listDot
|
||||||
|
|
||||||
list | a | returns |
|
list | a | returns |
|
||||||
--- | --- | --- |
|
--- | --- | --- |
|
||||||
list ($a -> $b) | $a | list ($b) |
|
list ($a -> $b) | $a | list ($b) |
|
||||||
|
|
||||||
Listdot takes a list of functions `[f, g, h]` and and an argument `a`. It applies the argument on every single
|
Listdot takes a list of functions `[f, g, h]` and and an argument `a`. It applies the argument on every single function.It conveniently lifts the argument out of the list.
|
||||||
function.It conveniently lifts the argument out of the list.
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
|
@ -683,6 +748,7 @@ Lua implementation:
|
||||||
-- listDot
|
-- listDot
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### eitherFunc
|
#### eitherFunc
|
||||||
|
|
||||||
f | g | a | returns |
|
f | g | a | returns |
|
||||||
|
@ -690,24 +756,21 @@ f | g | a | returns |
|
||||||
$a -> $b | $c -> $d | $a | $b |
|
$a -> $b | $c -> $d | $a | $b |
|
||||||
$a -> $b | $c -> $d | $c | $d |
|
$a -> $b | $c -> $d | $c | $d |
|
||||||
|
|
||||||
EitherFunc is a small utility function, mostly used in the parser. It allows the compiler to choose a function, based on
|
EitherFunc is a small utility function, mostly used in the parser. It allows the compiler to choose a function, based on the types.
|
||||||
the types.
|
|
||||||
|
|
||||||
Consider the mapping `{'someKey':'someValue'}`. Under normal circumstances, this acts as a pointwise-function,
|
Consider the mapping `{'someKey':'someValue'}`. Under normal circumstances, this acts as a pointwise-function, converting the string `someKey` into `someValue`, just like an ordinary dictionary would do. However, in the context of `mustMatch`, we would prefer this to act as a _check_, that the highway _has_ a key `someKey` which is `someValue`, thus acting as `{'someKey': {'$eq':'someValue'}}. Both behaviours are automatically supported in parsing, by parsing the string as `(eitherFunc id eq) 'someValue'`. The type system is then able to figure out which implementation is needed.
|
||||||
converting the string `someKey` into `someValue`, just like an ordinary dictionary would do. However, in the context
|
|
||||||
of `mustMatch`, we would prefer this to act as a _check_, that the highway _has_ a key `someKey` which is `someValue`,
|
|
||||||
thus acting
|
|
||||||
as `{'someKey': {'$eq':'someValue'}}`. Both behaviours are automatically supported in parsing, by parsing the string as `(
|
|
||||||
eitherFunc id eq) 'someValue'`. The type system is then able to figure out which implementation is needed.
|
|
||||||
|
|
||||||
Disclaimer: _you should never ever need this in your profiles_
|
Disclaimer: _you should never ever need this in your profiles_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
|
|
||||||
#### stringToTags
|
#### stringToTags
|
||||||
|
|
||||||
f | tags | returns |
|
f | tags | returns |
|
||||||
|
@ -716,6 +779,8 @@ string -> string -> $a | tags | list ($a) |
|
||||||
|
|
||||||
stringToTags converts a function `string -> string -> a` into a function `tags -> [a]`
|
stringToTags converts a function `string -> string -> a` into a function `tags -> [a]`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Lua implementation:
|
Lua implementation:
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace AspectedRouting.Language
|
||||||
{
|
{
|
||||||
public static class Analysis
|
public static class Analysis
|
||||||
{
|
{
|
||||||
|
|
||||||
public static Dictionary<string, (List<Type> Types, string inFunction)> UsedParameters(
|
public static Dictionary<string, (List<Type> Types, string inFunction)> UsedParameters(
|
||||||
this ProfileMetaData profile, Context context)
|
this ProfileMetaData profile, Context context)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +32,7 @@ namespace AspectedRouting.Language
|
||||||
param.ParamName + " is used\n" +
|
param.ParamName + " is used\n" +
|
||||||
$" in {oldUsage} as {string.Join(",", types)}\n" +
|
$" in {oldUsage} as {string.Join(",", types)}\n" +
|
||||||
$" in {inFunction} as {string.Join(",", param.Types)}\n" +
|
$" in {inFunction} as {string.Join(",", param.Types)}\n" +
|
||||||
"which can not be unified");
|
$"which can not be unified");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -45,8 +46,6 @@ namespace AspectedRouting.Language
|
||||||
AddParams(profile.Access, "profile definition for " + profile.Name + ".access");
|
AddParams(profile.Access, "profile definition for " + profile.Name + ".access");
|
||||||
AddParams(profile.Oneway, "profile definition for " + profile.Name + ".oneway");
|
AddParams(profile.Oneway, "profile definition for " + profile.Name + ".oneway");
|
||||||
AddParams(profile.Speed, "profile definition for " + profile.Name + ".speed");
|
AddParams(profile.Speed, "profile definition for " + profile.Name + ".speed");
|
||||||
AddParams(profile.ObstacleAccess, "profile definition for " + profile.Name + ".obstacleaccess");
|
|
||||||
AddParams(profile.ObstacleCost, "profile definition for " + profile.Name + ".obstaclecost");
|
|
||||||
|
|
||||||
foreach (var (key, expr) in profile.Priority)
|
foreach (var (key, expr) in profile.Priority)
|
||||||
{
|
{
|
||||||
|
@ -158,7 +157,7 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
foreach (var fName in toCheck)
|
foreach (var fName in toCheck)
|
||||||
{
|
{
|
||||||
queue.Enqueue(ctx.GetFunction(fName));
|
queue.Enqueue(ctx.GetFunction(fName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +166,7 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates an overview of the dependencies of the expression, both which parameters it needs and what other
|
/// Generates an overview of the dependencies of the expression, both which parameters it needs and what other functions (builtin or defined) it needs.
|
||||||
/// functions (builtin or defined) it needs.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="expr"></param>
|
/// <param name="expr"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
@ -199,7 +197,8 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
public static string TypeBreakdown(this IExpression e)
|
public static string TypeBreakdown(this IExpression e)
|
||||||
{
|
{
|
||||||
return e + " : " + string.Join(" ; ", e.Types);
|
|
||||||
|
return e.ToString() + " : "+string.Join(" ; ", e.Types);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SanityCheckProfile(this ProfileMetaData pmd, Context context)
|
public static void SanityCheckProfile(this ProfileMetaData pmd, Context context)
|
||||||
|
@ -235,7 +234,7 @@ namespace AspectedRouting.Language
|
||||||
if (unused.Any())
|
if (unused.Any())
|
||||||
{
|
{
|
||||||
Console.WriteLine("[WARNING] A default value is set for parameter, but it is unused: " +
|
Console.WriteLine("[WARNING] A default value is set for parameter, but it is unused: " +
|
||||||
string.Join(", ", unused));
|
string.Join(", ", unused));
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramsUsedInBehaviour = new HashSet<string>();
|
var paramsUsedInBehaviour = new HashSet<string>();
|
||||||
|
@ -286,7 +285,6 @@ namespace AspectedRouting.Language
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"[{pmd.Name}] WARNING: Some parameters only have a default value: {string.Join(", ", defaultOnly)}");
|
$"[{pmd.Name}] WARNING: Some parameters only have a default value: {string.Join(", ", defaultOnly)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SanityCheck(this IExpression e)
|
public static void SanityCheck(this IExpression e)
|
||||||
|
@ -296,19 +294,19 @@ namespace AspectedRouting.Language
|
||||||
var order = new List<IExpression>();
|
var order = new List<IExpression>();
|
||||||
var mapping = new List<IExpression>();
|
var mapping = new List<IExpression>();
|
||||||
if (Deconstruct.UnApply(
|
if (Deconstruct.UnApply(
|
||||||
Deconstruct.UnApply(Deconstruct.IsFunc(Funcs.FirstOf), Deconstruct.Assign(order)),
|
Deconstruct.UnApply(Deconstruct.IsFunc(Funcs.FirstOf), Deconstruct.Assign(order)),
|
||||||
Deconstruct.Assign(mapping)
|
Deconstruct.Assign(mapping)
|
||||||
).Invoke(expr))
|
).Invoke(expr))
|
||||||
{
|
{
|
||||||
var expectedKeys = ((IEnumerable<object>)order.First().Evaluate(null)).Select(o =>
|
var expectedKeys = ((IEnumerable<object>) order.First().Evaluate(null)).Select(o =>
|
||||||
{
|
|
||||||
if (o is IExpression x)
|
|
||||||
{
|
{
|
||||||
return (string)x.Evaluate(null);
|
if (o is IExpression x)
|
||||||
}
|
{
|
||||||
|
return (string) x.Evaluate(null);
|
||||||
|
}
|
||||||
|
|
||||||
return (string)o;
|
return (string) o;
|
||||||
})
|
})
|
||||||
.ToHashSet();
|
.ToHashSet();
|
||||||
var actualKeys = mapping.First().PossibleTags().Keys;
|
var actualKeys = mapping.First().PossibleTags().Keys;
|
||||||
var missingInOrder = actualKeys.Where(key => !expectedKeys.Contains(key)).ToList();
|
var missingInOrder = actualKeys.Where(key => !expectedKeys.Contains(key)).ToList();
|
||||||
|
@ -340,12 +338,6 @@ namespace AspectedRouting.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all possible tags which are used in the given expression.
|
|
||||||
*
|
|
||||||
* If a tag might match a wildcard, an explicit '*' will be added to the collection.
|
|
||||||
* This is different from the _other_ possibleTags, which will return an empty set.
|
|
||||||
*/
|
|
||||||
public static Dictionary<string, HashSet<string>> PossibleTags(this IEnumerable<IExpression> exprs)
|
public static Dictionary<string, HashSet<string>> PossibleTags(this IEnumerable<IExpression> exprs)
|
||||||
{
|
{
|
||||||
var usedTags = new Dictionary<string, HashSet<string>>();
|
var usedTags = new Dictionary<string, HashSet<string>>();
|
||||||
|
@ -361,7 +353,6 @@ namespace AspectedRouting.Language
|
||||||
{
|
{
|
||||||
if (!usedTags.TryGetValue(key, out var collection))
|
if (!usedTags.TryGetValue(key, out var collection))
|
||||||
{
|
{
|
||||||
// This is the first time we see this collection
|
|
||||||
collection = new HashSet<string>();
|
collection = new HashSet<string>();
|
||||||
usedTags[key] = collection;
|
usedTags[key] = collection;
|
||||||
}
|
}
|
||||||
|
@ -370,85 +361,15 @@ namespace AspectedRouting.Language
|
||||||
{
|
{
|
||||||
collection.Add(v);
|
collection.Add(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (values.Count == 0)
|
|
||||||
{
|
|
||||||
collection.Add("*");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return usedTags;
|
return usedTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dictionary<string, HashSet<string>> PossibleTagsRecursive(this IEnumerable<IExpression> exprs, Context c)
|
|
||||||
{
|
|
||||||
var usedTags = new Dictionary<string, HashSet<string>>();
|
|
||||||
foreach (var e in exprs)
|
|
||||||
{
|
|
||||||
var possibleTags = e.PossibleTagsRecursive(c);
|
|
||||||
|
|
||||||
if (possibleTags != null)
|
|
||||||
{
|
|
||||||
foreach (var tag in possibleTags)
|
|
||||||
{
|
|
||||||
usedTags[tag.Key] = tag.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return usedTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dictionary<string, HashSet<string>> PossibleTagsRecursive(this IExpression e, Context c)
|
|
||||||
{
|
|
||||||
var allExpr = new List<IExpression>();
|
|
||||||
var queue = new Queue<IExpression>();
|
|
||||||
queue.Enqueue(e);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
var next = queue.Dequeue();
|
|
||||||
allExpr.Add(next);
|
|
||||||
next.Visit(expression =>
|
|
||||||
{
|
|
||||||
if (expression is FunctionCall fc)
|
|
||||||
{
|
|
||||||
var called = c.GetFunction(fc.CalledFunctionName);
|
|
||||||
queue.Enqueue(called);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
} while (queue.Any());
|
|
||||||
|
|
||||||
var result = new Dictionary<string, HashSet<string>>();
|
|
||||||
|
|
||||||
foreach (var expression in allExpr)
|
|
||||||
{
|
|
||||||
var subTags = expression.PossibleTags();
|
|
||||||
if (subTags == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var kv in subTags)
|
|
||||||
{
|
|
||||||
if (!result.ContainsKey(kv.Key))
|
|
||||||
{
|
|
||||||
result[kv.Key] = new HashSet<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var val in kv.Value)
|
|
||||||
{
|
|
||||||
result[kv.Key].Add(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns which tags are used in this calculation
|
/// Returns which tags are used in this calculation
|
||||||
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
/// <returns>A dictionary containing all possible values. An entry with an empty list indicates a wildcard</returns>
|
/// <returns>A dictionary containing all possible values. An entry with an empty list indicates a wildcard</returns>
|
||||||
|
@ -522,8 +443,8 @@ namespace AspectedRouting.Language
|
||||||
{
|
{
|
||||||
var mapping = new List<IExpression>();
|
var mapping = new List<IExpression>();
|
||||||
if (Deconstruct.UnApply(Deconstruct.IsFunc(Funcs.MemberOf),
|
if (Deconstruct.UnApply(Deconstruct.IsFunc(Funcs.MemberOf),
|
||||||
Deconstruct.Assign(mapping)
|
Deconstruct.Assign(mapping)
|
||||||
).Invoke(f))
|
).Invoke(f))
|
||||||
{
|
{
|
||||||
memberships.Add(calledIn, mapping.First());
|
memberships.Add(calledIn, mapping.First());
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -34,11 +34,6 @@ namespace AspectedRouting.Language
|
||||||
Parameters.Add(name, new Constant(value));
|
Parameters.Add(name, new Constant(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddParameter(string name, IExpression value)
|
|
||||||
{
|
|
||||||
Parameters.Add(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddFunction(string name, AspectMetadata function)
|
public void AddFunction(string name, AspectMetadata function)
|
||||||
{
|
{
|
||||||
if (Funcs.Builtins.ContainsKey(name))
|
if (Funcs.Builtins.ContainsKey(name))
|
||||||
|
|
|
@ -17,8 +17,7 @@ namespace AspectedRouting.Language
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static (IExpression f, List<IExpression> args)? DeconstructApply(this IExpression e)
|
public static (IExpression f, List<IExpression> args)? DeconstructApply(this IExpression e)
|
||||||
{
|
{
|
||||||
if (!(e is Apply _))
|
if (!(e is Apply _)) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +25,7 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
var fs = new List<IExpression>();
|
var fs = new List<IExpression>();
|
||||||
|
|
||||||
while (UnApply(Assign(fs), Assign(argss)).Invoke(e))
|
while (UnApply(Assign(fs), Assign(argss)).Invoke(e)) {
|
||||||
{
|
|
||||||
e = fs.First();
|
e = fs.First();
|
||||||
fs.Clear();
|
fs.Clear();
|
||||||
}
|
}
|
||||||
|
@ -39,10 +37,8 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
public static Func<IExpression, bool> IsMapping(List<Mapping> collect)
|
public static Func<IExpression, bool> IsMapping(List<Mapping> collect)
|
||||||
{
|
{
|
||||||
return e =>
|
return e => {
|
||||||
{
|
if (e is Mapping m) {
|
||||||
if (e is Mapping m)
|
|
||||||
{
|
|
||||||
collect.Add(m);
|
collect.Add(m);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -51,24 +47,10 @@ 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)
|
public static Func<IExpression, bool> Assign(List<IExpression> collect)
|
||||||
{
|
{
|
||||||
return e =>
|
return e => {
|
||||||
{
|
|
||||||
collect.Add(e);
|
collect.Add(e);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -76,10 +58,8 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
public static Func<IExpression, bool> IsFunc(Function f)
|
public static Func<IExpression, bool> IsFunc(Function f)
|
||||||
{
|
{
|
||||||
return e =>
|
return e => {
|
||||||
{
|
if (!(e is Function fe)) {
|
||||||
if (!(e is Function fe))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,21 +67,6 @@ namespace AspectedRouting.Language
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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(
|
public static Func<IExpression, bool> UnApplyAny(
|
||||||
Func<IExpression, bool> matchFunc,
|
Func<IExpression, bool> matchFunc,
|
||||||
Func<IExpression, bool> matchArg)
|
Func<IExpression, bool> matchArg)
|
||||||
|
@ -114,28 +79,21 @@ namespace AspectedRouting.Language
|
||||||
Func<IExpression, bool> matchArg,
|
Func<IExpression, bool> matchArg,
|
||||||
bool matchAny = false)
|
bool matchAny = false)
|
||||||
{
|
{
|
||||||
return e =>
|
return e => {
|
||||||
{
|
if (!(e is Apply apply)) {
|
||||||
if (!(e is Apply apply))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (_, (f, a)) in apply.FunctionApplications)
|
foreach (var (_, (f, a)) in apply.FunctionApplications) {
|
||||||
{
|
|
||||||
var doesMatch = matchFunc.Invoke(f) && matchArg.Invoke(a);
|
var doesMatch = matchFunc.Invoke(f) && matchArg.Invoke(a);
|
||||||
if (matchAny)
|
if (matchAny) {
|
||||||
{
|
if (doesMatch) {
|
||||||
if (doesMatch)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if (!doesMatch) {
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ namespace AspectedRouting.Language.Expression
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Dictionary<Type, (IExpression f, IExpression a)> FunctionApplications;
|
public readonly Dictionary<Type, (IExpression f, IExpression a)> FunctionApplications;
|
||||||
|
|
||||||
private IExpression optimizedForm = null;
|
|
||||||
|
|
||||||
private Apply(string debugInfo, Dictionary<Type, (IExpression f, IExpression a)> argument)
|
private Apply(string debugInfo, Dictionary<Type, (IExpression f, IExpression a)> argument)
|
||||||
{
|
{
|
||||||
_debugInfo = debugInfo;
|
_debugInfo = debugInfo;
|
||||||
|
@ -29,18 +27,15 @@ namespace AspectedRouting.Language.Expression
|
||||||
|
|
||||||
public Apply(IExpression f, IExpression argument)
|
public Apply(IExpression f, IExpression argument)
|
||||||
{
|
{
|
||||||
if (f == null || argument == null)
|
if (f == null || argument == null) {
|
||||||
{
|
|
||||||
throw new NullReferenceException();
|
throw new NullReferenceException();
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionApplications = new Dictionary<Type, (IExpression f, IExpression a)>();
|
FunctionApplications = new Dictionary<Type, (IExpression f, IExpression a)>();
|
||||||
|
|
||||||
var typesCleaned = argument.Types.RenameVars(f.Types).ToList();
|
var typesCleaned = argument.Types.RenameVars(f.Types).ToList();
|
||||||
foreach (var funcType in f.Types)
|
foreach (var funcType in f.Types) {
|
||||||
{
|
if (!(funcType is Curry c)) {
|
||||||
if (!(funcType is Curry c))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,12 +43,10 @@ namespace AspectedRouting.Language.Expression
|
||||||
var expectedResultType = c.ResultType;
|
var expectedResultType = c.ResultType;
|
||||||
|
|
||||||
|
|
||||||
foreach (var argType in typesCleaned)
|
foreach (var argType in typesCleaned) {
|
||||||
{
|
|
||||||
// we try to unify the argType with the expected type
|
// we try to unify the argType with the expected type
|
||||||
var substitutions = expectedArgType.UnificationTable(argType);
|
var substitutions = expectedArgType.UnificationTable(argType);
|
||||||
if (substitutions == null)
|
if (substitutions == null) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,30 +56,25 @@ namespace AspectedRouting.Language.Expression
|
||||||
var actualFunction = f.Specialize(new Curry(actualArgType, actualResultType));
|
var actualFunction = f.Specialize(new Curry(actualArgType, actualResultType));
|
||||||
var actualArgument = argument.Specialize(actualArgType);
|
var actualArgument = argument.Specialize(actualArgType);
|
||||||
|
|
||||||
if (actualFunction == null || actualArgument == null)
|
if (actualFunction == null || actualArgument == null) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FunctionApplications.ContainsKey(actualResultType)) {
|
||||||
if (FunctionApplications.ContainsKey(actualResultType))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionApplications.Add(actualResultType, (actualFunction, actualArgument));
|
FunctionApplications.Add(actualResultType, (actualFunction, actualArgument));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FunctionApplications.Any())
|
if (!FunctionApplications.Any()) {
|
||||||
{
|
try {
|
||||||
try
|
_debugInfo = $"\n{f.Optimize().TypeBreakdown().Indent()}\n" +
|
||||||
{
|
|
||||||
_debugInfo = $"\n{f.Optimize(out var _).TypeBreakdown().Indent()}\n" +
|
|
||||||
"is given the argument: " +
|
"is given the argument: " +
|
||||||
"(" + argument.Optimize(out var _).TypeBreakdown() + ")";
|
"(" + argument.Optimize().TypeBreakdown() + ")";
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception) {
|
||||||
{
|
|
||||||
_debugInfo = $"\n (NO OPT) {f.TypeBreakdown().Indent()}\n" +
|
_debugInfo = $"\n (NO OPT) {f.TypeBreakdown().Indent()}\n" +
|
||||||
"is given the argument: " +
|
"is given the argument: " +
|
||||||
"(" + argument.TypeBreakdown() + ")";
|
"(" + argument.TypeBreakdown() + ")";
|
||||||
|
@ -102,8 +90,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
|
|
||||||
public object Evaluate(Context c, params IExpression[] arguments)
|
public object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
if (!Types.Any())
|
if (!Types.Any()) {
|
||||||
{
|
|
||||||
throw new ArgumentException("Trying to invoke an invalid expression: " + this);
|
throw new ArgumentException("Trying to invoke an invalid expression: " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +101,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
var arg = argExpr;
|
var arg = argExpr;
|
||||||
var allArgs = new IExpression[arguments.Length + 1];
|
var allArgs = new IExpression[arguments.Length + 1];
|
||||||
allArgs[0] = arg;
|
allArgs[0] = arg;
|
||||||
for (var i = 0; i < arguments.Length; i++)
|
for (var i = 0; i < arguments.Length; i++) {
|
||||||
{
|
|
||||||
allArgs[i + 1] = arguments[i];
|
allArgs[i + 1] = arguments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,42 +114,23 @@ namespace AspectedRouting.Language.Expression
|
||||||
return Specialize(allowedTypes);
|
return Specialize(allowedTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
||||||
{
|
{
|
||||||
var passed = FunctionApplications.Where(kv => allowedTypes.Invoke(kv.Key));
|
var passed = this.FunctionApplications.Where(kv => allowedTypes.Invoke(kv.Key));
|
||||||
if (!passed.Any())
|
if (!passed.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Apply("pruned", new Dictionary<Type, (IExpression A, IExpression F)>(passed));
|
return new Apply("pruned", new Dictionary<Type, (IExpression A, IExpression F)>(passed));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression Optimize(out bool somethingChanged)
|
public IExpression Optimize()
|
||||||
{
|
{
|
||||||
if (this.optimizedForm != null)
|
if (Types.Count() == 0) {
|
||||||
{
|
|
||||||
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.Any())
|
|
||||||
{
|
|
||||||
throw new ArgumentException("This application contain no valid types, so cannot be optimized" + this);
|
throw new ArgumentException("This application contain no valid types, so cannot be optimized" + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
somethingChanged = false;
|
|
||||||
// (eitherfunc dot id) id
|
// (eitherfunc dot id) id
|
||||||
// => (const dot _) id => dot id => id
|
// => (const dot _) id => dot id => id
|
||||||
// or => (constRight _ id) id => id id => id
|
// or => (constRight _ id) id => id id => id
|
||||||
if (
|
if (
|
||||||
UnApplyAny(
|
UnApplyAny(
|
||||||
|
@ -180,37 +147,23 @@ namespace AspectedRouting.Language.Expression
|
||||||
Any),
|
Any),
|
||||||
IsFunc(Funcs.Id)),
|
IsFunc(Funcs.Id)),
|
||||||
IsFunc(Funcs.Id)
|
IsFunc(Funcs.Id)
|
||||||
).Invoke(this))
|
).Invoke(this)) {
|
||||||
{
|
|
||||||
somethingChanged = true;
|
|
||||||
return Funcs.Id;
|
return Funcs.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Types.Count() > 1)
|
if (Types.Count() > 1) {
|
||||||
{
|
// Too much types to optimize
|
||||||
// Too much types to optimize: we optimize the subparts instead
|
|
||||||
var optimized = new Dictionary<Type, (IExpression f, IExpression a)>();
|
var optimized = new Dictionary<Type, (IExpression f, IExpression a)>();
|
||||||
foreach (var (resultType, (f, a)) in FunctionApplications)
|
foreach (var (resultType, (f, a)) in FunctionApplications) {
|
||||||
{
|
var fOpt = f.Optimize();
|
||||||
var fOpt = f.Optimize(out var scf);
|
var aOpt = a.Optimize();
|
||||||
var aOpt = a.Optimize(out var sca);
|
|
||||||
somethingChanged |= scf || sca;
|
|
||||||
optimized.Add(resultType, (fOpt, aOpt));
|
optimized.Add(resultType, (fOpt, aOpt));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (somethingChanged)
|
return new Apply(_debugInfo, optimized);
|
||||||
{
|
|
||||||
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
|
// id a => a
|
||||||
var arg = new List<IExpression>();
|
var arg = new List<IExpression>();
|
||||||
|
@ -218,40 +171,11 @@ namespace AspectedRouting.Language.Expression
|
||||||
UnApplyAny(
|
UnApplyAny(
|
||||||
IsFunc(Funcs.Id),
|
IsFunc(Funcs.Id),
|
||||||
Assign(arg)
|
Assign(arg)
|
||||||
).Invoke(this))
|
).Invoke(this)) {
|
||||||
{
|
return arg.First();
|
||||||
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)
|
// ifdotted fcondition fthen felse arg => if (fcondition arg) (fthen arg) (felse arg)
|
||||||
|
@ -270,104 +194,38 @@ namespace AspectedRouting.Language.Expression
|
||||||
Assign(fthen)),
|
Assign(fthen)),
|
||||||
Assign(felse)),
|
Assign(felse)),
|
||||||
Assign(arg)
|
Assign(arg)
|
||||||
).Invoke(this))
|
).Invoke(this)) {
|
||||||
{
|
|
||||||
var a = arg.First();
|
var a = arg.First();
|
||||||
somethingChanged = true;
|
|
||||||
return
|
return
|
||||||
Funcs.If.Apply(
|
Funcs.If.Apply(
|
||||||
fcondition.First().Apply(a).Optimize(out var _),
|
fcondition.First().Apply(a),
|
||||||
fthen.First().Apply(a).Optimize(out var _),
|
fthen.First().Apply(a),
|
||||||
felse.First().Apply(a).Optimize(out var _)
|
felse.First().Apply(a)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// 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 (f, a) = FunctionApplications.Values.First();
|
||||||
|
|
||||||
var (newFa, expr) = OptimizeApplicationPair(f, a, out var changed);
|
var (newFa, expr) = OptimizeApplicationPair(f, a);
|
||||||
if (expr != null)
|
if (expr != null) {
|
||||||
{
|
|
||||||
somethingChanged = true;
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed)
|
(f, a) = newFa.Value;
|
||||||
{
|
return new Apply(f, a);
|
||||||
somethingChanged = true;
|
|
||||||
(f, a) = newFa.Value;
|
|
||||||
return new Apply(f, a).Optimize(out _);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Visit(Func<IExpression, bool> visitor)
|
public void Visit(Func<IExpression, bool> visitor)
|
||||||
{
|
{
|
||||||
var continueVisit = visitor(this);
|
var continueVisit = visitor(this);
|
||||||
if (!continueVisit)
|
if (!continueVisit) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (_, (f, a)) in FunctionApplications)
|
foreach (var (_, (f, a)) in FunctionApplications) {
|
||||||
{
|
|
||||||
f.Visit(visitor);
|
f.Visit(visitor);
|
||||||
a.Visit(visitor);
|
a.Visit(visitor);
|
||||||
}
|
}
|
||||||
|
@ -377,13 +235,10 @@ namespace AspectedRouting.Language.Expression
|
||||||
{
|
{
|
||||||
var newArgs = new Dictionary<Type, (IExpression f, IExpression a)>();
|
var newArgs = new Dictionary<Type, (IExpression f, IExpression a)>();
|
||||||
|
|
||||||
foreach (var allowedType in allowedTypes)
|
foreach (var allowedType in allowedTypes) {
|
||||||
{
|
foreach (var (resultType, (funExpr, argExpr)) in FunctionApplications) {
|
||||||
foreach (var (resultType, (funExpr, argExpr)) in FunctionApplications)
|
|
||||||
{
|
|
||||||
var substitutions = resultType.UnificationTable(allowedType, true);
|
var substitutions = resultType.UnificationTable(allowedType, true);
|
||||||
if (substitutions == null)
|
if (substitutions == null) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,8 +250,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
var actualFunction = funExpr.Specialize(substitutions);
|
var actualFunction = funExpr.Specialize(substitutions);
|
||||||
var actualArgument = argExpr.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
|
// One of the subexpressions can't be optimized
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -405,47 +259,34 @@ namespace AspectedRouting.Language.Expression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newArgs.Any())
|
if (!newArgs.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Apply(_debugInfo, newArgs);
|
return new Apply(_debugInfo, newArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ((IExpression fOpt, IExpression fArg)?, IExpression result) OptimizeApplicationPair(
|
private ((IExpression fOpt, IExpression fArg)?, IExpression result) OptimizeApplicationPair(IExpression f,
|
||||||
IExpression fRaw,
|
IExpression a)
|
||||||
IExpression a,
|
|
||||||
out bool somethingChanged)
|
|
||||||
{
|
{
|
||||||
somethingChanged = false;
|
f = f.Optimize();
|
||||||
var f = fRaw.Optimize(out var scf);
|
|
||||||
somethingChanged |= scf;
|
|
||||||
|
|
||||||
if (f.Types.Count() == 0)
|
a = a.Optimize();
|
||||||
{
|
|
||||||
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(out var sca);
|
switch (f) {
|
||||||
somethingChanged |= sca;
|
|
||||||
switch (f)
|
|
||||||
{
|
|
||||||
case Id _:
|
case Id _:
|
||||||
return (null, a);
|
return (null, a);
|
||||||
|
|
||||||
case Apply apply:
|
case Apply apply:
|
||||||
|
|
||||||
if (apply.F is Const _)
|
if (apply.F is Const _) {
|
||||||
{
|
|
||||||
// (const x) y -> y
|
// (const x) y -> y
|
||||||
// apply == (const x) thus we return 'x' and ignore 'a'
|
// apply == (const x) thus we return 'x' and ignore 'a'
|
||||||
|
|
||||||
return (null, apply.A);
|
return (null, apply.A);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apply.F is ConstRight _)
|
if (apply.F is ConstRight _) {
|
||||||
{
|
|
||||||
// constRight x y -> y
|
// constRight x y -> y
|
||||||
// apply == (constRight x) so we return a
|
// apply == (constRight x) so we return a
|
||||||
return (null, a);
|
return (null, a);
|
||||||
|
@ -459,14 +300,12 @@ namespace AspectedRouting.Language.Expression
|
||||||
Assign(f0)
|
Assign(f0)
|
||||||
),
|
),
|
||||||
Assign(f1)).Invoke(apply)
|
Assign(f1)).Invoke(apply)
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
// apply == ((dot f0) f1)
|
// apply == ((dot f0) f1)
|
||||||
// ((dot f0) f1) a is the actual expression, but arg is already split of
|
// ((dot f0) f1) a is the actual expression, but arg is already split of
|
||||||
|
|
||||||
// f0 (f1 arg)
|
// f0 (f1 arg)
|
||||||
// which used to be (f0 . f1) arg
|
// which used to be (f0 . f1) arg
|
||||||
somethingChanged = true;
|
|
||||||
return ((f0.First(), new Apply(f1.First(), a)), null);
|
return ((f0.First(), new Apply(f1.First(), a)), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,82 +318,21 @@ namespace AspectedRouting.Language.Expression
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
if (!FunctionApplications.Any())
|
if (!FunctionApplications.Any()) {
|
||||||
{
|
|
||||||
return "NOT-TYPECHECKABLE APPLICATION: " + _debugInfo;
|
return "NOT-TYPECHECKABLE APPLICATION: " + _debugInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (f, arg) = FunctionApplications.Values.First();
|
var (f, arg) = FunctionApplications.Values.First();
|
||||||
if (f is Id _)
|
if (f is Id _) {
|
||||||
{
|
|
||||||
return arg.ToString();
|
return arg.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
var extra = "";
|
var extra = "";
|
||||||
if (FunctionApplications.Count() > 1)
|
if (FunctionApplications.Count() > 1) {
|
||||||
{
|
|
||||||
extra = " [" + FunctionApplications.Count + " IMPLEMENTATIONS]";
|
extra = " [" + FunctionApplications.Count + " IMPLEMENTATIONS]";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"({f} {arg.ToString().Indent()})" + extra;
|
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,6 +32,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
|
|
||||||
public object Evaluate(Context c, params IExpression[] arguments)
|
public object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
|
|
||||||
return ExpressionImplementation.Evaluate(c, arguments);
|
return ExpressionImplementation.Evaluate(c, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,29 +43,20 @@ namespace AspectedRouting.Language.Expression
|
||||||
Name, Description, Author, Unit, Filepath);
|
Name, Description, Author, Unit, Filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
||||||
{
|
{
|
||||||
var e = ExpressionImplementation.PruneTypes(allowedTypes);
|
var e = ExpressionImplementation.PruneTypes(allowedTypes);
|
||||||
if (e == null)
|
if (e == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AspectMetadata(e, Name, Description, Author, Unit,
|
return new AspectMetadata(e, Name, Description, Author, Unit,
|
||||||
Filepath, ProfileInternal);
|
Filepath, ProfileInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression Optimize(out bool somethingChanged)
|
public IExpression Optimize()
|
||||||
{
|
{
|
||||||
var optE = ExpressionImplementation.Optimize(out var sc);
|
return new AspectMetadata(ExpressionImplementation.Optimize(),
|
||||||
somethingChanged = sc;
|
Name, Description, Author, Unit, Filepath);
|
||||||
if (sc)
|
|
||||||
{
|
|
||||||
return new AspectMetadata(optE,
|
|
||||||
Name, Description, Author, Unit, Filepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Visit(Func<IExpression, bool> f)
|
public void Visit(Func<IExpression, bool> f)
|
||||||
|
@ -82,20 +74,5 @@ namespace AspectedRouting.Language.Expression
|
||||||
{
|
{
|
||||||
return $"# {Name}; {Unit} by {Author}\n\n# by {Author}\n# {Description}\n{ExpressionImplementation}";
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,17 +37,15 @@ namespace AspectedRouting.Language.Expression
|
||||||
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
||||||
{
|
{
|
||||||
var passedTypes = this.Types.Where(allowedTypes);
|
var passedTypes = this.Types.Where(allowedTypes);
|
||||||
if (!passedTypes.Any())
|
if (!passedTypes.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FunctionCall(this.Name, passedTypes);
|
return new FunctionCall(this.Name, passedTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual IExpression Optimize(out bool somethingChanged)
|
public virtual IExpression Optimize()
|
||||||
{
|
{
|
||||||
somethingChanged = false;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,9 +71,9 @@ namespace AspectedRouting.Language.Expression
|
||||||
|
|
||||||
if (ArgNames == null)
|
if (ArgNames == null)
|
||||||
{
|
{
|
||||||
throw new Exception("ArgNames not set for " + Name);
|
throw new Exception("ArgNames not set for "+Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var n in ArgNames)
|
foreach (var n in ArgNames)
|
||||||
{
|
{
|
||||||
dict[n] = new List<Type>();
|
dict[n] = new List<Type>();
|
||||||
|
@ -102,20 +100,5 @@ namespace AspectedRouting.Language.Expression
|
||||||
|
|
||||||
return dict;
|
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,14 +33,9 @@ namespace AspectedRouting.Language.Expression
|
||||||
Types = types;
|
Types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionCall(string name, Type type) : this(name, new[] { type })
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Evaluate(Context c, params IExpression[] arguments)
|
public object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
|
|
||||||
var func = c.GetFunction(_name);
|
var func = c.GetFunction(_name);
|
||||||
c = c.WithAspectName(_name);
|
c = c.WithAspectName(_name);
|
||||||
return func.Evaluate(c, arguments);
|
return func.Evaluate(c, arguments);
|
||||||
|
@ -60,17 +55,15 @@ namespace AspectedRouting.Language.Expression
|
||||||
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
||||||
{
|
{
|
||||||
var passedTypes = this.Types.Where(allowedTypes);
|
var passedTypes = this.Types.Where(allowedTypes);
|
||||||
if (!passedTypes.Any())
|
if (!passedTypes.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FunctionCall(this._name, passedTypes);
|
return new FunctionCall(this._name, passedTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression Optimize(out bool somethingChanged)
|
public IExpression Optimize()
|
||||||
{
|
{
|
||||||
somethingChanged = false;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,21 +87,6 @@ namespace AspectedRouting.Language.Expression
|
||||||
f(this);
|
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()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"${_name}";
|
return $"${_name}";
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
public string Author { get; }
|
public string Author { get; }
|
||||||
public string Filename { get; }
|
public string Filename { get; }
|
||||||
public List<string> VehicleTyps { get; }
|
public List<string> VehicleTyps { get; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Which tags are included in the routerdb but are _not_ used for routeplanning?
|
* 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, ...)
|
* Typically these are tags that are useful for navigation (name of the road, is this a tunnel, ...)
|
||||||
|
@ -28,14 +28,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
public IExpression Access { get; }
|
public IExpression Access { get; }
|
||||||
public IExpression Oneway { get; }
|
public IExpression Oneway { get; }
|
||||||
public IExpression Speed { get; }
|
public IExpression Speed { get; }
|
||||||
|
|
||||||
public IExpression ObstacleAccess { get; }
|
|
||||||
public IExpression ObstacleCost { get; }
|
|
||||||
|
|
||||||
public Dictionary<string, IExpression> Priority { get; }
|
public Dictionary<string, IExpression> Priority { get; }
|
||||||
|
|
||||||
public IExpression ScalingFactor { get; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moment of last change of any upstream file
|
* Moment of last change of any upstream file
|
||||||
*/
|
*/
|
||||||
|
@ -45,21 +38,17 @@ namespace AspectedRouting.Language.Expression
|
||||||
List<string> vehicleTyps, Dictionary<string, IExpression> defaultParameters,
|
List<string> vehicleTyps, Dictionary<string, IExpression> defaultParameters,
|
||||||
Dictionary<string, Dictionary<string, IExpression>> behaviours,
|
Dictionary<string, Dictionary<string, IExpression>> behaviours,
|
||||||
IExpression access, IExpression oneway, IExpression speed,
|
IExpression access, IExpression oneway, IExpression speed,
|
||||||
IExpression obstacleAccess, IExpression obstacleCost,
|
Dictionary<string, IExpression> priority, List<string> metadata, DateTime lastChange)
|
||||||
Dictionary<string, IExpression> priority, IExpression scalingFactor, List<string> metadata, DateTime lastChange)
|
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
Description = description;
|
||||||
Author = author;
|
Author = author;
|
||||||
Filename = filename;
|
Filename = filename;
|
||||||
VehicleTyps = vehicleTyps;
|
VehicleTyps = vehicleTyps;
|
||||||
Access = access.Optimize(out _);
|
Access = access.Optimize();
|
||||||
Oneway = oneway.Optimize(out _);
|
Oneway = oneway.Optimize();
|
||||||
Speed = speed.Optimize(out _);
|
Speed = speed.Optimize();
|
||||||
ObstacleAccess = obstacleAccess.Optimize(out _);
|
|
||||||
ObstacleCost = obstacleCost.Optimize(out _);
|
|
||||||
Priority = priority;
|
Priority = priority;
|
||||||
ScalingFactor = scalingFactor;
|
|
||||||
Metadata = metadata;
|
Metadata = metadata;
|
||||||
LastChange = lastChange;
|
LastChange = lastChange;
|
||||||
DefaultParameters = defaultParameters;
|
DefaultParameters = defaultParameters;
|
||||||
|
@ -68,28 +57,21 @@ namespace AspectedRouting.Language.Expression
|
||||||
CheckTypes(Access, "access");
|
CheckTypes(Access, "access");
|
||||||
CheckTypes(Oneway, "oneway");
|
CheckTypes(Oneway, "oneway");
|
||||||
CheckTypes(Speed, "speed");
|
CheckTypes(Speed, "speed");
|
||||||
CheckTypes(ObstacleAccess, "obstacleaccess");
|
|
||||||
CheckTypes(ObstacleCost, "obstaclecost");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckTypes(IExpression e, string name)
|
private static void CheckTypes(IExpression e, string name)
|
||||||
{
|
{
|
||||||
if (e == null)
|
if (e.Types.Count() == 1) {
|
||||||
{
|
|
||||||
throw new Exception("No expression given for " + name);
|
|
||||||
}
|
|
||||||
if (e.Types.Count() == 1)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception("Insufficient specialization: " + name + " has multiple types left, namely " +
|
throw new Exception("Insufficient specialization: " + name + " has multiple types left, namely " + e.Types.Pretty());
|
||||||
e.Types.Pretty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IExpression> AllExpressions(Context ctx)
|
public List<IExpression> AllExpressions(Context ctx)
|
||||||
{
|
{
|
||||||
var l = new List<IExpression> { Access, Oneway, Speed, ObstacleAccess, ObstacleCost };
|
var l = new List<IExpression> {Access, Oneway, Speed};
|
||||||
l.AddRange(DefaultParameters.Values);
|
l.AddRange(DefaultParameters.Values);
|
||||||
l.AddRange(Behaviours.Values.SelectMany(b => b.Values));
|
l.AddRange(Behaviours.Values.SelectMany(b => b.Values));
|
||||||
l.AddRange(Priority.Values);
|
l.AddRange(Priority.Values);
|
||||||
|
@ -106,7 +88,6 @@ namespace AspectedRouting.Language.Expression
|
||||||
var called = ctx.GetFunction(fc.CalledFunctionName);
|
var called = ctx.GetFunction(fc.CalledFunctionName);
|
||||||
allExpr.Add(called);
|
allExpr.Add(called);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -114,48 +95,15 @@ namespace AspectedRouting.Language.Expression
|
||||||
return allExpr;
|
return allExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IExpression> AllExpressionsFor(string behaviourName, Context context)
|
|
||||||
|
public ProfileResult Run(Context c, string behaviour, Dictionary<string, string> tags)
|
||||||
{
|
{
|
||||||
var allExpressions = new List<IExpression>
|
if (!Behaviours.ContainsKey(behaviour))
|
||||||
{
|
{
|
||||||
Access,
|
throw new ArgumentException(
|
||||||
Oneway,
|
$"Profile {Name} does not contain the behaviour {behaviour}\nTry one of {string.Join(",", Behaviours.Keys)}");
|
||||||
Speed,
|
|
||||||
ObstacleAccess,
|
|
||||||
ObstacleCost
|
|
||||||
};
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
var parameters = new Dictionary<string, IExpression>();
|
var parameters = new Dictionary<string, IExpression>();
|
||||||
|
|
||||||
foreach (var (k, v) in DefaultParameters)
|
foreach (var (k, v) in DefaultParameters)
|
||||||
|
@ -168,23 +116,12 @@ namespace AspectedRouting.Language.Expression
|
||||||
parameters[k.TrimStart('#')] = v;
|
parameters[k.TrimStart('#')] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parameters;
|
c = c.WithParameters(parameters)
|
||||||
}
|
.WithAspectName(this.Name);
|
||||||
|
|
||||||
public ProfileResult Run(Context c, string behaviour, Dictionary<string, string> tags)
|
|
||||||
{
|
|
||||||
if (!Behaviours.ContainsKey(behaviour))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
$"Profile {Name} does not contain the behaviour {behaviour}\nTry one of {string.Join(",", Behaviours.Keys)}");
|
|
||||||
}
|
|
||||||
|
|
||||||
c = c.WithParameters(ParametersFor(behaviour))
|
|
||||||
.WithAspectName(Name);
|
|
||||||
tags = new Dictionary<string, string>(tags);
|
tags = new Dictionary<string, string>(tags);
|
||||||
var canAccess = Access.Run(c, tags);
|
var canAccess = Access.Run(c, tags);
|
||||||
tags["access"] = "" + canAccess;
|
tags["access"] = "" + canAccess;
|
||||||
var speed = (double)Speed.Run(c, tags);
|
var speed = (double) Speed.Run(c, tags);
|
||||||
tags["speed"] = "" + speed;
|
tags["speed"] = "" + speed;
|
||||||
var oneway = Oneway.Run(c, tags);
|
var oneway = Oneway.Run(c, tags);
|
||||||
tags["oneway"] = "" + oneway;
|
tags["oneway"] = "" + oneway;
|
||||||
|
@ -201,7 +138,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
var weightExplanation = new List<string>();
|
var weightExplanation = new List<string>();
|
||||||
foreach (var (paramName, expression) in Priority)
|
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
|
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||||
if (aspectInfluence == 0)
|
if (aspectInfluence == 0)
|
||||||
{
|
{
|
||||||
|
@ -209,34 +146,50 @@ namespace AspectedRouting.Language.Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var aspectWeight = new Apply(
|
var aspectWeightObj = new Apply(
|
||||||
Funcs.EitherFunc.Apply(Funcs.Id, Funcs.Const, expression)
|
Funcs.EitherFunc.Apply(Funcs.Id, Funcs.Const, expression)
|
||||||
, new Constant(tags)).EvaluateDouble(paramName, c);
|
, new Constant(tags)).Evaluate(c);
|
||||||
|
|
||||||
|
double aspectWeight;
|
||||||
|
switch (aspectWeightObj)
|
||||||
|
{
|
||||||
|
case bool b:
|
||||||
|
aspectWeight = b ? 1.0 : 0.0;
|
||||||
|
break;
|
||||||
|
case double d:
|
||||||
|
aspectWeight = d;
|
||||||
|
break;
|
||||||
|
case int j:
|
||||||
|
aspectWeight = j;
|
||||||
|
break;
|
||||||
|
case string s:
|
||||||
|
if (s.Equals("yes"))
|
||||||
|
{
|
||||||
|
aspectWeight = 1.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (s.Equals("no"))
|
||||||
|
{
|
||||||
|
aspectWeight = 0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception($"Invalid value as result for {paramName}: got string {s}");
|
||||||
|
default:
|
||||||
|
throw new Exception($"Invalid value as result for {paramName}: got object {aspectWeightObj}");
|
||||||
|
}
|
||||||
|
|
||||||
weightExplanation.Add($"({paramName} = {aspectInfluence}) * {aspectWeight}");
|
weightExplanation.Add($"({paramName} = {aspectInfluence}) * {aspectWeight}");
|
||||||
priority += aspectInfluence * aspectWeight;
|
priority += aspectInfluence * aspectWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
var scalingFactor = Utils.AsDouble(ScalingFactor.Run(c, tags) ?? 1.0, "scalingfactor");
|
|
||||||
weightExplanation.Add("Scaling factor: " + scalingFactor);
|
|
||||||
priority *= scalingFactor;
|
|
||||||
if (priority <= 0)
|
if (priority <= 0)
|
||||||
{
|
{
|
||||||
canAccess = "no";
|
canAccess = "no";
|
||||||
weightExplanation.Add("WARNING: access has been set to 'no' as priority is < 0");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAccess is string canAccessString && oneway is string onewayString)
|
return new ProfileResult((string) canAccess, (string) oneway, speed, priority,
|
||||||
{
|
string.Join("\n ", weightExplanation));
|
||||||
return new ProfileResult(canAccessString, onewayString, speed, priority,
|
|
||||||
string.Join("\n ", weightExplanation));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception("CanAccess or oneway are not strings but " + canAccess.GetType() +
|
|
||||||
" and " + (oneway?.GetType()?.ToString() ?? "<null>"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ namespace AspectedRouting.Language
|
||||||
public static readonly Function Eq = new Eq();
|
public static readonly Function Eq = new Eq();
|
||||||
public static readonly Function NotEq = new NotEq();
|
public static readonly Function NotEq = new NotEq();
|
||||||
public static readonly Function Inv = new Inv();
|
public static readonly Function Inv = new Inv();
|
||||||
public static readonly Function IsNull = new IsNull();
|
|
||||||
|
|
||||||
public static readonly Function Default = new Default();
|
public static readonly Function Default = new Default();
|
||||||
|
|
||||||
|
@ -88,14 +87,15 @@ namespace AspectedRouting.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
var eSmallest = e.SpecializeToSmallestType();
|
var eSmallest = e.SpecializeToSmallestType();
|
||||||
if (eSmallest == null || !eSmallest.Types.Any())
|
if (eSmallest == null || eSmallest.Types.Count() == 0)
|
||||||
{
|
{
|
||||||
throw new Exception("Could not specialize " + e);
|
throw new Exception("Could not specialize " + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO FIX THIS so that it works
|
||||||
// An argument 'optimizes' it's types from 'string -> bool' to 'string -> string'
|
// An argument 'optimizes' it's types from 'string -> bool' to 'string -> string'
|
||||||
var eOpt = eSmallest.Optimize(out _);
|
var eOpt = eSmallest.Optimize();
|
||||||
if (eOpt == null || !eOpt.Types.Any())
|
if (eOpt == null || eOpt.Types.Count() == 0)
|
||||||
{
|
{
|
||||||
throw new Exception("Could not optimize " + eSmallest);
|
throw new Exception("Could not optimize " + eSmallest);
|
||||||
}
|
}
|
||||||
|
@ -106,10 +106,6 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
public static IExpression SpecializeToSmallestType(this IExpression e)
|
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)
|
if (e.Types.Count() == 1)
|
||||||
{
|
{
|
||||||
return e;
|
return e;
|
||||||
|
@ -137,7 +133,7 @@ namespace AspectedRouting.Language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.Specialize(new[] { smallest });
|
return e.Specialize(new[] {smallest});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IExpression Apply(this IExpression function, IEnumerable<IExpression> args)
|
public static IExpression Apply(this IExpression function, IEnumerable<IExpression> args)
|
||||||
|
@ -164,8 +160,7 @@ namespace AspectedRouting.Language
|
||||||
|
|
||||||
var lastArg = args[args.Count - 1];
|
var lastArg = args[args.Count - 1];
|
||||||
var firstArgs = args.GetRange(0, args.Count - 1);
|
var firstArgs = args.GetRange(0, args.Count - 1);
|
||||||
var applied = Apply(function, firstArgs);
|
return new Apply(Apply(function, firstArgs), lastArg);
|
||||||
return new Apply(applied, lastArg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var arg = ((IEnumerable<object>)arguments[0].Evaluate(c)).Select(o => (string)o);
|
var arg = ((IEnumerable<object>) arguments[0].Evaluate(c)).Select(o => (string) o);
|
||||||
|
|
||||||
|
|
||||||
if (arg.Any(str => str == null || str.Equals("no") || str.Equals("false")))
|
if (arg.Any(str => str == null || str.Equals("no") || str.Equals("false")))
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Returns 'yes' if the second argument is bigger then the first argument. (Works great in combination with $dot)";
|
"Returns 'yes' if the second argument is bigger then the first argument. (Works great in combination with $dot)";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "minimum", "f", "then", "else" };
|
public override List<string> ArgNames { get; } = new List<string> {"minimum", "f", "then","else"};
|
||||||
|
|
||||||
private static Type a = new Var("a");
|
private static Type a = new Var("a");
|
||||||
private static Type b = new Var("b");
|
private static Type b = new Var("b");
|
||||||
|
@ -20,7 +20,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
Curry.ConstructFrom(a,
|
Curry.ConstructFrom(a,
|
||||||
Typs.Double,
|
Typs.Double,
|
||||||
new Curry(b,Typs.Double),
|
new Curry(b,Typs.Double),
|
||||||
a, a, b),
|
a, a, b),
|
||||||
})
|
})
|
||||||
|
@ -50,7 +50,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
var x = arguments[4];
|
var x = arguments[4];
|
||||||
|
|
||||||
var arg1 = arguments[1].Evaluate(c, x);
|
var arg1 = arguments[1].Evaluate(c, x);
|
||||||
|
|
||||||
if (minimum == null || arg1 == null)
|
if (minimum == null || arg1 == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -60,7 +60,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
minimum = e.Evaluate(c);
|
minimum = e.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg1 is IExpression e1)
|
if (arg1 is IExpression e1)
|
||||||
{
|
{
|
||||||
arg1 = e1.Evaluate(c);
|
arg1 = e1.Evaluate(c);
|
||||||
|
@ -68,12 +68,12 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
if (minimum is int i0)
|
if (minimum is int i0)
|
||||||
{
|
{
|
||||||
minimum = (double)i0;
|
minimum = (double) i0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg1 is int i1)
|
if (arg1 is int i1)
|
||||||
{
|
{
|
||||||
arg1 = (double)i1;
|
arg1 = (double) i1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minimum is double d0 && arg1 is double d1)
|
if (minimum is double d0 && arg1 is double d1)
|
||||||
|
@ -86,7 +86,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
return @else;
|
return @else;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidCastException("One of the arguments is not a number: " + minimum + ", " + arg1);
|
throw new InvalidCastException("One of the arguments is not a number: "+minimum+", "+arg1);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public class Concat : Function
|
public class Concat : Function
|
||||||
{
|
{
|
||||||
public override string Description { get; } = "Concatenates two strings";
|
public override string Description { get; } = "Concatenates two strings";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "a", "b" };
|
public override List<string> ArgNames { get; } = new List<string>{"a","b"};
|
||||||
public Concat() : base("concat", true,
|
public Concat() : base("concat", true,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
|
@ -33,8 +33,8 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var arg0 = (string)arguments[0].Evaluate(c);
|
var arg0 = (string) arguments[0].Evaluate(c);
|
||||||
var arg1 = (string)arguments[1].Evaluate(c);
|
var arg1 = (string) arguments[1].Evaluate(c);
|
||||||
return arg0 + arg1;
|
return arg0 + arg1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Small utility function, which takes two arguments `a` and `b` and returns `a`. Used extensively to insert freedom";
|
"Small utility function, which takes two arguments `a` and `b` and returns `a`. Used extensively to insert freedom";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "a", "b" };
|
public override List<string> ArgNames { get; } = new List<string>{"a","b"};
|
||||||
|
|
||||||
public Const() : base("firstArg", true,
|
public Const() : base("firstArg", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -19,7 +19,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Funcs.AddBuiltin(this, "const");
|
Funcs.AddBuiltin(this,"const");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Const(IEnumerable<Type> types) : base("firstArg", types
|
private Const(IEnumerable<Type> types) : base("firstArg", types
|
||||||
|
@ -27,7 +27,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c,params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
if (arguments.Length == 1)
|
if (arguments.Length == 1)
|
||||||
{
|
{
|
||||||
|
@ -35,13 +35,13 @@ namespace AspectedRouting.Language.Functions
|
||||||
}
|
}
|
||||||
|
|
||||||
var f = arguments[0];
|
var f = arguments[0];
|
||||||
var args = new IExpression[arguments.Length - 2];
|
var args = new IExpression [arguments.Length - 2];
|
||||||
for (var i = 2; i < arguments.Length; i++)
|
for (var i = 2; i < arguments.Length; i++)
|
||||||
{
|
{
|
||||||
args[i - 2] = arguments[i];
|
args[i - 2] = arguments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.Evaluate(c, args);
|
return f.Evaluate(c,args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
||||||
|
|
|
@ -6,11 +6,10 @@ using Type = AspectedRouting.Language.Typ.Type;
|
||||||
namespace AspectedRouting.Language.Functions
|
namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public class ConstRight : Function
|
public class ConstRight : Function
|
||||||
{
|
{ public override string Description { get; } =
|
||||||
public override string Description { get; } =
|
"Small utility function, which takes two arguments `a` and `b` and returns `b`. Used extensively to insert freedom";
|
||||||
"Small utility function, which takes two arguments `a` and `b` and returns `b`. Used extensively to insert freedom";
|
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "a", "b" };
|
public override List<string> ArgNames { get; } = new List<string>{"a","b"};
|
||||||
|
|
||||||
public ConstRight() : base("constRight", true,
|
public ConstRight() : base("constRight", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -26,7 +25,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c,params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var argsFor1 = new IExpression[arguments.Length - 2];
|
var argsFor1 = new IExpression[arguments.Length - 2];
|
||||||
for (var i = 2; i < arguments.Length; i++)
|
for (var i = 2; i < arguments.Length; i++)
|
||||||
|
|
|
@ -14,11 +14,9 @@ namespace AspectedRouting.Language.Functions
|
||||||
public Constant(IEnumerable<Type> types, object o)
|
public Constant(IEnumerable<Type> types, object o)
|
||||||
{
|
{
|
||||||
Types = types.ToList();
|
Types = types.ToList();
|
||||||
if (o is IEnumerable<IExpression> enumerable)
|
if (o is IEnumerable<IExpression> enumerable) {
|
||||||
{
|
|
||||||
o = enumerable.ToList();
|
o = enumerable.ToList();
|
||||||
if (enumerable.Any(x => x == null))
|
if (enumerable.Any(x => x == null)) {
|
||||||
{
|
|
||||||
throw new NullReferenceException("Some subexpression is null");
|
throw new NullReferenceException("Some subexpression is null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,12 +26,10 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public Constant(Type t, object o)
|
public Constant(Type t, object o)
|
||||||
{
|
{
|
||||||
Types = new List<Type> { t };
|
Types = new List<Type> {t};
|
||||||
if (o is IEnumerable<IExpression> enumerable)
|
if (o is IEnumerable<IExpression> enumerable) {
|
||||||
{
|
|
||||||
o = enumerable.ToList();
|
o = enumerable.ToList();
|
||||||
if (enumerable.Any(x => x == null))
|
if (enumerable.Any(x => x == null)) {
|
||||||
{
|
|
||||||
throw new NullReferenceException("Some subexpression is null");
|
throw new NullReferenceException("Some subexpression is null");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,8 +42,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
var tps = exprs
|
var tps = exprs
|
||||||
.SpecializeToCommonTypes(out var specializedVersions)
|
.SpecializeToCommonTypes(out var specializedVersions)
|
||||||
.Select(t => new ListType(t));
|
.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 " +
|
throw new Exception("Specializing to common types failed for " +
|
||||||
string.Join(",", exprs.Select(e => e.ToString())));
|
string.Join(",", exprs.Select(e => e.ToString())));
|
||||||
}
|
}
|
||||||
|
@ -58,50 +53,40 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public Constant(IReadOnlyCollection<IExpression> exprs)
|
public Constant(IReadOnlyCollection<IExpression> exprs)
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
Types = exprs
|
Types = exprs
|
||||||
.SpecializeToCommonTypes(out var specializedVersions)
|
.SpecializeToCommonTypes(out var specializedVersions)
|
||||||
.Select(t => new ListType(t))
|
.Select(t => new ListType(t))
|
||||||
.ToList();
|
.ToList();
|
||||||
specializedVersions = specializedVersions.ToList();
|
if (specializedVersions.Any(x => x == null)) {
|
||||||
if (specializedVersions.Any(x => x == null))
|
throw new NullReferenceException("Some subexpression is 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();
|
_o = specializedVersions.ToList();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e) {
|
||||||
{
|
|
||||||
throw new Exception("While creating a list with members " +
|
throw new Exception("While creating a list with members " +
|
||||||
string.Join(", ", exprs.Select(x => x.Optimize(out var _))) +
|
string.Join(", ", exprs.Select(x => x.Optimize())) +
|
||||||
$" {e.Message}", e);
|
$" {e.Message}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Constant(string s)
|
public Constant(string s)
|
||||||
{
|
{
|
||||||
Types = new List<Type> { Typs.String };
|
Types = new List<Type> {Typs.String};
|
||||||
_o = s;
|
_o = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Constant(double d)
|
public Constant(double d)
|
||||||
{
|
{
|
||||||
if (d >= 0)
|
if (d >= 0) {
|
||||||
{
|
Types = new[] {Typs.Double, Typs.PDouble};
|
||||||
Types = new[] { Typs.Double, Typs.PDouble };
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
Types = new[] {Typs.Double};
|
||||||
Types = new[] { Typs.Double };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_o = d;
|
_o = d;
|
||||||
|
@ -109,13 +94,11 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public Constant(int i)
|
public Constant(int i)
|
||||||
{
|
{
|
||||||
if (i >= 0)
|
if (i >= 0) {
|
||||||
{
|
Types = new[] {Typs.Double, Typs.Nat, Typs.Nat, Typs.PDouble};
|
||||||
Types = new[] { Typs.Double, Typs.Int, Typs.Nat, Typs.PDouble };
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
Types = new[] {Typs.Double, Typs.Int};
|
||||||
Types = new[] { Typs.Double, Typs.Int };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_o = i;
|
_o = i;
|
||||||
|
@ -123,17 +106,16 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public Constant(Dictionary<string, string> tags)
|
public Constant(Dictionary<string, string> tags)
|
||||||
{
|
{
|
||||||
Types = new[] { Typs.Tags };
|
Types = new[] {Typs.Tags};
|
||||||
_o = tags;
|
_o = tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Type> Types { get; }
|
public IEnumerable<Type> Types { get; }
|
||||||
|
|
||||||
public IExpression PruneTypes(Func<Type, bool> allowedTypes)
|
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
||||||
{
|
{
|
||||||
var passedTypes = Types.Where(allowedTypes);
|
var passedTypes = Types.Where(allowedTypes);
|
||||||
if (!passedTypes.Any())
|
if (!passedTypes.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,32 +124,28 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public object Evaluate(Context c, params IExpression[] args)
|
public object Evaluate(Context c, params IExpression[] args)
|
||||||
{
|
{
|
||||||
if (_o is IExpression e)
|
if (_o is IExpression e) {
|
||||||
{
|
|
||||||
return e.Evaluate(c).Pretty();
|
return e.Evaluate(c).Pretty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Types.Count() > 1)
|
if (Types.Count() > 1) {
|
||||||
{
|
|
||||||
return _o;
|
return _o;
|
||||||
}
|
}
|
||||||
|
|
||||||
var t = Types.First();
|
var t = Types.First();
|
||||||
switch (t)
|
switch (t) {
|
||||||
{
|
|
||||||
case DoubleType _:
|
case DoubleType _:
|
||||||
case PDoubleType _:
|
case PDoubleType _:
|
||||||
if (_o is int i)
|
if (_o is int i) {
|
||||||
{
|
|
||||||
return
|
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 IntType _:
|
||||||
case NatType _:
|
case NatType _:
|
||||||
return (int)_o;
|
return (int) _o;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _o;
|
return _o;
|
||||||
|
@ -177,39 +155,31 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
var allowedTypes = allowedTypesEnumerable.ToList();
|
var allowedTypes = allowedTypesEnumerable.ToList();
|
||||||
var unified = Types.SpecializeTo(allowedTypes);
|
var unified = Types.SpecializeTo(allowedTypes);
|
||||||
if (unified == null)
|
if (unified == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newO = _o;
|
var newO = _o;
|
||||||
if (_o is IExpression e)
|
if (_o is IExpression e) {
|
||||||
{
|
|
||||||
newO = e.Specialize(allowedTypes);
|
newO = e.Specialize(allowedTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_o is IEnumerable<IExpression> es)
|
if (_o is IEnumerable<IExpression> es) {
|
||||||
{
|
|
||||||
var innerTypes = new List<Type>();
|
var innerTypes = new List<Type>();
|
||||||
foreach (var allowedType in allowedTypes)
|
foreach (var allowedType in allowedTypes) {
|
||||||
{
|
if (allowedType is ListType listType) {
|
||||||
if (allowedType is ListType listType)
|
|
||||||
{
|
|
||||||
innerTypes.Add(listType.InnerType);
|
innerTypes.Add(listType.InnerType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var specializedExpressions = new List<IExpression>();
|
var specializedExpressions = new List<IExpression>();
|
||||||
foreach (var expr in es)
|
foreach (var expr in es) {
|
||||||
{
|
if (expr == null) {
|
||||||
if (expr == null)
|
|
||||||
{
|
|
||||||
throw new NullReferenceException("Subexpression is null");
|
throw new NullReferenceException("Subexpression is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
var specialized = expr.Specialize(innerTypes);
|
var specialized = expr.Specialize(innerTypes);
|
||||||
if (specialized == null)
|
if (specialized == null) {
|
||||||
{
|
|
||||||
// If a subexpression can not be specialized, this list cannot be specialized
|
// If a subexpression can not be specialized, this list cannot be specialized
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -223,38 +193,26 @@ namespace AspectedRouting.Language.Functions
|
||||||
return new Constant(unified, newO);
|
return new Constant(unified, newO);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression Optimize(out bool somethingChanged)
|
public IExpression Optimize()
|
||||||
{
|
{
|
||||||
somethingChanged = false;
|
if (_o is IEnumerable<IExpression> exprs) {
|
||||||
if (_o is IEnumerable<IExpression> exprs)
|
|
||||||
{
|
|
||||||
// This is a list
|
// This is a list
|
||||||
var optExprs = new List<IExpression>();
|
var optExprs = new List<IExpression>();
|
||||||
foreach (var expression in exprs)
|
foreach (var expression in exprs) {
|
||||||
{
|
var exprOpt = expression.Optimize();
|
||||||
var exprOpt = expression.Optimize(out var sc);
|
if (exprOpt == null || exprOpt.Types.Count() == 0) {
|
||||||
somethingChanged |= sc;
|
|
||||||
if (exprOpt == null || exprOpt.Types.Count() == 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Non-optimizable expression:" + expression);
|
throw new ArgumentException("Non-optimizable expression:" + expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
optExprs.Add(exprOpt);
|
optExprs.Add(exprOpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (somethingChanged)
|
return new Constant(optExprs);
|
||||||
{
|
|
||||||
return new Constant(optExprs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_o is IExpression expr)
|
if (_o is IExpression expr) {
|
||||||
{
|
// This is a list
|
||||||
// This is a subexpression
|
return new Constant(expr.Types, expr.Optimize());
|
||||||
somethingChanged = true;
|
|
||||||
return expr.Optimize(out var _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -262,15 +220,12 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public void Visit(Func<IExpression, bool> f)
|
public void Visit(Func<IExpression, bool> f)
|
||||||
{
|
{
|
||||||
if (_o is IExpression e)
|
if (_o is IExpression e) {
|
||||||
{
|
|
||||||
e.Visit(f);
|
e.Visit(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_o is IEnumerable<IExpression> es)
|
if (_o is IEnumerable<IExpression> es) {
|
||||||
{
|
foreach (var x in es) {
|
||||||
foreach (var x in es)
|
|
||||||
{
|
|
||||||
x.Visit(f);
|
x.Visit(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,28 +233,6 @@ namespace AspectedRouting.Language.Functions
|
||||||
f(this);
|
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)
|
public void EvaluateAll(Context c, HashSet<IExpression> addTo)
|
||||||
{
|
{
|
||||||
addTo.Add(this);
|
addTo.Add(this);
|
||||||
|
@ -312,12 +245,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return ObjectExtensions.Pretty(_o);
|
return _o.Pretty();
|
||||||
}
|
|
||||||
|
|
||||||
public object Get()
|
|
||||||
{
|
|
||||||
return _o;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,24 +253,19 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public static string Pretty(this object o, Context context = null)
|
public static string Pretty(this object o, Context context = null)
|
||||||
{
|
{
|
||||||
switch (o)
|
switch (o) {
|
||||||
{
|
|
||||||
case null: return "null";
|
|
||||||
case Dictionary<string, string> d:
|
case Dictionary<string, string> d:
|
||||||
var txt = "";
|
var txt = "";
|
||||||
foreach (var (k, v) in d)
|
foreach (var (k, v) in d) {
|
||||||
{
|
|
||||||
txt += $"{k}={v};";
|
txt += $"{k}={v};";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{{{txt}}}";
|
return $"{{{txt}}}";
|
||||||
case Dictionary<string, List<string>> d:
|
case Dictionary<string, List<string>> d:
|
||||||
var t = "";
|
var t = "";
|
||||||
foreach (var (k, v) in d)
|
foreach (var (k, v) in d) {
|
||||||
{
|
|
||||||
var values = v.Pretty();
|
var values = v.Pretty();
|
||||||
if (!v.Any())
|
if (!v.Any()) {
|
||||||
{
|
|
||||||
values = "*";
|
values = "*";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +281,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
case object[] arr:
|
case object[] arr:
|
||||||
return arr.ToList().Pretty();
|
return arr.ToList().Pretty();
|
||||||
case double[] arr:
|
case double[] arr:
|
||||||
return arr.Select(d => (object)d).ToList().Pretty();
|
return arr.Select(d => (object) d).ToList().Pretty();
|
||||||
case string s:
|
case string s:
|
||||||
return "\"" + s.Replace("\"", "\\\"") + "\"";
|
return "\"" + s.Replace("\"", "\\\"") + "\"";
|
||||||
case IEnumerable<object> ls:
|
case IEnumerable<object> ls:
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Given a list of values, checks if the argument is contained in the list.";
|
"Given a list of values, checks if the argument is contained in the list.";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "list", "a" };
|
public override List<string> ArgNames { get; } = new List<string>{"list","a"};
|
||||||
|
|
||||||
public ContainedIn() : base("containedIn", true,
|
public ContainedIn() : base("containedIn", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -30,7 +30,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var list = (IEnumerable<IExpression>)arguments[0].Evaluate(c);
|
var list = (IEnumerable<IExpression>) arguments[0].Evaluate(c);
|
||||||
var arg = arguments[1];
|
var arg = arguments[1];
|
||||||
|
|
||||||
var result = new List<object>();
|
var result = new List<object>();
|
||||||
|
|
|
@ -7,11 +7,11 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public class Default : Function
|
public class Default : Function
|
||||||
{
|
{
|
||||||
|
|
||||||
public override string Description { get; } = "Calculates function `f` for the given argument. If the result is `null`, the default value is returned instead";
|
public override string Description { get; } = "Calculates function `f` for the given argument. If the result is `null`, the default value is returned instead";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "defaultValue", "f" };
|
public override List<string> ArgNames { get; } = new List<string> {"defaultValue", "f"};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static Var a = new Var("a");
|
private static Var a = new Var("a");
|
||||||
private static Var b = new Var("b");
|
private static Var b = new Var("b");
|
||||||
public Default() : base("default", true,
|
public Default() : base("default", true,
|
||||||
|
@ -37,13 +37,13 @@ namespace AspectedRouting.Language.Functions
|
||||||
return new Default(unified);
|
return new Default(unified);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c,params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var defaultValue = arguments[0];
|
var defaultValue = arguments[0];
|
||||||
var func = arguments[1];
|
var func = arguments[1];
|
||||||
var args = arguments.ToList().GetRange(2, arguments.Length - 2).ToArray();
|
var args= arguments.ToList().GetRange(2, arguments.Length - 2).ToArray();
|
||||||
|
|
||||||
var calculated = func.Evaluate(c, args);
|
var calculated = func.Evaluate(c,args);
|
||||||
if (calculated == null)
|
if (calculated == null)
|
||||||
{
|
{
|
||||||
return defaultValue.Evaluate(c);
|
return defaultValue.Evaluate(c);
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Higher order function: converts `f (g a)` into `(dot f g) a`. In other words, this fuses `f` and `g` in a new function, which allows the argument to be lifted out of the expression ";
|
"Higher order function: converts `f (g a)` into `(dot f g) a`. In other words, this fuses `f` and `g` in a new function, which allows the argument to be lifted out of the expression ";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "f", "g", "a" };
|
public override List<string> ArgNames { get; } = new List<string> {"f", "g", "a"};
|
||||||
public static readonly Var A = new Var("a");
|
public static readonly Var A = new Var("a");
|
||||||
public static readonly Var B = new Var("b");
|
public static readonly Var B = new Var("b");
|
||||||
public static readonly Var C = new Var("c");
|
public static readonly Var C = new Var("c");
|
||||||
|
@ -36,12 +36,11 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
if (arguments.Count() <= 2)
|
if (arguments.Count() <= 2)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var f0 = arguments[0];
|
var f0 = arguments[0];
|
||||||
var f1 = arguments[1];
|
var f1 = arguments[1];
|
||||||
var resultType = ((Curry)f1.Types.First()).ResultType;
|
var resultType = ((Curry) f1.Types.First()).ResultType;
|
||||||
var a = arguments[2];
|
var a = arguments[2];
|
||||||
return f0.Evaluate(c, new Constant(resultType, f1.Evaluate(c, a)));
|
return f0.Evaluate(c, new Constant(resultType, f1.Evaluate(c, a)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,12 @@ namespace AspectedRouting.Language.Functions
|
||||||
"" +
|
"" +
|
||||||
"Consider the mapping `{'someKey':'someValue'}`. Under normal circumstances, this acts as a pointwise-function, converting the string `someKey` into `someValue`, just like an ordinary dictionary would do. " +
|
"Consider the mapping `{'someKey':'someValue'}`. Under normal circumstances, this acts as a pointwise-function, converting the string `someKey` into `someValue`, just like an ordinary dictionary would do. " +
|
||||||
"However, in the context of `mustMatch`, we would prefer this to act as a _check_, that the highway _has_ a key `someKey` which is `someValue`, thus acting as " +
|
"However, in the context of `mustMatch`, we would prefer this to act as a _check_, that the highway _has_ a key `someKey` which is `someValue`, thus acting as " +
|
||||||
"`{'someKey': {'$eq':'someValue'}}`. " +
|
"`{'someKey': {'$eq':'someValue'}}. " +
|
||||||
"Both behaviours are automatically supported in parsing, by parsing all string as `(eitherFunc id eq) 'someValue'`. " +
|
"Both behaviours are automatically supported in parsing, by parsing the string as `(eitherFunc id eq) 'someValue'`. " +
|
||||||
"The type system is then able to figure out which implementation is needed an discards the unneeded implementations.\n\n" +
|
"The type system is then able to figure out which implementation is needed.\n\n" +
|
||||||
"Disclaimer: _you should never ever need this in your profiles_";
|
"Disclaimer: _you should never ever need this in your profiles_";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "f", "g", "a" };
|
public override List<string> ArgNames { get; } = new List<string>{"f","g","a"};
|
||||||
private static Var a = new Var("a");
|
private static Var a = new Var("a");
|
||||||
private static Var b = new Var("b");
|
private static Var b = new Var("b");
|
||||||
private static Var c = new Var("c");
|
private static Var c = new Var("c");
|
||||||
|
@ -53,7 +53,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object Evaluate(Context _, params IExpression[] arguments)
|
public override object Evaluate(Context _,params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("EitherFunc not sufficiently specialized");
|
throw new ArgumentException("EitherFunc not sufficiently specialized");
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,8 @@ using AspectedRouting.Language.Typ;
|
||||||
namespace AspectedRouting.Language.Functions
|
namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public class Eq : Function
|
public class Eq : Function
|
||||||
{
|
{ public override string Description { get; } = "Returns 'yes' if both values _are_ the same";
|
||||||
public override string Description { get; } = "Returns 'yes' if both values _are_ the same";
|
public override List<string> ArgNames { get; } = new List<string>{"a","b"};
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "a", "b" };
|
|
||||||
public Eq() : base("eq", true,
|
public Eq() : base("eq", true,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,25 +8,22 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public class FirstMatchOf : Function
|
public class FirstMatchOf : Function
|
||||||
{
|
{
|
||||||
public override string Description { get; } = "This higher-order function takes a list of keys, a mapping (function over tags) and a collection of tags." +
|
public override string Description { get; } = "This higherorder function takes a list of keys, a mapping (function over tags) and a collection of tags. It will try the function for the first key (and it's respective value). If the function fails (it gives null), it'll try the next key.\n\n" +
|
||||||
"It will try the function for the first key (and it's respective value). If the function fails (it gives null), it'll try the next key.\n\n" +
|
"E.g. `$firstMatchOf ['maxspeed','highway'] {'maxspeed' --> $parse, 'highway' --> {residential --> 30, tertiary --> 50}}` applied on `{maxspeed=70, highway=tertiary}` will yield `70` as that is the first key in the list; `{highway=residential}` will yield `30`.";
|
||||||
"E.g. `$firstMatchOf ['maxspeed','highway'] {'maxspeed' --> $parse, 'highway' --> {residential --> 30, tertiary --> 50}}` applied on `{maxspeed=70, highway=tertiary}`" +
|
public override List<string> ArgNames { get; } = new List<string> {"s"};
|
||||||
" will yield `70` as that is the first key in the list; `{highway=residential}` will yield `30`.";
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "s" };
|
|
||||||
|
|
||||||
public FirstMatchOf() : base("first_match_of", true,
|
public FirstMatchOf() : base("first_match_of", true,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
// [String] -> (Tags -> [a]) -> Tags -> a
|
// [String] -> (Tags -> [a]) -> Tags -> a
|
||||||
Curry.ConstructFrom(
|
Curry.ConstructFrom(new Var("a"), // Result type on top!
|
||||||
new Var("a"), // Result type on top!
|
|
||||||
new ListType(Typs.String),
|
new ListType(Typs.String),
|
||||||
new Curry(Typs.Tags, new ListType(new Var("a"))),
|
new Curry(Typs.Tags, new ListType(new Var("a"))),
|
||||||
Typs.Tags
|
Typs.Tags
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
Funcs.AddBuiltin(this, "firstMatchOf");
|
Funcs.AddBuiltin( this,"firstMatchOf");
|
||||||
}
|
}
|
||||||
|
|
||||||
private FirstMatchOf(IEnumerable<Type> types) : base("first_match_of", types)
|
private FirstMatchOf(IEnumerable<Type> types) : base("first_match_of", types)
|
||||||
|
@ -46,7 +43,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var order = ((IEnumerable<object>)arguments[0].Evaluate(c))
|
var order = ((IEnumerable<object>) arguments[0].Evaluate(c))
|
||||||
.Select(o =>
|
.Select(o =>
|
||||||
{
|
{
|
||||||
if (o is string s)
|
if (o is string s)
|
||||||
|
@ -55,11 +52,11 @@ namespace AspectedRouting.Language.Functions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (string)((IExpression)o).Evaluate(c);
|
return (string) ((IExpression) o).Evaluate(c);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var function = arguments[1];
|
var function = arguments[1];
|
||||||
var tags = (Dictionary<string, string>)arguments[2].Evaluate(c);
|
var tags = (Dictionary<string, string>) arguments[2].Evaluate(c);
|
||||||
|
|
||||||
var singletonDict = new Dictionary<string, string>();
|
var singletonDict = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
@ -75,7 +72,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((List<object>)result).First();
|
return ((List<object>) result).First();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -15,38 +15,32 @@ namespace AspectedRouting.Language.Functions
|
||||||
new Curry(new Var("b"), new ListType(new Var("a"))),
|
new Curry(new Var("b"), new ListType(new Var("a"))),
|
||||||
new Curry(new Var("b"), new Var("a")))
|
new Curry(new Var("b"), new Var("a")))
|
||||||
}
|
}
|
||||||
)
|
) { }
|
||||||
{ }
|
|
||||||
|
|
||||||
private HeadFunction(IEnumerable<Type> unified) : base("head", unified) { }
|
private HeadFunction(IEnumerable<Type> unified) : base("head", unified) { }
|
||||||
|
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Select the first non-null value of a list; returns 'null' on empty list or on null";
|
"Select the first non-null value of a list; returns 'null' on empty list or on null";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "ls" };
|
public override List<string> ArgNames { get; } = new List<string> {"ls"};
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
object o = arguments[0];
|
object o = arguments[0];
|
||||||
if (o is Apply app)
|
if (o is Apply app) {
|
||||||
{
|
|
||||||
o = app.Evaluate(c, arguments.SubArray(1));
|
o = app.Evaluate(c, arguments.SubArray(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (o is IExpression e)
|
while (o is IExpression e) {
|
||||||
{
|
|
||||||
o = e.Evaluate(c);
|
o = e.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(o is IEnumerable<object> ls))
|
if (!(o is IEnumerable<object> ls)) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var v in ls)
|
foreach (var v in ls) {
|
||||||
{
|
if (v != null) {
|
||||||
if (v != null)
|
|
||||||
{
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +51,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
||||||
{
|
{
|
||||||
var unified = Types.SpecializeTo(allowedTypes);
|
var unified = Types.SpecializeTo(allowedTypes);
|
||||||
if (unified == null)
|
if (unified == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,8 @@ using AspectedRouting.Language.Typ;
|
||||||
namespace AspectedRouting.Language.Functions
|
namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
public class Id : Function
|
public class Id : Function
|
||||||
{
|
{ public override string Description { get; } = "Returns the argument unchanged - the identity function. Seems useless at first sight, but useful in parsing";
|
||||||
public override string Description { get; } = "Returns the argument unchanged - the identity function. Seems useless at first sight, but useful in parsing";
|
public override List<string> ArgNames { get; } = new List<string>{"a"};
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "a" };
|
|
||||||
public Id() : base("id", true,
|
public Id() : base("id", true,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
|
@ -32,9 +31,9 @@ namespace AspectedRouting.Language.Functions
|
||||||
return new Id(unified);
|
return new Id(unified);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c,params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
return arguments[0].Evaluate(c, arguments.ToList().GetRange(1, arguments.Length - 1).ToArray());
|
return arguments[0].Evaluate(c,arguments.ToList().GetRange(1, arguments.Length-1).ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,10 +10,9 @@ namespace AspectedRouting.Language.Functions
|
||||||
private static Var b = new Var("b");
|
private static Var b = new Var("b");
|
||||||
|
|
||||||
public override string Description { get; } = "Selects either one of the branches, depending on the condition." +
|
public override string Description { get; } = "Selects either one of the branches, depending on the condition." +
|
||||||
" The 'then' branch is returned if the condition returns the string `yes` or `true`." +
|
" The 'then' branch is returned if the condition returns the string `yes` or `true`. Otherwise, the `else` branch is taken (including if the condition returns `null`)" +
|
||||||
" Otherwise, the `else` branch is taken (including if the condition returns `null`)" +
|
"If the `else` branch is not set, `null` is returned in the condition is false.";
|
||||||
"If the `else` branch is not set, `null` is returned if the condition evaluates to false.";
|
public override List<string> ArgNames { get; } = new List<string> {"condition", "then", "else"};
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "condition", "then", "else" };
|
|
||||||
|
|
||||||
public If() : base("if_then_else", true,
|
public If() : base("if_then_else", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -34,7 +33,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var condition = arguments[0].Evaluate(c);
|
var condition = arguments[0].Evaluate(c);
|
||||||
var then = arguments[1];
|
var then = arguments[1];
|
||||||
IExpression @else = null;
|
IExpression @else = null;
|
||||||
if (arguments.Length > 2)
|
if (arguments.Length > 2)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AspectedRouting.Language.Expression;
|
using AspectedRouting.Language.Expression;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
using Type = AspectedRouting.Language.Typ.Type;
|
|
||||||
|
|
||||||
namespace AspectedRouting.Language.Functions
|
namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
|
@ -10,34 +8,34 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
private static Var a = new Var("a");
|
private static Var a = new Var("a");
|
||||||
private static Var b = new Var("b");
|
private static Var b = new Var("b");
|
||||||
|
|
||||||
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" +
|
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" +
|
"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." +
|
"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`" +
|
" 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." +
|
"If the `else` branch is not set, `null` is returned in the condition is false." +
|
||||||
"In case the condition returns 'null', then the 'else'-branch is taken.";
|
"In case the condition returns 'null', then the 'else'-branch is taken.";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "condition", "then", "else" };
|
public override List<string> ArgNames { get; } = new List<string> {"condition", "then", "else"};
|
||||||
|
|
||||||
public IfDotted() : base("if_then_else_dotted", true,
|
public IfDotted() : base("if_then_else_dotted", true,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
|
|
||||||
Curry.ConstructFrom(a,
|
Curry.ConstructFrom(a,
|
||||||
new Curry(b, Typs.Bool),
|
new Curry(b, Typs.Bool),
|
||||||
new Curry(b, a),
|
new Curry(b, a),
|
||||||
b),
|
b),
|
||||||
Curry.ConstructFrom(a,
|
Curry.ConstructFrom(a,
|
||||||
new Curry(b, Typs.String),
|
new Curry(b, Typs.String),
|
||||||
new Curry(b, a),
|
new Curry(b, a),
|
||||||
b),
|
b),
|
||||||
Curry.ConstructFrom(a,
|
Curry.ConstructFrom(a,
|
||||||
new Curry(b, Typs.Bool),
|
new Curry(b, Typs.Bool),
|
||||||
new Curry(b, a),
|
new Curry(b, a),
|
||||||
new Curry(b, a),
|
new Curry(b, a),
|
||||||
b),
|
b),
|
||||||
Curry.ConstructFrom(a,
|
Curry.ConstructFrom(a,
|
||||||
new Curry(b, Typs.String),
|
new Curry(b, Typs.String),
|
||||||
new Curry(b, a),
|
new Curry(b, a),
|
||||||
new Curry(b, a),
|
new Curry(b, a),
|
||||||
|
@ -55,18 +53,18 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var conditionfunc = arguments[0];
|
var conditionfunc = arguments[0];
|
||||||
var thenfunc = arguments[1];
|
var thenfunc = arguments[1];
|
||||||
IExpression elsefunc = null;
|
IExpression elsefunc = null;
|
||||||
IExpression argument = arguments[2];
|
IExpression argument = arguments[2];
|
||||||
|
|
||||||
if (arguments.Length == 4)
|
if (arguments.Length == 4)
|
||||||
{
|
{
|
||||||
elsefunc = arguments[2];
|
elsefunc = arguments[2];
|
||||||
argument = arguments[3];
|
argument = arguments[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
var condition = ((IExpression)conditionfunc).Apply(argument).Evaluate(c);
|
var condition = ((IExpression) conditionfunc).Apply(argument).Evaluate(c);
|
||||||
|
|
||||||
if (condition != null && (condition.Equals("yes") || condition.Equals("true") || condition.Equals(true)))
|
if (condition != null && (condition.Equals("yes") || condition.Equals("true") || condition.Equals(true)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public class Inv : Function
|
public class Inv : Function
|
||||||
{
|
{
|
||||||
public override string Description { get; } = "Calculates `1/d`";
|
public override string Description { get; } = "Calculates `1/d`";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "d" };
|
public override List<string> ArgNames { get; } = new List<string> {"d"};
|
||||||
|
|
||||||
public Inv() : base("inv", true, new[]
|
public Inv() : base("inv", true, new[]
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var arg = (double)arguments[0].Evaluate(c);
|
var arg = (double) arguments[0].Evaluate(c);
|
||||||
return 1 / arg;
|
return 1 / arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
"Listdot takes a list of functions `[f, g, h]` and and an argument `a`. It applies the argument on every single function." +
|
"Listdot takes a list of functions `[f, g, h]` and and an argument `a`. It applies the argument on every single function." +
|
||||||
"It conveniently lifts the argument out of the list.";
|
"It conveniently lifts the argument out of the list.";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "list", "a" };
|
public override List<string> ArgNames { get; } = new List<string>{"list","a"};
|
||||||
|
|
||||||
public ListDot() : base("listDot", true,
|
public ListDot() : base("listDot", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -32,7 +32,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var listOfFuncs = (IEnumerable<IExpression>)arguments[0].Evaluate(c);
|
var listOfFuncs = (IEnumerable<IExpression>) arguments[0].Evaluate(c);
|
||||||
var arg = arguments[1];
|
var arg = arguments[1];
|
||||||
|
|
||||||
var result = new List<object>();
|
var result = new List<object>();
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
|
|
||||||
var newFunctions = new Dictionary<string, IExpression>();
|
var newFunctions = new Dictionary<string, IExpression>();
|
||||||
var functionType = unified.Select(c => ((Curry)c).ResultType);
|
var functionType = unified.Select(c => ((Curry) c).ResultType);
|
||||||
var enumerable = functionType.ToList();
|
var enumerable = functionType.ToList();
|
||||||
|
|
||||||
foreach (var (k, expr) in StringToResultFunctions)
|
foreach (var (k, expr) in StringToResultFunctions)
|
||||||
|
@ -79,42 +79,40 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
|
|
||||||
var s = arguments[0].Evaluate(c);
|
var s = arguments[0].Evaluate(c);
|
||||||
while (s is Constant constant)
|
while (s is Constant constant)
|
||||||
{
|
{
|
||||||
s = constant.Evaluate(c);
|
s = constant.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var key = (string) s;
|
||||||
var key = (string)s;
|
|
||||||
var otherARgs = arguments.ToList().GetRange(1, arguments.Length - 1);
|
var otherARgs = arguments.ToList().GetRange(1, arguments.Length - 1);
|
||||||
if (!StringToResultFunctions.ContainsKey(key))
|
if (!StringToResultFunctions.ContainsKey(key)) { // This is really roundabout, but it has to be
|
||||||
{ // This is really roundabout, but it has to be
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultFunction = StringToResultFunctions[key];
|
var resultFunction = StringToResultFunctions[key];
|
||||||
if (resultFunction == null)
|
if (resultFunction == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultFunction.Evaluate(c, otherARgs.ToArray());
|
return resultFunction.Evaluate(c, otherARgs.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IExpression Optimize(out bool somethingChanged)
|
public override IExpression Optimize()
|
||||||
{
|
{
|
||||||
var optimizedFunctions = new Dictionary<string, IExpression>();
|
var optimizedFunctions = new Dictionary<string, IExpression>();
|
||||||
somethingChanged = false;
|
|
||||||
foreach (var (k, e) in StringToResultFunctions)
|
foreach (var (k, e) in StringToResultFunctions)
|
||||||
{
|
{
|
||||||
var opt = e.Optimize(out var sc);
|
var opt = e.Optimize();
|
||||||
somethingChanged |= sc;
|
|
||||||
|
var typeOptStr = string.Join(";", opt.Types);
|
||||||
|
var typeEStr = string.Join("; ", e.Types);
|
||||||
if (!opt.Types.Any())
|
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: " +
|
throw new NullReferenceException($"Optimized version is null, has different or empty types: " +
|
||||||
$"\n{typeEStr}" +
|
$"\n{typeEStr}" +
|
||||||
$"\n{typeOptStr}");
|
$"\n{typeOptStr}");
|
||||||
|
@ -123,13 +121,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
optimizedFunctions[k] = opt;
|
optimizedFunctions[k] = opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!somethingChanged)
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Mapping(optimizedFunctions);
|
return new Mapping(optimizedFunctions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mapping Construct(params (string key, IExpression e)[] exprs)
|
public static Mapping Construct(params (string key, IExpression e)[] exprs)
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Returns the biggest value in the list. For a list of booleans, this acts as 'or'";
|
"Returns the biggest value in the list. For a list of booleans, this acts as 'or'";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "list" };
|
public override List<string> ArgNames { get; } = new List<string> {"list"};
|
||||||
|
|
||||||
public Max() : base("max", true,
|
public Max() : base("max", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -45,7 +45,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var ls = ((IEnumerable<object>)arguments[0].Evaluate(c)).Where(o => o != null);
|
var ls = ((IEnumerable<object>) arguments[0].Evaluate(c)).Where(o => o != null);
|
||||||
|
|
||||||
var expectedType = (Types.First() as Curry).ResultType;
|
var expectedType = (Types.First() as Curry).ResultType;
|
||||||
switch (expectedType)
|
switch (expectedType)
|
||||||
|
|
|
@ -13,8 +13,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
new Curry(Typs.Tags, Typs.Bool),
|
new Curry(Typs.Tags, Typs.Bool),
|
||||||
new Curry(Typs.Tags, Typs.Bool))
|
new Curry(Typs.Tags, Typs.Bool))
|
||||||
}
|
}
|
||||||
)
|
) { }
|
||||||
{ }
|
|
||||||
|
|
||||||
public MemberOf(IEnumerable<Type> types) : base("memberOf", types) { }
|
public MemberOf(IEnumerable<Type> types) : base("memberOf", types) { }
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
" a flag `_relation:<aspect_name>=\"yes\"` will be set if the aspect matches on every way for where this aspect matches.\n" +
|
" a flag `_relation:<aspect_name>=\"yes\"` will be set if the aspect matches on every way for where this aspect matches.\n" +
|
||||||
"However, this plays poorly with parameters (e.g.: what if we want to cycle over a highway which is part of a certain cycling network with a certain `#network_name`?) " +
|
"However, this plays poorly with parameters (e.g.: what if we want to cycle over a highway which is part of a certain cycling network with a certain `#network_name`?) " +
|
||||||
"Luckily, parameters can only be simple values. To work around this problem, an extra tag is introduced for _every single profile_:" +
|
"Luckily, parameters can only be simple values. To work around this problem, an extra tag is introduced for _every single profile_:" +
|
||||||
"`_relation:<profile_name>:<aspect_name>=yes'. The subfunction is thus executed `countOf(relations) * countOf(profiles)` time, yielding `countOf(profiles)` tags." +
|
"`_relation:<profile_name>:<aspect_name>=yes'. The subfunction is thus executed `countOr(relations) * countOf(profiles)` time, yielding `countOf(profiles)` tags." +
|
||||||
" The profile function then picks the tags for himself and strips the `<profile_name>:` away from the key.\n\n" +
|
" The profile function then picks the tags for himself and strips the `<profile_name>:` away from the key.\n\n" +
|
||||||
"\n\n" +
|
"\n\n" +
|
||||||
"In the test.csv, one can simply use `_relation:<aspect_name>=yes` to mimic relations in your tests";
|
"In the test.csv, one can simply use `_relation:<aspect_name>=yes` to mimic relations in your tests";
|
||||||
|
@ -40,43 +39,34 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var tags = (Dictionary<string, string>)arguments[1].Evaluate(c);
|
var tags = (Dictionary<string, string>) arguments[1].Evaluate(c);
|
||||||
var name = c.AspectName.TrimStart('$');
|
var name = c.AspectName.TrimStart('$');
|
||||||
|
|
||||||
if (tags.TryGetValue("_relation:" + name, out var v))
|
if (tags.TryGetValue("_relation:" + name, out var v)) {
|
||||||
{
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the case of tests, relations might be added with "_relation:1:<key>"
|
// In the case of tests, relations might be added with "_relation:1:<key>"
|
||||||
// So, we create this table as dictionary
|
// So, we create this table as dictionary
|
||||||
var relationTags = new Dictionary<string, Dictionary<string, string>>();
|
var relationTags = new Dictionary<string, Dictionary<string, string>>();
|
||||||
foreach (var tag in tags)
|
foreach (var tag in tags) {
|
||||||
{
|
if (tag.Key.StartsWith("_relation:")) {
|
||||||
if (!tag.Key.StartsWith("_relation:"))
|
var keyParts = tag.Key.Split(":");
|
||||||
{
|
if (keyParts.Length != 3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var relationName = keyParts[1];
|
||||||
|
if (!relationTags.ContainsKey(relationName)) {
|
||||||
|
relationTags.Add(relationName, new Dictionary<string, string>());
|
||||||
|
}
|
||||||
|
|
||||||
var keyParts = tag.Key.Split(":");
|
relationTags[relationName].Add(keyParts[2], tag.Value);
|
||||||
if (keyParts.Length != 3)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
var relationName = keyParts[1];
|
|
||||||
if (!relationTags.ContainsKey(relationName))
|
|
||||||
{
|
|
||||||
relationTags.Add(relationName, new Dictionary<string, string>());
|
|
||||||
}
|
|
||||||
|
|
||||||
relationTags[relationName].Add(keyParts[2], tag.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var relationTagging in relationTags)
|
foreach (var relationTagging in relationTags) {
|
||||||
{
|
|
||||||
var result = arguments[0].Evaluate(c, new Constant(relationTagging.Value));
|
var result = arguments[0].Evaluate(c, new Constant(relationTagging.Value));
|
||||||
if (result.Equals("yes"))
|
if (result.Equals("yes")) {
|
||||||
{
|
|
||||||
return "yes";
|
return "yes";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,8 +77,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
||||||
{
|
{
|
||||||
var unified = Types.SpecializeTo(allowedTypes);
|
var unified = Types.SpecializeTo(allowedTypes);
|
||||||
if (unified == null)
|
if (unified == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Out of a list of values, gets the smallest value. In case of a list of bools, this acts as `and`. Note that 'null'-values are ignored.";
|
"Out of a list of values, gets the smallest value. In case of a list of bools, this acts as `and`. Note that 'null'-values are ignored.";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "list" };
|
public override List<string> ArgNames { get; } = new List<string> {"list"};
|
||||||
|
|
||||||
public Min() : base("min", true,
|
public Min() : base("min", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -44,8 +44,8 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var ls = ((IEnumerable<object>)arguments[0].Evaluate(c)).Where(o => o != null);
|
var ls = ((IEnumerable<object>) arguments[0].Evaluate(c)).Where(o => o != null);
|
||||||
var expectedType = ((Curry)Types.First()).ResultType;
|
var expectedType = ((Curry) Types.First()).ResultType;
|
||||||
|
|
||||||
switch (expectedType)
|
switch (expectedType)
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
o = e.Evaluate(c);
|
o = e.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (double)o;
|
return (double) o;
|
||||||
}).Min();
|
}).Min();
|
||||||
default:
|
default:
|
||||||
return ls.Select(o =>
|
return ls.Select(o =>
|
||||||
|
@ -77,7 +77,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
o = e.Evaluate(c);
|
o = e.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)o;
|
return (int) o;
|
||||||
}).Min();
|
}).Min();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override string Description { get; } =
|
public override string Description { get; } =
|
||||||
"Multiplies all the values in a given list. On a list of booleans, this acts as 'and' or 'all', as `false` and `no` are interpreted as zero. Null values are ignored and thus considered to be `one`";
|
"Multiplies all the values in a given list. On a list of booleans, this acts as 'and' or 'all', as `false` and `no` are interpreted as zero. Null values are ignored and thus considered to be `one`";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "list" };
|
public override List<string> ArgNames { get; } = new List<string> {"list"};
|
||||||
|
|
||||||
|
|
||||||
public Multiply() : base("multiply", true,
|
public Multiply() : base("multiply", true,
|
||||||
|
@ -43,8 +43,8 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var ls = ((IEnumerable<object>)arguments[0].Evaluate(c)).Where(o => o != null);
|
var ls = ((IEnumerable<object>) arguments[0].Evaluate(c)).Where(o => o != null);
|
||||||
var expectedType = ((Curry)Types.First()).ResultType;
|
var expectedType = ((Curry) Types.First()).ResultType;
|
||||||
|
|
||||||
|
|
||||||
switch (expectedType)
|
switch (expectedType)
|
||||||
|
@ -81,7 +81,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
o = e.Evaluate(c);
|
o = e.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
mult *= (double)o;
|
mult *= (double) o;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mult;
|
return mult;
|
||||||
|
@ -95,7 +95,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
o = e.Evaluate(c);
|
o = e.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
multI *= (int)o;
|
multI *= (int) o;
|
||||||
}
|
}
|
||||||
|
|
||||||
return multI;
|
return multI;
|
||||||
|
|
|
@ -42,8 +42,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
public override IExpression Specialize(IEnumerable<Type> allowedTypes)
|
||||||
{
|
{
|
||||||
var unified = Types.SpecializeTo(allowedTypes);
|
var unified = Types.SpecializeTo(allowedTypes);
|
||||||
if (unified == null)
|
if (unified == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,50 +51,43 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var neededKeys = (IEnumerable<object>)arguments[0].Evaluate(c);
|
var neededKeys = (IEnumerable<object>) arguments[0].Evaluate(c);
|
||||||
var function = arguments[1];
|
var function = arguments[1];
|
||||||
|
|
||||||
var tags = (Dictionary<string, string>)arguments[2].Evaluate(c);
|
var tags = (Dictionary<string, string>) arguments[2].Evaluate(c);
|
||||||
|
|
||||||
foreach (var oo in neededKeys)
|
foreach (var oo in neededKeys) {
|
||||||
{
|
|
||||||
var o = oo;
|
var o = oo;
|
||||||
while (o is IExpression e)
|
while (o is IExpression e) {
|
||||||
{
|
|
||||||
o = e.Evaluate(c);
|
o = e.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(o is string tagKey))
|
if (!(o is string tagKey)) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tags.ContainsKey(tagKey))
|
if (!tags.ContainsKey(tagKey)) {
|
||||||
{
|
|
||||||
// A required key is missing
|
// A required key is missing
|
||||||
// Normally, we return no; but there is a second chance
|
// Normally, we return no; but there is a second chance
|
||||||
// IF the mapping returns 'yes' on null, we make an exception and ignore it
|
// IF the mapping returns 'yes' on null, we make an exception and ignore it
|
||||||
var applied = function.Evaluate(c, new Constant(new Dictionary<string, string> {
|
var applied = function.Evaluate(c, new Constant(new Dictionary<string, string> {
|
||||||
{tagKey, ""}
|
{tagKey, ""}
|
||||||
}));
|
}));
|
||||||
if (applied == null)
|
if (applied == null) {
|
||||||
{
|
|
||||||
return "no";
|
return "no";
|
||||||
}
|
}
|
||||||
if (applied.Equals("yes") || (applied is IEnumerable<object> l && l.Count() > 0 && l.ToList()[0].Equals("yes")))
|
if (applied.Equals("yes") || (applied is IEnumerable<object> l && l.Count() > 0 && l.ToList()[0].Equals("yes")) ) {
|
||||||
{
|
|
||||||
continue; // We ignore the absence of the key
|
continue; // We ignore the absence of the key
|
||||||
}
|
}
|
||||||
return "no";
|
return "no";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = (IEnumerable<object>)function.Evaluate(c, new Constant(tags));
|
var result = (IEnumerable<object>) function.Evaluate(c, new Constant(tags));
|
||||||
|
|
||||||
if (result.Any(o =>
|
if (result.Any(o =>
|
||||||
o == null ||
|
o == null ||
|
||||||
o is string s && (s.Equals("no") || s.Equals("false"))))
|
o is string s && (s.Equals("no") || s.Equals("false")))) {
|
||||||
{
|
|
||||||
// The mapped function is executed. If the mapped function gives 'no', null or 'false' for any value, "no" is returned
|
// The mapped function is executed. If the mapped function gives 'no', null or 'false' for any value, "no" is returned
|
||||||
return "no";
|
return "no";
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,14 @@ namespace AspectedRouting.Language.Functions
|
||||||
public class NotEq : Function
|
public class NotEq : Function
|
||||||
{
|
{
|
||||||
public override string Description { get; } = "OVerloaded function, either boolean not or returns 'yes' if the two passed in values are _not_ the same;";
|
public override string Description { get; } = "OVerloaded function, either boolean not or returns 'yes' if the two passed in values are _not_ the same;";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "a", "b" };
|
public override List<string> ArgNames { get; } = new List<string> {"a", "b"};
|
||||||
|
|
||||||
public NotEq() : base("notEq", true,
|
public NotEq() : base("notEq", true,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
Curry.ConstructFrom(Typs.Bool, new Var("a"), new Var("a")),
|
Curry.ConstructFrom(Typs.Bool, new Var("a"), new Var("a")),
|
||||||
Curry.ConstructFrom(Typs.String, new Var("a"), new Var("a")),
|
Curry.ConstructFrom(Typs.String, new Var("a"), new Var("a")),
|
||||||
new Curry(Typs.Bool, Typs.Bool),
|
new Curry(Typs.Bool, Typs.Bool),
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
Funcs.AddBuiltin(this, "not");
|
Funcs.AddBuiltin(this, "not");
|
||||||
|
@ -43,7 +43,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
var booleanArg = arguments[0].Evaluate(c);
|
var booleanArg = arguments[0].Evaluate(c);
|
||||||
return booleanArg.Equals("no");
|
return booleanArg.Equals("no");
|
||||||
}
|
}
|
||||||
|
|
||||||
var arg0 = arguments[0].Evaluate(c);
|
var arg0 = arguments[0].Evaluate(c);
|
||||||
var arg1 = arguments[1].Evaluate(c);
|
var arg1 = arguments[1].Evaluate(c);
|
||||||
if ((!(arg0?.Equals(arg1) ?? false)))
|
if ((!(arg0?.Equals(arg1) ?? false)))
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public Parameter(string s)
|
public Parameter(string s)
|
||||||
{
|
{
|
||||||
Types = new[] { new Var("parameter") };
|
Types = new[] {new Var("parameter") };
|
||||||
ParamName = s;
|
ParamName = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
{
|
{
|
||||||
var paramName = ParamName.TrimStart('#'); // context saves paramnames without '#'
|
var paramName = ParamName.TrimStart('#'); // context saves paramnames without '#'
|
||||||
var value = c?.Parameters?.GetValueOrDefault(paramName, null);
|
var value = c?.Parameters?.GetValueOrDefault(paramName, null);
|
||||||
if (value is Constant constant)
|
if(value is Constant constant)
|
||||||
{
|
{
|
||||||
return constant.Evaluate(c);
|
return constant.Evaluate(c);
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,6 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public IExpression Specialize(IEnumerable<Type> allowedTypes)
|
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);
|
var unified = Types.SpecializeTo(allowedTypes);
|
||||||
if (unified == null)
|
if (unified == null)
|
||||||
{
|
{
|
||||||
|
@ -50,24 +45,22 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
return new Parameter(unified, ParamName);
|
return new Parameter(unified, ParamName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
public IExpression PruneTypes(System.Func<Type, bool> allowedTypes)
|
||||||
{
|
{
|
||||||
var passedTypes = this.Types.Where(allowedTypes);
|
var passedTypes = this.Types.Where(allowedTypes);
|
||||||
if (!passedTypes.Any())
|
if (!passedTypes.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Parameter(passedTypes, this.ParamName);
|
return new Parameter(passedTypes, this.ParamName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression Optimize(out bool somethingChanged)
|
public IExpression Optimize()
|
||||||
{
|
{
|
||||||
somethingChanged = false;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExpression OptimizeWithArgument(IExpression arg)
|
public IExpression OptimizeWithArgument(IExpression arg)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Trying to invoke a parameter");
|
throw new NotSupportedException("Trying to invoke a parameter");
|
||||||
|
@ -78,26 +71,9 @@ namespace AspectedRouting.Language.Functions
|
||||||
f(this);
|
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()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return ParamName;
|
return ParamName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public class Parse : Function
|
public class Parse : Function
|
||||||
{
|
{
|
||||||
public override string Description { get; } = "Parses a string into a numerical value. Returns 'null' if parsing fails or no input is given. If a duration is given (e.g. `01:15`), then the number of minutes (75) is returned";
|
public override string Description { get; } = "Parses a string into a numerical value. Returns 'null' if parsing fails or no input is given. If a duration is given (e.g. `01:15`), then the number of minutes (75) is returned";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "s" };
|
public override List<string> ArgNames { get; } = new List<string>{"s"};
|
||||||
|
|
||||||
public Parse() : base("parse", true,
|
public Parse() : base("parse", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -39,18 +39,18 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var arg = (string)arguments[0].Evaluate(c);
|
var arg = (string) arguments[0].Evaluate(c);
|
||||||
var expectedType = ((Curry)Types.First()).ResultType;
|
var expectedType = ((Curry) Types.First()).ResultType;
|
||||||
|
|
||||||
var duration = Regex.Match(arg, @"^(\d+):(\d+)$");
|
var duration = Regex.Match(arg, @"^(\d+):(\d+)$");
|
||||||
if (duration.Success)
|
if (duration.Success)
|
||||||
{
|
{
|
||||||
// This is a duration of the form 'hh:mm' -> we return the total minute count
|
// This is a duration of the form 'hh:mm' -> we return the total minute count
|
||||||
var hours = int.Parse(duration.Groups[1].Value);
|
var hours = int.Parse(duration.Groups[1].Value);
|
||||||
var minutes = int.Parse(duration.Groups[2].Value);
|
var minutes = int.Parse(duration.Groups[2].Value);
|
||||||
arg = (hours * 60 + minutes).ToString();
|
arg = (hours * 60 + minutes).ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -62,12 +62,12 @@ namespace AspectedRouting.Language.Functions
|
||||||
default: return int.Parse(arg);
|
default: return int.Parse(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Could not parse " + arg + " as " + expectedType);
|
Console.Error.WriteLine("Could not parse " + arg + " as " + expectedType);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
"*stringToTags* converts a function `string -> string -> a` into a function `tags -> [a]`. " +
|
"*stringToTags* converts a function `string -> string -> a` into a function `tags -> [a]`. " +
|
||||||
"It is used internally to convert a hash of functions. `stringToTags` shouldn't be needed when implementing profiles.";
|
"It is used internally to convert a hash of functions. `stringToTags` shouldn't be needed when implementing profiles.";
|
||||||
|
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "f", "tags" };
|
public override List<string> ArgNames { get; } = new List<string> {"f", "tags"};
|
||||||
|
|
||||||
private static readonly Type _baseFunction =
|
private static readonly Type _baseFunction =
|
||||||
Curry.ConstructFrom(new Var("a"), Typs.String, Typs.String);
|
Curry.ConstructFrom(new Var("a"), Typs.String, Typs.String);
|
||||||
|
@ -33,9 +33,8 @@ namespace AspectedRouting.Language.Functions
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var f = arguments[0];
|
var f = arguments[0];
|
||||||
var tags = (Dictionary<string, string>)arguments[1].Evaluate(c);
|
var tags = (Dictionary<string, string>) arguments[1].Evaluate(c);
|
||||||
if (tags == null)
|
if (tags == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var result = new List<object>();
|
var result = new List<object>();
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
public class Sum : Function
|
public class Sum : Function
|
||||||
{
|
{
|
||||||
public override string Description { get; } = "Sums all the numbers in the given list. If the list is a list of booleans, `yes` or `true` will be considered to equal `1`. Null values are ignored (and thus handled as being `0`)";
|
public override string Description { get; } = "Sums all the numbers in the given list. If the list is a list of booleans, `yes` or `true` will be considered to equal `1`. Null values are ignored (and thus handled as being `0`)";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "list" };
|
public override List<string> ArgNames { get; } = new List<string>{"list"};
|
||||||
|
|
||||||
public Sum() : base("sum", true,
|
public Sum() : base("sum", true,
|
||||||
new[]
|
new[]
|
||||||
|
@ -17,7 +17,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
new Curry(new ListType(Typs.Int), Typs.Int),
|
new Curry(new ListType(Typs.Int), Typs.Int),
|
||||||
new Curry(new ListType(Typs.PDouble), Typs.PDouble),
|
new Curry(new ListType(Typs.PDouble), Typs.PDouble),
|
||||||
new Curry(new ListType(Typs.Double), Typs.Double),
|
new Curry(new ListType(Typs.Double), Typs.Double),
|
||||||
new Curry(new ListType(Typs.Bool), Typs.Int),
|
new Curry(new ListType(Typs.Bool), Typs.Int),
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
Funcs.AddBuiltin(this, "plus");
|
Funcs.AddBuiltin(this, "plus");
|
||||||
|
@ -44,15 +44,15 @@ namespace AspectedRouting.Language.Functions
|
||||||
|
|
||||||
public override object Evaluate(Context c, params IExpression[] arguments)
|
public override object Evaluate(Context c, params IExpression[] arguments)
|
||||||
{
|
{
|
||||||
var ls = ((IEnumerable<object>)arguments[0]
|
var ls = ((IEnumerable<object>) arguments[0]
|
||||||
.Evaluate(c))
|
.Evaluate(c))
|
||||||
.Where(o => o != null);
|
.Where(o => o!=null);
|
||||||
var expectedType = (Types.First() as Curry).ResultType;
|
var expectedType = (Types.First() as Curry).ResultType;
|
||||||
|
|
||||||
switch (expectedType)
|
switch (expectedType)
|
||||||
{
|
{
|
||||||
case BoolType _:
|
case BoolType _:
|
||||||
var sumB = 0;
|
var sumB= 0;
|
||||||
foreach (var o in ls)
|
foreach (var o in ls)
|
||||||
{
|
{
|
||||||
if (o.Equals("yes") || o.Equals("true"))
|
if (o.Equals("yes") || o.Equals("true"))
|
||||||
|
@ -67,7 +67,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
var sum = 0.0;
|
var sum = 0.0;
|
||||||
foreach (var o in ls)
|
foreach (var o in ls)
|
||||||
{
|
{
|
||||||
sum += (double)o;
|
sum += (double) o;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
|
@ -75,7 +75,7 @@ namespace AspectedRouting.Language.Functions
|
||||||
var sumI = 1;
|
var sumI = 1;
|
||||||
foreach (var o in ls)
|
foreach (var o in ls)
|
||||||
{
|
{
|
||||||
sumI += (int)o;
|
sumI += (int) o;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sumI;
|
return sumI;
|
||||||
|
|
|
@ -7,10 +7,10 @@ namespace AspectedRouting.Language.Functions
|
||||||
public class ToString : Function
|
public class ToString : Function
|
||||||
{
|
{
|
||||||
public override string Description { get; } = "Converts a value into a human readable string";
|
public override string Description { get; } = "Converts a value into a human readable string";
|
||||||
public override List<string> ArgNames { get; } = new List<string> { "obj" };
|
public override List<string> ArgNames { get; } = new List<string>{"obj"};
|
||||||
|
|
||||||
public ToString() : base("to_string", true,
|
public ToString() : base("to_string", true,
|
||||||
new[] { new Curry(new Var("a"), Typs.String) })
|
new[] {new Curry(new Var("a"), Typs.String)})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.Language.Functions;
|
using AspectedRouting.Language.Functions;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
|
@ -32,83 +31,58 @@ namespace AspectedRouting.Language
|
||||||
/// Optimize a single expression, eventually recursively (e.g. a list can optimize all the contents)
|
/// Optimize a single expression, eventually recursively (e.g. a list can optimize all the contents)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IExpression Optimize(out bool somethingChanged);
|
IExpression Optimize();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Optimize with the given argument, e.g. listdot can become a list of applied arguments.
|
/// Optimize with the given argument, e.g. listdot can become a list of applied arguments.
|
||||||
|
/// By default, this should return 'this.Apply(argument)'
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="argument"></param>
|
/// <param name="argument"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
// IExpression OptimizeWithArgument(IExpression argument);
|
// IExpression OptimizeWithArgument(IExpression argument);
|
||||||
void Visit(Func<IExpression, bool> f);
|
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 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)
|
public static object Run(this IExpression e, Context c, Dictionary<string, string> tags)
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
var result = e.Apply(new Constant(tags)).Evaluate(c);
|
var result = e.Apply(new Constant(tags)).Evaluate(c);
|
||||||
while (result is IExpression ex)
|
while (result is IExpression ex) {
|
||||||
{
|
|
||||||
result = ex.Apply(new Constant(tags)).Evaluate(c);
|
result = ex.Apply(new Constant(tags)).Evaluate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception err)
|
catch (Exception err) {
|
||||||
{
|
|
||||||
throw new Exception($"While evaluating the expression {e} with arguments a list of tags", err);
|
throw new Exception($"While evaluating the expression {e} with arguments a list of tags", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double EvaluateDouble(this IExpression e, string paramName, Context c, params IExpression[] arguments)
|
|
||||||
{
|
|
||||||
return Utils.AsDouble(e.Evaluate(c, arguments), paramName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IExpression Specialize(this IExpression e, Type t)
|
public static IExpression Specialize(this IExpression e, Type t)
|
||||||
{
|
{
|
||||||
if (t == null)
|
if (t == null) {
|
||||||
{
|
|
||||||
throw new NullReferenceException("Cannot specialize to null");
|
throw new NullReferenceException("Cannot specialize to null");
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.Specialize(new[] { t });
|
return e.Specialize(new[] {t});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IExpression Specialize(this IExpression e, Dictionary<string, Type> substitutions)
|
public static IExpression Specialize(this IExpression e, Dictionary<string, Type> substitutions)
|
||||||
{
|
{
|
||||||
var newTypes = new HashSet<Type>();
|
var newTypes = new HashSet<Type>();
|
||||||
|
|
||||||
foreach (var oldType in e.Types)
|
foreach (var oldType in e.Types) {
|
||||||
{
|
|
||||||
var newType = oldType.Substitute(substitutions);
|
var newType = oldType.Substitute(substitutions);
|
||||||
if (newType == null)
|
if (newType == null) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
newTypes.Add(newType);
|
newTypes.Add(newType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newTypes.Any())
|
if (!newTypes.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,28 +109,23 @@ namespace AspectedRouting.Language
|
||||||
var allExpressions = new HashSet<IExpression>();
|
var allExpressions = new HashSet<IExpression>();
|
||||||
specializedExpressions = allExpressions;
|
specializedExpressions = allExpressions;
|
||||||
|
|
||||||
foreach (var expr in exprs)
|
foreach (var expr in exprs) {
|
||||||
{
|
if (specializedTypes == null) {
|
||||||
if (specializedTypes == null)
|
specializedTypes = expr.Types;
|
||||||
{
|
|
||||||
specializedTypes = expr.Types; // This is t
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
var newlySpecialized = Typs.WidestCommonTypes(specializedTypes, expr.Types);
|
var newlySpecialized = Typs.WidestCommonTypes(specializedTypes, expr.Types);
|
||||||
if (!newlySpecialized.Any())
|
if (!newlySpecialized.Any()) {
|
||||||
{
|
throw new ArgumentException("Could not find a common ground for types "+specializedTypes.Pretty()+ " and "+expr.Types.Pretty());
|
||||||
throw new ArgumentException("Could not find a common ground for types " + specializedTypes.Pretty() + " and " + expr.Types.Pretty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
specializedTypes = newlySpecialized;
|
specializedTypes = newlySpecialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var expr in exprs)
|
foreach (var expr in exprs) {
|
||||||
{
|
|
||||||
var e = expr.Specialize(specializedTypes);
|
var e = expr.Specialize(specializedTypes);
|
||||||
allExpressions.Add(e);
|
allExpressions.Add(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ namespace AspectedRouting.Language.Typ
|
||||||
ArgType = argType;
|
ArgType = argType;
|
||||||
ResultType = resultType;
|
ResultType = resultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static string ToString(Type argType, Type resultType)
|
private static string ToString(Type argType, Type resultType)
|
||||||
{
|
{
|
||||||
var arg = argType.ToString();
|
var arg = argType.ToString();
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
Typs.AddBuiltin(this);
|
Typs.AddBuiltin(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
|
@ -30,20 +30,16 @@ namespace AspectedRouting.Language.Typ
|
||||||
var results = new HashSet<Type>();
|
var results = new HashSet<Type>();
|
||||||
|
|
||||||
allowedTypes = allowedTypes.ToList();
|
allowedTypes = allowedTypes.ToList();
|
||||||
foreach (var t0 in types0)
|
foreach (var t0 in types0) {
|
||||||
{
|
foreach (var allowed in allowedTypes) {
|
||||||
foreach (var allowed in allowedTypes)
|
|
||||||
{
|
|
||||||
var unified = t0.Unify(allowed, reverseSuperSet);
|
var unified = t0.Unify(allowed, reverseSuperSet);
|
||||||
if (unified != null)
|
if (unified != null) {
|
||||||
{
|
|
||||||
results.Add(unified);
|
results.Add(unified);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results.Any())
|
if (results.Any()) {
|
||||||
{
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,14 +59,12 @@ namespace AspectedRouting.Language.Typ
|
||||||
public static Type Unify(this Type t0, Type t1, bool reverseSuperset = false)
|
public static Type Unify(this Type t0, Type t1, bool reverseSuperset = false)
|
||||||
{
|
{
|
||||||
var table = t0.UnificationTable(t1, reverseSuperset);
|
var table = t0.UnificationTable(t1, reverseSuperset);
|
||||||
if (table == null)
|
if (table == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subbed = t0.Substitute(table);
|
var subbed = t0.Substitute(table);
|
||||||
if (reverseSuperset)
|
if (reverseSuperset) {
|
||||||
{
|
|
||||||
return SelectSmallestUnion(t1, subbed);
|
return SelectSmallestUnion(t1, subbed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +79,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static Type SelectSmallestUnion(this Type wider, Type smaller)
|
private static Type SelectSmallestUnion(this Type wider, Type smaller)
|
||||||
{
|
{
|
||||||
switch (wider)
|
switch (wider) {
|
||||||
{
|
|
||||||
case Var a:
|
case Var a:
|
||||||
return a;
|
return a;
|
||||||
case ListType l when smaller is ListType lsmaller:
|
case ListType l when smaller is ListType lsmaller:
|
||||||
|
@ -100,8 +93,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
cWider.ResultType.SelectSmallestUnion(cSmaller.ResultType);
|
cWider.ResultType.SelectSmallestUnion(cSmaller.ResultType);
|
||||||
return new Curry(arg, result);
|
return new Curry(arg, result);
|
||||||
default:
|
default:
|
||||||
if (wider.IsSuperSet(smaller) && !smaller.IsSuperSet(wider))
|
if (wider.IsSuperSet(smaller) && !smaller.IsSuperSet(wider)) {
|
||||||
{
|
|
||||||
return smaller;
|
return smaller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +111,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
public static IEnumerable<Type> UnifyAll(this Type t0, IEnumerable<Type> t1)
|
public static IEnumerable<Type> UnifyAll(this Type t0, IEnumerable<Type> t1)
|
||||||
{
|
{
|
||||||
var result = t1.Select(t => t0.Unify(t)).ToHashSet();
|
var result = t1.Select(t => t0.Unify(t)).ToHashSet();
|
||||||
if (result.Any(x => x == null))
|
if (result.Any(x => x == null)) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,8 +121,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
|
|
||||||
public static Type Substitute(this Type t0, Dictionary<string, Type> substitutions)
|
public static Type Substitute(this Type t0, Dictionary<string, Type> substitutions)
|
||||||
{
|
{
|
||||||
switch (t0)
|
switch (t0) {
|
||||||
{
|
|
||||||
case Var a when substitutions.TryGetValue(a.Name, out var t):
|
case Var a when substitutions.TryGetValue(a.Name, out var t):
|
||||||
return t;
|
return t;
|
||||||
case ListType l:
|
case ListType l:
|
||||||
|
@ -161,8 +151,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
|
|
||||||
bool AddSubs(string key, Type valueToAdd)
|
bool AddSubs(string key, Type valueToAdd)
|
||||||
{
|
{
|
||||||
if (substitutionsOn0.TryGetValue(key, out var oldSubs))
|
if (substitutionsOn0.TryGetValue(key, out var oldSubs)) {
|
||||||
{
|
|
||||||
return oldSubs.Equals(valueToAdd);
|
return oldSubs.Equals(valueToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,15 +161,12 @@ namespace AspectedRouting.Language.Typ
|
||||||
|
|
||||||
bool AddAllSubs(Dictionary<string, Type> table)
|
bool AddAllSubs(Dictionary<string, Type> table)
|
||||||
{
|
{
|
||||||
if (table == null)
|
if (table == null) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (key, tp) in table)
|
foreach (var (key, tp) in table) {
|
||||||
{
|
if (!AddSubs(key, tp)) {
|
||||||
if (!AddSubs(key, tp))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,54 +174,45 @@ namespace AspectedRouting.Language.Typ
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (t0)
|
switch (t0) {
|
||||||
{
|
|
||||||
case Var a:
|
case Var a:
|
||||||
if (!AddSubs(a.Name, t1))
|
if (!AddSubs(a.Name, t1)) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ListType l0 when t1 is ListType l1:
|
case ListType l0 when t1 is ListType l1: {
|
||||||
{
|
var table = l0.InnerType.UnificationTable(l1.InnerType, reverseSupersetRelation);
|
||||||
var table = l0.InnerType.UnificationTable(l1.InnerType, reverseSupersetRelation);
|
if (!AddAllSubs(table)) {
|
||||||
if (!AddAllSubs(table))
|
return null;
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case Curry curry0 when t1 is Curry curry1:
|
break;
|
||||||
{
|
}
|
||||||
// contravariance for arguments: reversed
|
|
||||||
var tableA = curry0.ArgType.UnificationTable(curry1.ArgType, !reverseSupersetRelation);
|
|
||||||
var tableB = curry0.ResultType.UnificationTable(curry1.ResultType, reverseSupersetRelation);
|
|
||||||
if (!(AddAllSubs(tableA) && AddAllSubs(tableB)))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
case Curry curry0 when t1 is Curry curry1: {
|
||||||
|
// contravariance for arguments: reversed
|
||||||
|
var tableA = curry0.ArgType.UnificationTable(curry1.ArgType, !reverseSupersetRelation);
|
||||||
|
var tableB = curry0.ResultType.UnificationTable(curry1.ResultType, reverseSupersetRelation);
|
||||||
|
if (!(AddAllSubs(tableA) && AddAllSubs(tableB))) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
if (t1 is Var v)
|
if (t1 is Var v) {
|
||||||
{
|
|
||||||
AddSubs(v.Name, t0);
|
AddSubs(v.Name, t0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reverseSupersetRelation && !t0.IsSuperSet(t1))
|
if (!reverseSupersetRelation && !t0.IsSuperSet(t1)) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reverseSupersetRelation && !t1.IsSuperSet(t0))
|
if (reverseSupersetRelation && !t1.IsSuperSet(t0)) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,28 +227,23 @@ namespace AspectedRouting.Language.Typ
|
||||||
// We do not have to worry about overlapping names, as they should be cleaned before calling this method
|
// We do not have to worry about overlapping names, as they should be cleaned before calling this method
|
||||||
|
|
||||||
bool appliedTransitivity;
|
bool appliedTransitivity;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
appliedTransitivity = false;
|
appliedTransitivity = false;
|
||||||
var keys = substitutionsOn0.Keys.ToList();
|
var keys = substitutionsOn0.Keys.ToList();
|
||||||
foreach (var key in keys)
|
foreach (var key in keys) {
|
||||||
{
|
|
||||||
var val = substitutionsOn0[key];
|
var val = substitutionsOn0[key];
|
||||||
var usedVars = val.UsedVariables();
|
var usedVars = val.UsedVariables();
|
||||||
var isContained = keys.Any(usedVars.Contains);
|
var isContained = keys.Any(usedVars.Contains);
|
||||||
if (!isContained)
|
if (!isContained) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newVal = val.Substitute(substitutionsOn0);
|
var newVal = val.Substitute(substitutionsOn0);
|
||||||
if (newVal.Equals(val))
|
if (newVal.Equals(val)) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newVal.UsedVariables().Contains(key) && !newVal.Equals(new Var(key)))
|
if (newVal.UsedVariables().Contains(key) && !newVal.Equals(new Var(key))) {
|
||||||
{
|
|
||||||
// The substitution contains itself; and it is bigger then itself
|
// The substitution contains itself; and it is bigger then itself
|
||||||
// This means that $a is substituted by e.g. ($a -> $x), implying an infinite and contradictory type
|
// This means that $a is substituted by e.g. ($a -> $x), implying an infinite and contradictory type
|
||||||
return null;
|
return null;
|
||||||
|
@ -288,23 +260,20 @@ namespace AspectedRouting.Language.Typ
|
||||||
public static HashSet<string> UsedVariables(this Type t0, HashSet<string> addTo = null)
|
public static HashSet<string> UsedVariables(this Type t0, HashSet<string> addTo = null)
|
||||||
{
|
{
|
||||||
addTo ??= new HashSet<string>();
|
addTo ??= new HashSet<string>();
|
||||||
switch (t0)
|
switch (t0) {
|
||||||
{
|
|
||||||
case Var a:
|
case Var a:
|
||||||
addTo.Add(a.Name);
|
addTo.Add(a.Name);
|
||||||
break;
|
break;
|
||||||
case ListType l0:
|
case ListType l0: {
|
||||||
{
|
l0.InnerType.UsedVariables(addTo);
|
||||||
l0.InnerType.UsedVariables(addTo);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case Curry curry0:
|
case Curry curry0: {
|
||||||
{
|
curry0.ArgType.UsedVariables(addTo);
|
||||||
curry0.ArgType.UsedVariables(addTo);
|
curry0.ResultType.UsedVariables(addTo);
|
||||||
curry0.ResultType.UsedVariables(addTo);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,13 +282,11 @@ namespace AspectedRouting.Language.Typ
|
||||||
|
|
||||||
public static bool IsSuperSet(this Type t0, Type t1)
|
public static bool IsSuperSet(this Type t0, Type t1)
|
||||||
{
|
{
|
||||||
if (t0 is Var || t1 is Var)
|
if (t0 is Var || t1 is Var) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (t0)
|
switch (t0) {
|
||||||
{
|
|
||||||
case StringType _ when t1 is BoolType _:
|
case StringType _ when t1 is BoolType _:
|
||||||
return true;
|
return true;
|
||||||
case DoubleType _ when t1 is PDoubleType _:
|
case DoubleType _ when t1 is PDoubleType _:
|
||||||
|
@ -338,11 +305,10 @@ namespace AspectedRouting.Language.Typ
|
||||||
case ListType l0 when t1 is ListType l1:
|
case ListType l0 when t1 is ListType l1:
|
||||||
return l0.InnerType.IsSuperSet(l1.InnerType);
|
return l0.InnerType.IsSuperSet(l1.InnerType);
|
||||||
|
|
||||||
case Curry c0 when t1 is Curry c1:
|
case Curry c0 when t1 is Curry c1: {
|
||||||
{
|
return c0.ResultType.IsSuperSet(c1.ResultType) &&
|
||||||
return c0.ResultType.IsSuperSet(c1.ResultType) &&
|
c1.ArgType.IsSuperSet(c0.ArgType); // contravariance for arguments: reversed order!
|
||||||
c1.ArgType.IsSuperSet(c0.ArgType); // contravariance for arguments: reversed order!
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -363,8 +329,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
|
|
||||||
// The substitution table
|
// The substitution table
|
||||||
var subsTable = new Dictionary<string, Type>();
|
var subsTable = new Dictionary<string, Type>();
|
||||||
foreach (var v in variablesToRename)
|
foreach (var v in variablesToRename) {
|
||||||
{
|
|
||||||
var newValue = Var.Fresh(alreadyUsed);
|
var newValue = Var.Fresh(alreadyUsed);
|
||||||
subsTable.Add(v, newValue);
|
subsTable.Add(v, newValue);
|
||||||
alreadyUsed.Add(newValue.Name);
|
alreadyUsed.Add(newValue.Name);
|
||||||
|
@ -377,8 +342,7 @@ namespace AspectedRouting.Language.Typ
|
||||||
public static List<Type> Uncurry(this Type t)
|
public static List<Type> Uncurry(this Type t)
|
||||||
{
|
{
|
||||||
var args = new List<Type>();
|
var args = new List<Type>();
|
||||||
while (t is Curry c)
|
while (t is Curry c) {
|
||||||
{
|
|
||||||
args.Add(c.ArgType);
|
args.Add(c.ArgType);
|
||||||
t = c.ResultType;
|
t = c.ResultType;
|
||||||
}
|
}
|
||||||
|
@ -401,16 +365,12 @@ namespace AspectedRouting.Language.Typ
|
||||||
{
|
{
|
||||||
var widest = new HashSet<Type>();
|
var widest = new HashSet<Type>();
|
||||||
|
|
||||||
foreach (var type0 in t0)
|
foreach (var type0 in t0) {
|
||||||
{
|
foreach (var type1 in t1) {
|
||||||
foreach (var type1 in t1)
|
|
||||||
{
|
|
||||||
var t = WidestCommonType(type0, type1);
|
var t = WidestCommonType(type0, type1);
|
||||||
if (t != null)
|
if (t != null) {
|
||||||
{
|
|
||||||
var (type, subsTable) = t.Value;
|
var (type, subsTable) = t.Value;
|
||||||
if (subsTable != null)
|
if (subsTable != null) {
|
||||||
{
|
|
||||||
type = type.Substitute(subsTable);
|
type = type.Substitute(subsTable);
|
||||||
}
|
}
|
||||||
widest.Add(type);
|
widest.Add(type);
|
||||||
|
@ -437,54 +397,44 @@ namespace AspectedRouting.Language.Typ
|
||||||
{
|
{
|
||||||
// First things first: we try to unify
|
// First things first: we try to unify
|
||||||
|
|
||||||
if (t0 is Curry c0 && t1 is Curry c1)
|
if (t0 is Curry c0 && t1 is Curry c1) {
|
||||||
{
|
|
||||||
var arg = SmallestCommonType(c0.ArgType, c1.ArgType);
|
var arg = SmallestCommonType(c0.ArgType, c1.ArgType);
|
||||||
var result = WidestCommonType(c0.ResultType, c1.ResultType);
|
var result = WidestCommonType(c0.ResultType, c1.ResultType);
|
||||||
if (arg == null)
|
if (arg == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var (argT, subs0) = arg.Value;
|
var (argT, subs0) = arg.Value;
|
||||||
|
|
||||||
if (result == null)
|
if (result == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var (resultT, subs1) = result.Value;
|
var (resultT, subs1) = result.Value;
|
||||||
return (new Curry(argT, resultT), MergeDicts(subs0, subs1));
|
return (new Curry(argT, resultT), MergeDicts(subs0, subs1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (t0 is Var v)
|
if (t0 is Var v) {
|
||||||
{
|
if (t1 is Var vx) {
|
||||||
if (t1 is Var vx)
|
if (v.Name == vx.Name) {
|
||||||
{
|
|
||||||
if (v.Name == vx.Name)
|
|
||||||
{
|
|
||||||
return (t0, null);
|
return (t0, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (t1, new Dictionary<string, Type> { { v.Name, t1 } });
|
return (t1, new Dictionary<string, Type> {{v.Name, t1}});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1 is Var v1)
|
if (t1 is Var v1) {
|
||||||
{
|
return (t0, new Dictionary<string, Type> {{v1.Name, t1}});
|
||||||
return (t0, new Dictionary<string, Type> { { v1.Name, t1 } });
|
|
||||||
}
|
}
|
||||||
if (t0 == t1 || t0.Equals(t1))
|
if (t0 == t1 || t0.Equals(t1)) {
|
||||||
{
|
|
||||||
return (t0, null);
|
return (t0, null);
|
||||||
}
|
}
|
||||||
var t0IsSuperT1 = t0.IsSuperSet(t1);
|
var t0IsSuperT1 = t0.IsSuperSet(t1);
|
||||||
var t1IsSuperT0 = t1.IsSuperSet(t0);
|
var t1IsSuperT0 = t1.IsSuperSet(t0);
|
||||||
if (t0IsSuperT1 && !t1IsSuperT0)
|
if (t0IsSuperT1 && !t1IsSuperT0) {
|
||||||
{
|
|
||||||
return (t0, null);
|
return (t0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1IsSuperT0 && !t0IsSuperT1)
|
if (t1IsSuperT0 && !t0IsSuperT1) {
|
||||||
{
|
|
||||||
return (t1, null);
|
return (t1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,25 +444,20 @@ namespace AspectedRouting.Language.Typ
|
||||||
private static Dictionary<string, Type> MergeDicts(Dictionary<string, Type> subs0,
|
private static Dictionary<string, Type> MergeDicts(Dictionary<string, Type> subs0,
|
||||||
Dictionary<string, Type> subs1)
|
Dictionary<string, Type> subs1)
|
||||||
{
|
{
|
||||||
if (subs0 == null && subs1 == null)
|
if (subs0 == null && subs1 == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var subsTable = new Dictionary<string, Type>();
|
var subsTable = new Dictionary<string, Type>();
|
||||||
|
|
||||||
void AddSubs(Dictionary<string, Type> dict)
|
void AddSubs(Dictionary<string, Type> dict)
|
||||||
{
|
{
|
||||||
if (dict == null)
|
if (dict == null) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (var kv in dict)
|
foreach (var kv in dict) {
|
||||||
{
|
if (subsTable.TryGetValue(kv.Key, out var t)) {
|
||||||
if (subsTable.TryGetValue(kv.Key, out var t))
|
|
||||||
{
|
|
||||||
// We have seen this variable-type-name before... We should check if it matches
|
// We have seen this variable-type-name before... We should check if it matches
|
||||||
if (t.Equals(kv.Value))
|
if (t.Equals(kv.Value)) {
|
||||||
{
|
|
||||||
// Ok! No problem!
|
// Ok! No problem!
|
||||||
// It is already added anyway, so we continue
|
// It is already added anyway, so we continue
|
||||||
continue;
|
continue;
|
||||||
|
@ -522,15 +467,13 @@ namespace AspectedRouting.Language.Typ
|
||||||
throw new Exception(t + " != " + kv.Value);
|
throw new Exception(t + " != " + kv.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kv.Value is Var v)
|
if (kv.Value is Var v) {
|
||||||
{
|
if (v.Name == kv.Key) {
|
||||||
if (v.Name == kv.Key)
|
|
||||||
{
|
|
||||||
// Well, this is a useless substitution...
|
// Well, this is a useless substitution...
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subsTable[kv.Key] = kv.Value;
|
subsTable[kv.Key] = kv.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,11 +481,10 @@ namespace AspectedRouting.Language.Typ
|
||||||
AddSubs(subs0);
|
AddSubs(subs0);
|
||||||
AddSubs(subs1);
|
AddSubs(subs1);
|
||||||
|
|
||||||
if (!subsTable.Any())
|
if (!subsTable.Any()) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return subsTable;
|
return subsTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,49 +502,41 @@ namespace AspectedRouting.Language.Typ
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static (Type, Dictionary<string, Type> substitutionTable)? SmallestCommonType(Type t0, Type t1)
|
public static (Type, Dictionary<string, Type> substitutionTable)? SmallestCommonType(Type t0, Type t1)
|
||||||
{
|
{
|
||||||
if (t0 is Curry c0 && t1 is Curry c1)
|
if (t0 is Curry c0 && t1 is Curry c1) {
|
||||||
{
|
|
||||||
var arg = WidestCommonType(c0.ArgType, c1.ArgType);
|
var arg = WidestCommonType(c0.ArgType, c1.ArgType);
|
||||||
var result = SmallestCommonType(c0.ResultType, c1.ResultType);
|
var result = SmallestCommonType(c0.ResultType, c1.ResultType);
|
||||||
if (arg == null)
|
if (arg == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var (argT, subs0) = arg.Value;
|
var (argT, subs0) = arg.Value;
|
||||||
|
|
||||||
if (result == null)
|
if (result == null) {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var (resultT, subs1) = result.Value;
|
var (resultT, subs1) = result.Value;
|
||||||
return (new Curry(argT, resultT), MergeDicts(subs0, subs1));
|
return (new Curry(argT, resultT), MergeDicts(subs0, subs1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (t0 is Var v)
|
if (t0 is Var v) {
|
||||||
{
|
return (t1, new Dictionary<string, Type> {{v.Name, t1}});
|
||||||
return (t1, new Dictionary<string, Type> { { v.Name, t1 } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1 is Var v1)
|
if (t1 is Var v1) {
|
||||||
{
|
return (t0, new Dictionary<string, Type> {{v1.Name, t1}});
|
||||||
return (t0, new Dictionary<string, Type> { { v1.Name, t1 } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t0 == t1 || t0.Equals(t1))
|
if (t0 == t1 || t0.Equals(t1)) {
|
||||||
{
|
|
||||||
return (t0, null);
|
return (t0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var t0IsSuperT1 = t0.IsSuperSet(t1);
|
var t0IsSuperT1 = t0.IsSuperSet(t1);
|
||||||
var t1IsSuperT0 = t1.IsSuperSet(t0);
|
var t1IsSuperT0 = t1.IsSuperSet(t0);
|
||||||
if (t0IsSuperT1 && !t1IsSuperT0)
|
if (t0IsSuperT1 && !t1IsSuperT0) {
|
||||||
{
|
|
||||||
return (t0, null);
|
return (t0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1IsSuperT0 && !t0IsSuperT1)
|
if (t1IsSuperT0 && !t0IsSuperT1) {
|
||||||
{
|
|
||||||
return (t1, null);
|
return (t1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using AspectedRouting.IO.itinero1;
|
|
||||||
using AspectedRouting.IO.itinero2;
|
|
||||||
using AspectedRouting.IO.md;
|
|
||||||
using AspectedRouting.Language;
|
|
||||||
using AspectedRouting.Language.Expression;
|
|
||||||
using AspectedRouting.Tests;
|
|
||||||
|
|
||||||
namespace AspectedRouting
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Prints to the specified location
|
|
||||||
*/
|
|
||||||
public class Printer
|
|
||||||
{
|
|
||||||
private readonly List<(AspectMetadata aspect, AspectTestSuite tests)> _aspects;
|
|
||||||
private readonly Context _context;
|
|
||||||
private readonly string _outputDirectory;
|
|
||||||
private readonly ProfileMetaData _profile;
|
|
||||||
private readonly List<BehaviourTestSuite> _profileTests;
|
|
||||||
private readonly bool _includeTests;
|
|
||||||
|
|
||||||
public Printer(string outputDirectory, ProfileMetaData profile, Context context,
|
|
||||||
List<(AspectMetadata aspect, AspectTestSuite tests)> aspects,
|
|
||||||
List<BehaviourTestSuite> profileTests, bool includeTests)
|
|
||||||
{
|
|
||||||
_outputDirectory = outputDirectory;
|
|
||||||
_profile = profile;
|
|
||||||
_context = context;
|
|
||||||
_aspects = aspects;
|
|
||||||
_profileTests = profileTests;
|
|
||||||
_includeTests = includeTests;
|
|
||||||
|
|
||||||
|
|
||||||
if (!Directory.Exists($"{outputDirectory}/profile-documentation/")) {
|
|
||||||
Directory.CreateDirectory($"{outputDirectory}/profile-documentation/");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists($"{outputDirectory}/itinero1/")) {
|
|
||||||
Directory.CreateDirectory($"{outputDirectory}/itinero1/");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists($"{outputDirectory}/itinero2/")) {
|
|
||||||
Directory.CreateDirectory($"{outputDirectory}/itinero2/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PrintUsedTags()
|
|
||||||
{
|
|
||||||
var profile = _profile;
|
|
||||||
var context = _context;
|
|
||||||
Console.WriteLine("\n\n\n---------- " + profile.Name +
|
|
||||||
" : used tags and corresponding values --------------");
|
|
||||||
foreach (var (key, values) in profile.AllExpressions(context).PossibleTags()) {
|
|
||||||
var vs = "*";
|
|
||||||
if (values.Any()) {
|
|
||||||
vs = string.Join(", ", values);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine(key + ": " + vs);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("\n\n\n------------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteProfile1()
|
|
||||||
{
|
|
||||||
var aspectTests = _aspects.Select(a => a.tests).ToList();
|
|
||||||
|
|
||||||
var luaProfile = new LuaPrinter1(_profile, _context,
|
|
||||||
aspectTests,
|
|
||||||
_profileTests
|
|
||||||
).ToLua();
|
|
||||||
|
|
||||||
var itinero1ProfileFile = Path.Combine($"{_outputDirectory}/itinero1/" + _profile.Name + ".lua");
|
|
||||||
File.WriteAllText(itinero1ProfileFile, luaProfile);
|
|
||||||
Console.WriteLine($"Written {new FileInfo(itinero1ProfileFile).FullName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteAllProfile2()
|
|
||||||
{
|
|
||||||
foreach (var (behaviourName,_) in _profile.Behaviours) {
|
|
||||||
WriteProfile2(behaviourName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteProfile2(string behaviourName)
|
|
||||||
{
|
|
||||||
var aspectTests = _aspects.Select(a => a.tests).ToList();
|
|
||||||
|
|
||||||
var lua2behaviour = new LuaPrinter2(
|
|
||||||
_profile,
|
|
||||||
behaviourName,
|
|
||||||
_context,
|
|
||||||
aspectTests,
|
|
||||||
_profileTests.Where(testsSuite => testsSuite.BehaviourName == behaviourName),
|
|
||||||
_includeTests
|
|
||||||
).ToLua();
|
|
||||||
|
|
||||||
var itinero2ProfileFile = Path.Combine($"{_outputDirectory}/itinero2/{_profile.Name}.{behaviourName}.lua");
|
|
||||||
File.WriteAllText(
|
|
||||||
itinero2ProfileFile,
|
|
||||||
lua2behaviour);
|
|
||||||
Console.WriteLine($"Written {new FileInfo(itinero2ProfileFile).FullName}");
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PrintMdInfo()
|
|
||||||
{
|
|
||||||
var profileMd = new MarkDownSection();
|
|
||||||
profileMd.AddTitle(_profile.Name, 1);
|
|
||||||
|
|
||||||
profileMd.Add(_profile.Description);
|
|
||||||
profileMd.AddTitle("Default parameters", 4);
|
|
||||||
profileMd.Add("| name | value | ", "| ---- | ---- | ",
|
|
||||||
string.Join("\n",
|
|
||||||
_profile.DefaultParameters.Select(delegate(KeyValuePair<string, IExpression> kv)
|
|
||||||
{
|
|
||||||
var v = kv.Value.Evaluate(_context);
|
|
||||||
if (!(v is string || v is int || v is double)) {
|
|
||||||
v = "_special value_";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $" | {kv.Key} | {v} |";
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
foreach (var (behaviourName, vars) in _profile.Behaviours) {
|
|
||||||
var behaviourMd = new ProfileToMD(_profile, behaviourName, _context);
|
|
||||||
|
|
||||||
File.WriteAllText(
|
|
||||||
$"{_outputDirectory}/profile-documentation/{_profile.Name}.{behaviourName}.md",
|
|
||||||
behaviourMd.ToString());
|
|
||||||
profileMd.AddTitle($"[{behaviourName}](./{_profile.Name}.{behaviourName}.md)", 2);
|
|
||||||
profileMd.Add(vars["description"].Evaluate(_context).ToString());
|
|
||||||
profileMd.Add(behaviourMd.MainFormula());
|
|
||||||
}
|
|
||||||
|
|
||||||
File.WriteAllText(
|
|
||||||
$"{_outputDirectory}/profile-documentation/{_profile.Name}.md",
|
|
||||||
profileMd.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue