Refactoring of lua printing, adds generation of itinero 2.0 profiles
This commit is contained in:
parent
8bf77cbc69
commit
5268d4ee81
25 changed files with 1191 additions and 580 deletions
|
@ -12,6 +12,9 @@
|
||||||
<None Update="IO\lua\**">
|
<None Update="IO\lua\**">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="IO\lua\unitTestProfile2.lua">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AspectedRouting.Language;
|
||||||
|
using AspectedRouting.Language.Expression;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.itinero1
|
||||||
|
{
|
||||||
|
public class LuaParameterPrinter
|
||||||
|
{
|
||||||
|
private ProfileMetaData _profile;
|
||||||
|
private LuaSkeleton.LuaSkeleton _skeleton;
|
||||||
|
|
||||||
|
public LuaParameterPrinter(ProfileMetaData profile, LuaSkeleton.LuaSkeleton skeleton)
|
||||||
|
{
|
||||||
|
_profile = profile;
|
||||||
|
_skeleton = skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public string GenerateDefaultParameters()
|
||||||
|
{
|
||||||
|
var impl = new List<string>()
|
||||||
|
{
|
||||||
|
"function default_parameters()",
|
||||||
|
" local parameters = {}",
|
||||||
|
DeclareParametersFor(_profile.DefaultParameters),
|
||||||
|
" return parameters",
|
||||||
|
"end"
|
||||||
|
};
|
||||||
|
|
||||||
|
return string.Join("\n",impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a piece of code of the following format:
|
||||||
|
///
|
||||||
|
/// 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()`
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="behaviour"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string DeclareParametersFor(Dictionary<string, IExpression> subParams)
|
||||||
|
{
|
||||||
|
var impl = "";
|
||||||
|
foreach (var (paramName, value) in subParams)
|
||||||
|
{
|
||||||
|
if (paramName.Equals("description"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl += $" parameters.{paramName.TrimStart('#').AsLuaIdentifier()} = {_skeleton.ToLua(value)}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,18 +2,20 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using AspectedRouting.IO.itinero1;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Expression;
|
using AspectedRouting.Language.Expression;
|
||||||
using AspectedRouting.Language.Functions;
|
using AspectedRouting.Language.Functions;
|
||||||
using AspectedRouting.Language.Typ;
|
using AspectedRouting.Language.Typ;
|
||||||
using static AspectedRouting.Language.Deconstruct;
|
using static AspectedRouting.Language.Deconstruct;
|
||||||
|
|
||||||
namespace AspectedRouting.IO.itinero1
|
namespace AspectedRouting.IO.LuaSkeleton
|
||||||
{
|
{
|
||||||
public partial class LuaPrinter
|
public partial class LuaSkeleton
|
||||||
{
|
{
|
||||||
private string ToLua(IExpression bare, string key = "nil")
|
internal string ToLua(IExpression bare, string key = "nil")
|
||||||
{
|
{
|
||||||
|
|
||||||
var collectedMapping = new List<IExpression>();
|
var collectedMapping = new List<IExpression>();
|
||||||
var order = new List<IExpression>();
|
var order = new List<IExpression>();
|
||||||
|
|
||||||
|
@ -63,6 +65,9 @@ namespace AspectedRouting.IO.itinero1
|
||||||
var func = new List<IExpression>();
|
var func = new List<IExpression>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
UnApply(
|
UnApply(
|
||||||
UnApply(IsFunc(Funcs.Dot), Assign(func)),
|
UnApply(IsFunc(Funcs.Dot), Assign(func)),
|
||||||
|
@ -155,7 +160,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFunction(called);
|
AddFunction(called);
|
||||||
return $"{fc.CalledFunctionName.FunctionName()}(parameters, tags, result)";
|
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:
|
||||||
|
@ -184,7 +189,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
return ToLua(collected.First(), key);
|
return ToLua(collected.First(), key);
|
||||||
|
|
||||||
case Parameter p:
|
case Parameter p:
|
||||||
return $"parameters[\"{p.ParamName.FunctionName()}\"]";
|
return $"parameters[\"{p.ParamName.AsLuaIdentifier()}\"]";
|
||||||
default:
|
default:
|
||||||
throw new Exception("Could not convert " + bare + " to a lua expression");
|
throw new Exception("Could not convert " + bare + " to a lua expression");
|
||||||
}
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using AspectedRouting.IO.itinero1;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Expression;
|
using AspectedRouting.Language.Expression;
|
||||||
|
|
||||||
namespace AspectedRouting.IO.itinero1
|
namespace AspectedRouting.IO.LuaSkeleton
|
||||||
{
|
{
|
||||||
public partial class LuaPrinter
|
public partial class LuaSkeleton
|
||||||
{
|
{
|
||||||
private readonly HashSet<string> _alreadyAddedFunctions = new HashSet<string>();
|
|
||||||
|
|
||||||
public void AddFunction(AspectMetadata meta)
|
public void AddFunction(AspectMetadata meta)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
{
|
{
|
||||||
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.FunctionName()}\"";
|
funcNameDeclaration = $"\n local funcName = \"{meta.Name.AsLuaIdentifier()}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -49,16 +49,12 @@ namespace AspectedRouting.IO.itinero1
|
||||||
"Number of combintations: " + numberOfCombinations,
|
"Number of combintations: " + numberOfCombinations,
|
||||||
"Returns values: ",
|
"Returns values: ",
|
||||||
"]]",
|
"]]",
|
||||||
"function " + meta.Name.FunctionName() + "(parameters, tags, result)" + funcNameDeclaration,
|
"function " + meta.Name.AsLuaIdentifier() + "(parameters, tags, result)" + funcNameDeclaration,
|
||||||
" return " + ToLua(meta.ExpressionImplementation),
|
" return " + ToLua(meta.ExpressionImplementation),
|
||||||
"end"
|
"end"
|
||||||
);
|
);
|
||||||
|
|
||||||
_code.Add(impl);
|
_functionImplementations.Add(impl);
|
||||||
foreach (var k in possibleTags.Keys)
|
|
||||||
{
|
|
||||||
_neededKeys.Add(k); // To generate a whitelist of OSM-keys that should be kept
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
78
AspectedRouting/IO/LuaSkeleton/LuaSkeleton.cs
Normal file
78
AspectedRouting/IO/LuaSkeleton/LuaSkeleton.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using AspectedRouting.Language;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.LuaSkeleton
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The 'LuaSkeleton' is a class which is used in Lua generation of profiles.
|
||||||
|
///
|
||||||
|
/// The lua skeleton basically keeps track of dependencies, and added functions.
|
||||||
|
/// Once done, all these can be retrieved as code.
|
||||||
|
///
|
||||||
|
/// E.g. if an expression is turned into lua with 'ToExpression', then the dependencies will be automatically added.
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public partial class LuaSkeleton
|
||||||
|
{
|
||||||
|
private readonly Context _context;
|
||||||
|
|
||||||
|
private readonly HashSet<string> _dependencies = new HashSet<string>();
|
||||||
|
private readonly List<string> _functionImplementations = new List<string>();
|
||||||
|
private readonly HashSet<string> _alreadyAddedFunctions = new HashSet<string>();
|
||||||
|
|
||||||
|
public LuaSkeleton(Context context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddDep(string name)
|
||||||
|
{
|
||||||
|
_dependencies.Add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> GenerateFunctions()
|
||||||
|
{
|
||||||
|
return _functionImplementations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddDependenciesFor(IExpression e)
|
||||||
|
{
|
||||||
|
var (_, functionNames) = e.InList().DirectlyAndInderectlyCalled(_context);
|
||||||
|
foreach (var functionName in functionNames)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_context.DefinedFunctions.TryGetValue(functionName, out var aspectemeta))
|
||||||
|
{
|
||||||
|
AddFunction(aspectemeta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddDep(functionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> GenerateDependencies()
|
||||||
|
{
|
||||||
|
var imps = new List<string>();
|
||||||
|
|
||||||
|
foreach (var name in _dependencies)
|
||||||
|
{
|
||||||
|
var path = $"IO/lua/{name}.lua";
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
imps.Add(File.ReadAllText(path));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return imps;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ namespace AspectedRouting.IO.itinero1
|
||||||
return "{" + string.Join(", ", contents) + "}";
|
return "{" + string.Join(", ", contents) + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string FunctionName(this string s)
|
public static string AsLuaIdentifier(this string s)
|
||||||
{
|
{
|
||||||
return s.Replace("$", "")
|
return s.Replace("$", "")
|
||||||
.Replace("#", "")
|
.Replace("#", "")
|
151
AspectedRouting/IO/LuaSkeleton/LuaTestPrinter.cs
Normal file
151
AspectedRouting/IO/LuaSkeleton/LuaTestPrinter.cs
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AspectedRouting.Tests;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.itinero1
|
||||||
|
{
|
||||||
|
public class LuaTestPrinter
|
||||||
|
{
|
||||||
|
private LuaSkeleton.LuaSkeleton _skeleton;
|
||||||
|
|
||||||
|
public LuaTestPrinter(LuaSkeleton.LuaSkeleton skeleton, List<string> unitTestRunners)
|
||||||
|
{
|
||||||
|
_skeleton = skeleton;
|
||||||
|
unitTestRunners.ForEach(_skeleton.AddDep);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public string GenerateFullTestSuite(List<BehaviourTestSuite> profileTests, List<AspectTestSuite> aspectTests)
|
||||||
|
{
|
||||||
|
|
||||||
|
_skeleton.AddDep("inv");
|
||||||
|
_skeleton.AddDep("double_compare");
|
||||||
|
|
||||||
|
|
||||||
|
var aspectTestSuite =
|
||||||
|
string.Join("\n\n", aspectTests
|
||||||
|
.Where(x => x != null)
|
||||||
|
.Select(
|
||||||
|
GenerateAspectTestSuite
|
||||||
|
));
|
||||||
|
|
||||||
|
var profileTestSuite =
|
||||||
|
string.Join("\n\n", profileTests
|
||||||
|
.Where(x => x != null)
|
||||||
|
.Select(
|
||||||
|
GenerateProfileTestSuite
|
||||||
|
));
|
||||||
|
|
||||||
|
return string.Join("\n\n\n", new List<string>
|
||||||
|
{
|
||||||
|
"function test_all()",
|
||||||
|
" " + aspectTestSuite.Indent(),
|
||||||
|
" -- Behaviour tests --",
|
||||||
|
" " + profileTestSuite.Indent(),
|
||||||
|
"end"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GenerateProfileTestSuite(BehaviourTestSuite testSuite)
|
||||||
|
{
|
||||||
|
return string.Join("\n",
|
||||||
|
testSuite.Tests.Select((test, i) => GenerateProfileUnitTestCall(testSuite, i, test.Item1, test.tags))
|
||||||
|
.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateProfileUnitTestCall(BehaviourTestSuite testSuite, int index, ProfileResult expected,
|
||||||
|
Dictionary<string, string> tags)
|
||||||
|
{
|
||||||
|
_skeleton.AddDep("debug_table");
|
||||||
|
var parameters = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
|
||||||
|
var keysToCheck = new List<string>();
|
||||||
|
foreach (var (key, value) in tags)
|
||||||
|
{
|
||||||
|
if (key.StartsWith("#"))
|
||||||
|
{
|
||||||
|
parameters[key.TrimStart('#')] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.StartsWith("_relation:"))
|
||||||
|
{
|
||||||
|
keysToCheck.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var key in keysToCheck)
|
||||||
|
{
|
||||||
|
var newKey = key.Replace(".", "_");
|
||||||
|
tags[newKey] = tags[key];
|
||||||
|
tags.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (paramName, _) in parameters)
|
||||||
|
{
|
||||||
|
tags.Remove("#" + paramName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates something like:
|
||||||
|
// function unit_test_profile(profile_function, profile_name, index, expected, tags)
|
||||||
|
return
|
||||||
|
$"unit_test_profile(behaviour_{testSuite.Profile.Name.AsLuaIdentifier()}_{testSuite.BehaviourName.AsLuaIdentifier()}, " +
|
||||||
|
$"\"{testSuite.BehaviourName}\", " +
|
||||||
|
$"{index}, " +
|
||||||
|
$"{{access = \"{D(expected.Access)}\", speed = {expected.Speed}, oneway = \"{D(expected.Oneway)}\", priority = {expected.Priority} }}, " +
|
||||||
|
tags.ToLuaTable() +
|
||||||
|
")";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GenerateAspectTestSuite(AspectTestSuite testSuite)
|
||||||
|
{
|
||||||
|
var fName = testSuite.FunctionToApply.Name;
|
||||||
|
var tests =
|
||||||
|
testSuite.Tests
|
||||||
|
.Select((test, i) => GenerateAspectUnitTestCall(fName, i, test.expected, test.tags))
|
||||||
|
.ToList();
|
||||||
|
return string.Join("\n", tests);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate a unit test call
|
||||||
|
/// </summary>
|
||||||
|
private string GenerateAspectUnitTestCall(string functionToApplyName, int index, string expected,
|
||||||
|
Dictionary<string, string> tags)
|
||||||
|
{
|
||||||
|
var parameters = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
foreach (var (key, value) in tags)
|
||||||
|
{
|
||||||
|
if (key.StartsWith("#"))
|
||||||
|
{
|
||||||
|
parameters[key.TrimStart('#')] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (paramName, _) in parameters)
|
||||||
|
{
|
||||||
|
tags.Remove("#" + paramName);
|
||||||
|
}
|
||||||
|
|
||||||
|
_skeleton.AddDep("unitTest");
|
||||||
|
_skeleton.AddDep("debug_table");
|
||||||
|
return
|
||||||
|
$"unit_test({functionToApplyName.AsLuaIdentifier()}, \"{functionToApplyName}\", {index}, \"{expected}\", {parameters.ToLuaTable()}, {tags.ToLuaTable()})";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string D(string s)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(s))
|
||||||
|
{
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,98 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace AspectedRouting.IO.itinero1
|
|
||||||
{
|
|
||||||
public partial class LuaPrinter
|
|
||||||
{
|
|
||||||
private readonly HashSet<string> _dependencies = new HashSet<string>();
|
|
||||||
private readonly HashSet<string> _neededKeys = new HashSet<string>();
|
|
||||||
|
|
||||||
private readonly List<string> _code = new List<string>();
|
|
||||||
private readonly List<string> _tests = new List<string>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A dictionary containing the implementation of basic functions
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static IEnumerable<string> LoadFunctions(IEnumerable<string> names)
|
|
||||||
{
|
|
||||||
var imps = new List<string>();
|
|
||||||
|
|
||||||
foreach (var name in names)
|
|
||||||
{
|
|
||||||
var path = $"IO/lua/{name}.lua";
|
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
|
||||||
imps.Add(File.ReadAllText(path));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return imps;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddDep(string name)
|
|
||||||
{
|
|
||||||
_dependencies.Add(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string ToLua()
|
|
||||||
{
|
|
||||||
var deps = _dependencies.ToList();
|
|
||||||
deps.Add("unitTestProfile");
|
|
||||||
deps.Add("inv");
|
|
||||||
deps.Add("double_compare");
|
|
||||||
deps.Add("spoken_instructions");
|
|
||||||
|
|
||||||
var code = new List<string>();
|
|
||||||
|
|
||||||
code.Add($"-- Itinero 1.0-profile, generated on {DateTime.Now:s}");
|
|
||||||
code.Add("\n\n----------------------------- UTILS ---------------------------");
|
|
||||||
code.AddRange(LoadFunctions(deps).ToList());
|
|
||||||
|
|
||||||
code.Add("\n\n----------------------------- PROFILE ---------------------------");
|
|
||||||
var keys = _neededKeys.Select(key => "\"" + key + "\"");
|
|
||||||
code.Add("\n\nprofile_whitelist = {\n " + string.Join("\n , ", keys) + "}");
|
|
||||||
|
|
||||||
code.AddRange(_code);
|
|
||||||
|
|
||||||
code.Add("\n\n ------------------------------- TESTS -------------------------");
|
|
||||||
|
|
||||||
code.Add("function test_all()");
|
|
||||||
code.Add(string.Join("\n",_tests).Indent());
|
|
||||||
code.Add("end");
|
|
||||||
|
|
||||||
var compatibility = string.Join("\n",
|
|
||||||
|
|
||||||
|
|
||||||
"",
|
|
||||||
"if (itinero == nil) then",
|
|
||||||
" itinero = {}",
|
|
||||||
" itinero.log = print",
|
|
||||||
"",
|
|
||||||
" -- Itinero is not defined -> we are running from a lua interpreter -> the tests are intended",
|
|
||||||
" runTests = true",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"else",
|
|
||||||
" print = itinero.log",
|
|
||||||
"end",
|
|
||||||
"",
|
|
||||||
"test_all()",
|
|
||||||
"if (not failed_tests and not failed_profile_tests) then",
|
|
||||||
" print(\"Tests OK\")",
|
|
||||||
"end"
|
|
||||||
);
|
|
||||||
code.Add(compatibility);
|
|
||||||
|
|
||||||
return string.Join("\n\n\n", code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
130
AspectedRouting/IO/itinero1/LuaPrinter1.MainFunction.cs
Normal file
130
AspectedRouting/IO/itinero1/LuaPrinter1.MainFunction.cs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AspectedRouting.Language;
|
||||||
|
using AspectedRouting.Language.Functions;
|
||||||
|
using AspectedRouting.Language.Typ;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.itinero1
|
||||||
|
{
|
||||||
|
public partial class LuaPrinter1
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
private string GenerateMainProfileFunction()
|
||||||
|
{
|
||||||
|
var impl = string.Join("\n",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"--[[",
|
||||||
|
_profile.Name,
|
||||||
|
"This is the main function called to calculate the access, oneway and speed.",
|
||||||
|
"Comfort is calculated as well, based on the parameters which are padded in",
|
||||||
|
"",
|
||||||
|
"Created by " + _profile.Author,
|
||||||
|
"Originally defined in " + _profile.Filename,
|
||||||
|
"]]",
|
||||||
|
"function " + _profile.Name + "(parameters, tags, result)",
|
||||||
|
"",
|
||||||
|
" -- initialize the result table on the default values",
|
||||||
|
" result.access = 0",
|
||||||
|
" result.speed = 0",
|
||||||
|
" result.factor = 1",
|
||||||
|
" result.direction = 0",
|
||||||
|
" result.canstop = true",
|
||||||
|
" result.attributes_to_keep = {}",
|
||||||
|
"",
|
||||||
|
" local access = " + _skeleton.ToLua(_profile.Access),
|
||||||
|
" if (access == nil or access == \"no\") then",
|
||||||
|
" return",
|
||||||
|
" end",
|
||||||
|
" tags.access = access",
|
||||||
|
" local oneway = " + _skeleton.ToLua(_profile.Oneway),
|
||||||
|
" tags.oneway = oneway",
|
||||||
|
" local speed = " + _skeleton.ToLua(_profile.Speed),
|
||||||
|
" tags.speed = speed",
|
||||||
|
" local distance = 1 -- the weight per meter for distance travelled is, well, 1m/m",
|
||||||
|
"");
|
||||||
|
|
||||||
|
impl +=
|
||||||
|
"\n local priority = 0\n ";
|
||||||
|
|
||||||
|
foreach (var (parameterName, expression) in _profile.Priority)
|
||||||
|
{
|
||||||
|
var paramInLua = _skeleton.ToLua(new Parameter(parameterName));
|
||||||
|
|
||||||
|
|
||||||
|
var exprInLua = _skeleton.ToLua(expression.Optimize());
|
||||||
|
var subs = new Curry(Typs.Tags, new Var(("a"))).UnificationTable(expression.Types.First());
|
||||||
|
if (subs != null && subs.TryGetValue("$a", out var resultType) &&
|
||||||
|
(resultType.Equals(Typs.Bool) || resultType.Equals(Typs.String)))
|
||||||
|
{
|
||||||
|
_skeleton. AddDep("parse");
|
||||||
|
exprInLua = "parse(" + exprInLua + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
impl += "\n " + string.Join("\n ",
|
||||||
|
$"if({paramInLua} ~= 0) then",
|
||||||
|
$" priority = priority + {paramInLua} * {exprInLua}",
|
||||||
|
"end"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl += string.Join("\n",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
" if (priority <= 0) then",
|
||||||
|
" result.access = 0",
|
||||||
|
" return",
|
||||||
|
" end",
|
||||||
|
"",
|
||||||
|
" result.access = 1",
|
||||||
|
" result.speed = speed",
|
||||||
|
" result.factor = 1 / priority",
|
||||||
|
"",
|
||||||
|
" if (oneway == \"both\") then",
|
||||||
|
" result.direction = 0",
|
||||||
|
" elseif (oneway == \"with\") then",
|
||||||
|
" result.direction = 1",
|
||||||
|
" elseif (oneway == \"against\") then",
|
||||||
|
" result.direction = 2",
|
||||||
|
" else",
|
||||||
|
" error(\"Unexpected value for oneway: \"..oneway)",
|
||||||
|
" end",
|
||||||
|
"",
|
||||||
|
"end"
|
||||||
|
);
|
||||||
|
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private (string functionName, string implementation) GenerateBehaviourFunction(
|
||||||
|
string behaviourName,
|
||||||
|
Dictionary<string, IExpression> behaviourParameters)
|
||||||
|
{
|
||||||
|
var referenceName = _profile.Name + "_" + behaviourName;
|
||||||
|
var functionName = referenceName.AsLuaIdentifier();
|
||||||
|
behaviourParameters.TryGetValue("description", out var description);
|
||||||
|
|
||||||
|
_skeleton.AddDep("remove_relation_prefix");
|
||||||
|
var impl = string.Join("\n",
|
||||||
|
"",
|
||||||
|
"--[[",
|
||||||
|
description,
|
||||||
|
"]]",
|
||||||
|
"function behaviour_" + functionName + "(tags, result)",
|
||||||
|
$" tags = remove_relation_prefix(tags, \"{behaviourName.AsLuaIdentifier()}\")",
|
||||||
|
" local parameters = default_parameters()",
|
||||||
|
" parameters.name = \"" + referenceName + "\"",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
impl += _parameterPrinter.DeclareParametersFor(behaviourParameters);
|
||||||
|
|
||||||
|
impl += " " + _profile.Name + "(parameters, tags, result)\n";
|
||||||
|
impl += "end\n";
|
||||||
|
return (functionName, impl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
AspectedRouting/IO/itinero1/LuaPrinter1.RelationPreprocessor.cs
Normal file
108
AspectedRouting/IO/itinero1/LuaPrinter1.RelationPreprocessor.cs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AspectedRouting.Language;
|
||||||
|
using AspectedRouting.Language.Expression;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.itinero1
|
||||||
|
{
|
||||||
|
public partial class LuaPrinter1
|
||||||
|
{
|
||||||
|
|
||||||
|
private (string implementation, HashSet<string> extraKeys) GenerateMembershipPreprocessor()
|
||||||
|
{
|
||||||
|
// Extra keys are the names of introduced tag-keys, e.g. '_relation:bicycle_fastest:cycle_highway'
|
||||||
|
var extraKeys = new HashSet<string>();
|
||||||
|
var memberships = Analysis.MembershipMappingsFor(_profile, _context);
|
||||||
|
|
||||||
|
foreach (var (calledInFunction, membership) in memberships)
|
||||||
|
{
|
||||||
|
var funcMetaData = new AspectMetadata(
|
||||||
|
membership,
|
||||||
|
"relation_preprocessing_for_" + calledInFunction.AsLuaIdentifier(),
|
||||||
|
"Function preprocessing needed for aspect " + calledInFunction +
|
||||||
|
", called by the relation preprocessor",
|
||||||
|
"Generator", "", "NA"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
_skeleton.AddFunction(funcMetaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var func = new List<string>
|
||||||
|
{
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"-- Processes the relation. All tags which are added to result.attributes_to_keep will be copied to 'attributes' of each individual way",
|
||||||
|
"function relation_tag_processor(relation_tags, result)",
|
||||||
|
" local parameters = {}",
|
||||||
|
" local subresult = {}",
|
||||||
|
" local matched = false",
|
||||||
|
" result.attributes_to_keep = {}",
|
||||||
|
" ",
|
||||||
|
" -- Legacy to add colours to the bike networks",
|
||||||
|
" legacy_relation_preprocessor(relation_tags, result)"
|
||||||
|
};
|
||||||
|
_skeleton.AddDep("legacy");
|
||||||
|
|
||||||
|
foreach (var (calledInFunction, expr) in memberships)
|
||||||
|
{
|
||||||
|
func.Add($"\n\n -- {calledInFunction} ---");
|
||||||
|
|
||||||
|
var usedParameters = expr.UsedParameters().Select(param => param.ParamName.TrimStart('#')).ToHashSet();
|
||||||
|
|
||||||
|
// First, we calculate the value for the default parameters
|
||||||
|
var preProcName = "relation_preprocessing_for_" + calledInFunction.AsLuaIdentifier();
|
||||||
|
func.Add("");
|
||||||
|
func.Add("");
|
||||||
|
func.Add(" subresult.attributes_to_keep = {}");
|
||||||
|
func.Add(" parameters = default_parameters()");
|
||||||
|
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
||||||
|
func.Add(" if (matched) then");
|
||||||
|
var tagKey = "_relation:" + calledInFunction.AsLuaIdentifier();
|
||||||
|
extraKeys.Add(tagKey);
|
||||||
|
func.Add(
|
||||||
|
" -- " + tagKey +
|
||||||
|
" is the default value, which will be overwritten in 'remove_relation_prefix' for behaviours having a different parameter settign");
|
||||||
|
func.Add($" result.attributes_to_keep[\"{tagKey}\"] = \"yes\"");
|
||||||
|
func.Add(" end");
|
||||||
|
|
||||||
|
|
||||||
|
if (usedParameters.Count() == 0)
|
||||||
|
{
|
||||||
|
// Every behaviour uses the default parameters for this one
|
||||||
|
func.Add(" -- No parameter dependence for aspect " + calledInFunction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (behaviourName, parameters) in _profile.Behaviours)
|
||||||
|
{
|
||||||
|
if (usedParameters.Except(parameters.Keys.ToHashSet()).Any())
|
||||||
|
{
|
||||||
|
// The parameters where the membership depends on, are not used here
|
||||||
|
// This is thus the same as the default. We don't have to calculate it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
func.Add("");
|
||||||
|
func.Add("");
|
||||||
|
func.Add(" subresult.attributes_to_keep = {}");
|
||||||
|
func.Add(" parameters = default_parameters()");
|
||||||
|
func.Add(_parameterPrinter.DeclareParametersFor(parameters.Where(kv => usedParameters.Contains(kv.Key))
|
||||||
|
.ToDictionary(kv => kv.Key, kv => kv.Value)));
|
||||||
|
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
||||||
|
func.Add(" if (matched) then");
|
||||||
|
tagKey = "_relation:" + behaviourName.AsLuaIdentifier() + ":" + calledInFunction.AsLuaIdentifier();
|
||||||
|
extraKeys.Add(tagKey);
|
||||||
|
func.Add($" result.attributes_to_keep[\"{tagKey}\"] = \"yes\"");
|
||||||
|
func.Add(" end");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func.Add("end");
|
||||||
|
|
||||||
|
return (string.Join("\n", func), extraKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
148
AspectedRouting/IO/itinero1/LuaPrinter1.cs
Normal file
148
AspectedRouting/IO/itinero1/LuaPrinter1.cs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AspectedRouting.Language;
|
||||||
|
using AspectedRouting.Language.Expression;
|
||||||
|
using AspectedRouting.Tests;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.itinero1
|
||||||
|
{
|
||||||
|
public partial class LuaPrinter1
|
||||||
|
{
|
||||||
|
private readonly ProfileMetaData _profile;
|
||||||
|
private readonly Context _context;
|
||||||
|
private readonly List<AspectTestSuite> _aspectTestSuites;
|
||||||
|
private readonly List<BehaviourTestSuite> _profileTests;
|
||||||
|
private readonly LuaSkeleton.LuaSkeleton _skeleton;
|
||||||
|
|
||||||
|
|
||||||
|
private readonly LuaParameterPrinter _parameterPrinter;
|
||||||
|
|
||||||
|
|
||||||
|
public LuaPrinter1(ProfileMetaData profile, Context context,
|
||||||
|
List<AspectTestSuite> aspectTestSuites,
|
||||||
|
List<BehaviourTestSuite> profileTests)
|
||||||
|
{
|
||||||
|
_profile = profile;
|
||||||
|
_context = context;
|
||||||
|
_aspectTestSuites = aspectTestSuites;
|
||||||
|
_profileTests = profileTests;
|
||||||
|
_skeleton = new LuaSkeleton.LuaSkeleton(context);
|
||||||
|
_parameterPrinter = new LuaParameterPrinter(profile, _skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToLua()
|
||||||
|
{
|
||||||
|
_skeleton.AddDep("spoken_instructions");
|
||||||
|
|
||||||
|
var (membershipFunction, extraKeys) = GenerateMembershipPreprocessor();
|
||||||
|
var (profileOverview, behaviourFunctions) = GenerateProfileFunctions();
|
||||||
|
var mainFunction = GenerateMainProfileFunction();
|
||||||
|
var tests = new LuaTestPrinter(_skeleton, new List<string>{"unitTest","unitTestProfile"}).GenerateFullTestSuite(_profileTests, _aspectTestSuites);
|
||||||
|
|
||||||
|
|
||||||
|
var keys = _profile.AllExpressions(_context).PossibleTags().Keys
|
||||||
|
.Concat(extraKeys)
|
||||||
|
.Select(key => "\"" + key + "\"")
|
||||||
|
.ToHashSet();
|
||||||
|
|
||||||
|
var header = new List<string>
|
||||||
|
{
|
||||||
|
$"-- Itinero 1.0-profile, generated by AspectedRouting on {DateTime.Now:s}",
|
||||||
|
$"name = \"{_profile.Name}\"",
|
||||||
|
"normalize = false",
|
||||||
|
"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 = {\n \"cycle_network_colour\"," // cycle network colour is sneaked in here for legacy reasons
|
||||||
|
+ string.Join("\n , ", _profile.Metadata.Select(s => "\"" + s + "\""))
|
||||||
|
+ " }",
|
||||||
|
"profile_whitelist = {\n " + string.Join("\n , ", keys) + "\n }",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
profileOverview,
|
||||||
|
"",
|
||||||
|
_parameterPrinter.GenerateDefaultParameters()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Add the aspect functions to the skeleton
|
||||||
|
var usedFunctions = _profile.CalledFunctionsRecursive(_context).Values.SelectMany(v => v).ToHashSet();
|
||||||
|
foreach (var functionName in usedFunctions)
|
||||||
|
{
|
||||||
|
_skeleton.AddFunction(_context.GetAspect(functionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The dependencies should be generated after all the other functions are generated, to make sure all are added
|
||||||
|
var dependencies = _skeleton.GenerateDependencies();
|
||||||
|
var functions = _skeleton.GenerateFunctions();
|
||||||
|
|
||||||
|
var allCode = new List<List<string>>
|
||||||
|
{
|
||||||
|
header,
|
||||||
|
behaviourFunctions,
|
||||||
|
mainFunction.InList(),
|
||||||
|
membershipFunction.InList(),
|
||||||
|
"---------------------- ASPECTS ----------------------".InList(),
|
||||||
|
functions,
|
||||||
|
"---------------------- UTILS ------------------------".InList(),
|
||||||
|
dependencies,
|
||||||
|
"----------------------- TESTS ------------------------".InList(),
|
||||||
|
tests.InList(),
|
||||||
|
GenerateLegacyTail().InList()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return string.Join("\n\n\n", allCode.Select(code => string.Join("\n", code)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private (string profilesOverview, List<string> behaviourImplementations) GenerateProfileFunctions()
|
||||||
|
{
|
||||||
|
// Profiles gets the contents for the 'profiles' field, part of the profile spec
|
||||||
|
var profiles = new List<string>();
|
||||||
|
var behaviourImplementations = new List<string>();
|
||||||
|
foreach (var (behaviourName, behaviourParameters) in _profile.Behaviours)
|
||||||
|
{
|
||||||
|
var (functionName, implementation ) = GenerateBehaviourFunction(behaviourName, behaviourParameters);
|
||||||
|
behaviourImplementations.Add(implementation);
|
||||||
|
profiles.Add(
|
||||||
|
string.Join(",\n ",
|
||||||
|
$" name = \"{behaviourName.AsLuaIdentifier()}\"",
|
||||||
|
" function_name = \"behaviour_" + functionName + "\"",
|
||||||
|
" metric = \"custom\""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var profilesOverview = "profiles = {\n {\n" +
|
||||||
|
string.Join("\n },\n {\n ", profiles) + "\n }\n}";
|
||||||
|
return (profilesOverview, behaviourImplementations);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GenerateLegacyTail()
|
||||||
|
{
|
||||||
|
return string.Join("\n",
|
||||||
|
"",
|
||||||
|
"if (itinero == nil) then",
|
||||||
|
" itinero = {}",
|
||||||
|
" itinero.log = print",
|
||||||
|
"",
|
||||||
|
" -- Itinero is not defined -> we are running from a lua interpreter -> the tests are intended",
|
||||||
|
" runTests = true",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"else",
|
||||||
|
" print = itinero.log",
|
||||||
|
"end",
|
||||||
|
"",
|
||||||
|
"test_all()",
|
||||||
|
"if (not failed_tests and not failed_profile_tests) then",
|
||||||
|
" print(\"Tests OK\")",
|
||||||
|
"end"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,297 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using AspectedRouting.Language;
|
|
||||||
using AspectedRouting.Language.Expression;
|
|
||||||
using AspectedRouting.Language.Functions;
|
|
||||||
using AspectedRouting.Language.Typ;
|
|
||||||
|
|
||||||
namespace AspectedRouting.IO.itinero1
|
|
||||||
{
|
|
||||||
public partial class LuaPrinter
|
|
||||||
{
|
|
||||||
private readonly Context _context;
|
|
||||||
|
|
||||||
public LuaPrinter(Context context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateMembershipPreprocessor(ProfileMetaData profile)
|
|
||||||
{
|
|
||||||
var memberships = Analysis.MembershipMappingsFor(profile, _context);
|
|
||||||
|
|
||||||
foreach (var (calledInFunction, membership) in memberships)
|
|
||||||
{
|
|
||||||
var funcMetaData = new AspectMetadata(
|
|
||||||
membership,
|
|
||||||
"relation_preprocessing_for_" + calledInFunction.FunctionName(),
|
|
||||||
"Function preprocessing needed for aspect " + calledInFunction +
|
|
||||||
", called by the relation preprocessor",
|
|
||||||
"Generator", "", "NA"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
AddFunction(funcMetaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var func = new List<string>
|
|
||||||
{
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"-- Processes the relation. All tags which are added to result.attributes_to_keep will be copied to 'attributes' of each individual way",
|
|
||||||
"function relation_tag_processor(relation_tags, result)",
|
|
||||||
" local parameters = {}",
|
|
||||||
" local subresult = {}",
|
|
||||||
" local matched = false",
|
|
||||||
" result.attributes_to_keep = {}"
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var (calledInFunction, expr) in memberships)
|
|
||||||
{
|
|
||||||
func.Add($"\n\n -- {calledInFunction} ---");
|
|
||||||
|
|
||||||
var usedParameters = expr.UsedParameters().Select(param => param.ParamName.TrimStart('#')).ToHashSet();
|
|
||||||
|
|
||||||
// First, we calculate the value for the default parameters
|
|
||||||
var preProcName = "relation_preprocessing_for_" + calledInFunction.FunctionName();
|
|
||||||
func.Add("");
|
|
||||||
func.Add("");
|
|
||||||
func.Add(" subresult.attributes_to_keep = {}");
|
|
||||||
func.Add(" parameters = default_parameters()");
|
|
||||||
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
|
||||||
func.Add(" if (matched) then");
|
|
||||||
var tagKey = "_relation:" + calledInFunction.FunctionName();
|
|
||||||
_neededKeys.Add(tagKey);
|
|
||||||
func.Add(
|
|
||||||
" -- " + tagKey +
|
|
||||||
" is the default value, which will be overwritten in 'remove_relation_prefix' for behaviours having a different parameter settign");
|
|
||||||
func.Add($" result.attributes_to_keep[\"{tagKey}\"] = \"yes\"");
|
|
||||||
func.Add(" end");
|
|
||||||
|
|
||||||
|
|
||||||
if (usedParameters.Count() == 0)
|
|
||||||
{
|
|
||||||
// Every behaviour uses the default parameters for this one
|
|
||||||
func.Add(" -- No parameter dependence for aspect " + calledInFunction);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (behaviourName, parameters) in profile.Behaviours)
|
|
||||||
{
|
|
||||||
if (usedParameters.Except(parameters.Keys.ToHashSet()).Any())
|
|
||||||
{
|
|
||||||
// The parameters where the membership depends on, are not used here
|
|
||||||
// This is thus the same as the default. We don't have to calculate it
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
func.Add("");
|
|
||||||
func.Add("");
|
|
||||||
func.Add(" subresult.attributes_to_keep = {}");
|
|
||||||
func.Add(" parameters = default_parameters()");
|
|
||||||
func.Add(ParametersToLua(parameters.Where(kv => usedParameters.Contains(kv.Key))
|
|
||||||
.ToDictionary(kv => kv.Key, kv => kv.Value)));
|
|
||||||
func.Add($" matched = {preProcName}(parameters, relation_tags, subresult)");
|
|
||||||
func.Add(" if (matched) then");
|
|
||||||
tagKey = "_relation:" + behaviourName.FunctionName() + ":" + calledInFunction.FunctionName();
|
|
||||||
_neededKeys.Add(tagKey);
|
|
||||||
func.Add($" result.attributes_to_keep[\"{tagKey}\"] = \"yes\"");
|
|
||||||
func.Add(" end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func.Add("end");
|
|
||||||
|
|
||||||
|
|
||||||
_code.Add(string.Join("\n", func));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the necessary called functions and the profile main entry point
|
|
||||||
/// </summary>
|
|
||||||
public void AddProfile(ProfileMetaData profile)
|
|
||||||
{
|
|
||||||
var defaultParameters = "\n";
|
|
||||||
foreach (var (name, (types, inFunction)) in profile.UsedParameters(_context))
|
|
||||||
{
|
|
||||||
defaultParameters += $"{name}: {string.Join(", ", types)}\n" +
|
|
||||||
$" Used in {inFunction}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateMembershipPreprocessor(profile);
|
|
||||||
|
|
||||||
|
|
||||||
var impl = string.Join("\n",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
$"name = \"{profile.Name}\"",
|
|
||||||
"normalize = false",
|
|
||||||
"vehicle_type = {" + string.Join(", ", profile.VehicleTyps.Select(s => "\"" + s + "\"")) + "}",
|
|
||||||
"meta_whitelist = {\n " + string.Join("\n , ", profile.Metadata.Select(s => "\"" + s + "\"")) +
|
|
||||||
"}",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"--[[",
|
|
||||||
profile.Name,
|
|
||||||
"This is the main function called to calculate the access, oneway and speed.",
|
|
||||||
"Comfort is calculated as well, based on the parameters which are padded in",
|
|
||||||
"",
|
|
||||||
"Created by " + profile.Author,
|
|
||||||
"Originally defined in " + profile.Filename,
|
|
||||||
"Used parameters: " + defaultParameters.Indent(),
|
|
||||||
"]]",
|
|
||||||
"function " + profile.Name + "(parameters, tags, result)",
|
|
||||||
"",
|
|
||||||
" -- initialize the result table on the default values",
|
|
||||||
" result.access = 0",
|
|
||||||
" result.speed = 0",
|
|
||||||
" result.factor = 1",
|
|
||||||
" result.direction = 0",
|
|
||||||
" result.canstop = true",
|
|
||||||
" result.attributes_to_keep = {}",
|
|
||||||
"",
|
|
||||||
" local access = " + ToLua(profile.Access),
|
|
||||||
" if (access == nil or access == \"no\") then",
|
|
||||||
" return",
|
|
||||||
" end",
|
|
||||||
" tags.access = access",
|
|
||||||
" local oneway = " + ToLua(profile.Oneway),
|
|
||||||
" tags.oneway = oneway",
|
|
||||||
" local speed = " + ToLua(profile.Speed),
|
|
||||||
" tags.speed = speed",
|
|
||||||
" local distance = 1 -- the weight per meter for distance travelled is, well, 1m/m",
|
|
||||||
"");
|
|
||||||
|
|
||||||
impl +=
|
|
||||||
"\n local priority = 0\n ";
|
|
||||||
|
|
||||||
foreach (var (parameterName, expression) in profile.Priority)
|
|
||||||
{
|
|
||||||
var paramInLua = ToLua(new Parameter(parameterName));
|
|
||||||
|
|
||||||
|
|
||||||
var exprInLua = ToLua(expression);
|
|
||||||
var subs = new Curry(Typs.Tags, new Var(("a"))).UnificationTable(expression.Types.First());
|
|
||||||
if (subs != null && subs.TryGetValue("$a", out var resultType) &&
|
|
||||||
(resultType.Equals(Typs.Bool) || resultType.Equals(Typs.String)))
|
|
||||||
{
|
|
||||||
AddDep("parse");
|
|
||||||
exprInLua = "parse(" + exprInLua + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl += "\n " + string.Join("\n ",
|
|
||||||
$"if({paramInLua} ~= 0) then",
|
|
||||||
$" priority = priority + {paramInLua} * {exprInLua}",
|
|
||||||
"end"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl += string.Join("\n",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
" if (priority <= 0) then",
|
|
||||||
" result.access = 0",
|
|
||||||
" return",
|
|
||||||
" end",
|
|
||||||
"",
|
|
||||||
" result.access = 1",
|
|
||||||
" result.speed = speed",
|
|
||||||
" result.factor = 1 / priority",
|
|
||||||
"",
|
|
||||||
" if (oneway == \"both\") then",
|
|
||||||
" result.direction = 0",
|
|
||||||
" elseif (oneway == \"with\") then",
|
|
||||||
" result.direction = 1",
|
|
||||||
" elseif (oneway == \"against\") then",
|
|
||||||
" result.direction = 2",
|
|
||||||
" else",
|
|
||||||
" error(\"Unexpected value for oneway: \"..oneway)",
|
|
||||||
" end",
|
|
||||||
"",
|
|
||||||
"end",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"function default_parameters()",
|
|
||||||
" local parameters = {}",
|
|
||||||
ParametersToLua(profile.DefaultParameters),
|
|
||||||
" return parameters",
|
|
||||||
"end",
|
|
||||||
"",
|
|
||||||
""
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
var profiles = new List<string>();
|
|
||||||
foreach (var (name, subParams) in profile.Behaviours)
|
|
||||||
{
|
|
||||||
impl += BehaviourFunction(profile, name, subParams, profiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl += "\n\n\n";
|
|
||||||
impl += "profiles = {\n {\n" +
|
|
||||||
string.Join("\n },\n {\n ", profiles) + "\n }\n}";
|
|
||||||
|
|
||||||
_code.Add(impl);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string BehaviourFunction(ProfileMetaData profile,
|
|
||||||
string name,
|
|
||||||
Dictionary<string, IExpression> subParams, List<string> profiles)
|
|
||||||
{
|
|
||||||
var functionName = profile.Name + "_" + name;
|
|
||||||
|
|
||||||
subParams.TryGetValue("description", out var description);
|
|
||||||
profiles.Add(
|
|
||||||
string.Join(",\n ",
|
|
||||||
$" name = \"{name.FunctionName()}\"",
|
|
||||||
" function_name = \"behaviour_" + functionName.FunctionName() + "\"",
|
|
||||||
" metric = \"custom\""
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
AddDep("remove_relation_prefix");
|
|
||||||
var impl = string.Join("\n",
|
|
||||||
"",
|
|
||||||
"--[[",
|
|
||||||
description,
|
|
||||||
"]]",
|
|
||||||
"function behaviour_" + functionName.FunctionName() + "(tags, result)",
|
|
||||||
$" tags = remove_relation_prefix(tags, \"{name.FunctionName()}\")",
|
|
||||||
" local parameters = default_parameters()",
|
|
||||||
" parameters.name = \"" + functionName + "\"",
|
|
||||||
""
|
|
||||||
);
|
|
||||||
|
|
||||||
impl += ParametersToLua(subParams);
|
|
||||||
|
|
||||||
impl += " " + profile.Name + "(parameters, tags, result)\n";
|
|
||||||
impl += "end\n";
|
|
||||||
return impl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// `local parameters = default_parameters()` must still be invoked by caller!
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="subParams"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string ParametersToLua(Dictionary<string, IExpression> subParams)
|
|
||||||
{
|
|
||||||
var impl = "";
|
|
||||||
foreach (var (paramName, value) in subParams)
|
|
||||||
{
|
|
||||||
if (paramName.Equals("description"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl += $" parameters.{paramName.TrimStart('#').FunctionName()} = {ToLua(value)}\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return impl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using AspectedRouting.Tests;
|
|
||||||
|
|
||||||
namespace AspectedRouting.IO.itinero1
|
|
||||||
{
|
|
||||||
public partial class LuaPrinter
|
|
||||||
{
|
|
||||||
public void AddTestSuite(ProfileTestSuite testSuite)
|
|
||||||
{
|
|
||||||
var tests = string.Join("\n",
|
|
||||||
testSuite.Tests.Select((test, i) => ToLua(testSuite, i, test.Item1, test.tags)));
|
|
||||||
_tests.Add(tests);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ToLua(ProfileTestSuite testSuite, int index, ProfileResult expected, Dictionary<string, string> tags)
|
|
||||||
{
|
|
||||||
AddDep("debug_table");
|
|
||||||
var parameters = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
|
|
||||||
var keysToCheck = new List<string>();
|
|
||||||
foreach (var (key, value) in tags)
|
|
||||||
{
|
|
||||||
if (key.StartsWith("#"))
|
|
||||||
{
|
|
||||||
parameters[key.TrimStart('#')] = value;
|
|
||||||
}
|
|
||||||
if(key.StartsWith("_relation:"))
|
|
||||||
{
|
|
||||||
keysToCheck.Add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var key in keysToCheck)
|
|
||||||
{
|
|
||||||
var newKey = key.Replace(".", "_");
|
|
||||||
tags[newKey] = tags[key];
|
|
||||||
tags.Remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (paramName, _) in parameters)
|
|
||||||
{
|
|
||||||
tags.Remove("#" + paramName);
|
|
||||||
}
|
|
||||||
// function unit_test_profile(profile_function, profile_name, index, expected, tags)
|
|
||||||
|
|
||||||
return $"unit_test_profile(behaviour_{testSuite.Profile.Name.FunctionName()}_{testSuite.BehaviourName.FunctionName()}, " +
|
|
||||||
$"\"{testSuite.BehaviourName}\", " +
|
|
||||||
$"{index}, " +
|
|
||||||
$"{{access = \"{D(expected.Access)}\", speed = {expected.Speed}, oneway = \"{D(expected.Oneway)}\", weight = {expected.Priority} }}, " +
|
|
||||||
tags.ToLuaTable() +
|
|
||||||
")";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string D(string s)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(s))
|
|
||||||
{
|
|
||||||
return "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void AddTestSuite(AspectTestSuite testSuite)
|
|
||||||
{
|
|
||||||
var fName = testSuite.FunctionToApply.Name;
|
|
||||||
var tests = string.Join("\n",
|
|
||||||
testSuite.Tests.Select((test, i) => ToLua(fName, i, test.expected, test.tags)));
|
|
||||||
_tests.Add(tests);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ToLua(string functionToApplyName, int index, string expected, Dictionary<string, string> tags)
|
|
||||||
{
|
|
||||||
var parameters = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var (key, value) in tags)
|
|
||||||
{
|
|
||||||
if (key.StartsWith("#"))
|
|
||||||
{
|
|
||||||
parameters[key.TrimStart('#')] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (paramName, _) in parameters)
|
|
||||||
{
|
|
||||||
tags.Remove("#" + paramName);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddDep("unitTest");
|
|
||||||
AddDep("debug_table");
|
|
||||||
var funcName = functionToApplyName.Replace(" ", "_").Replace(".", "_");
|
|
||||||
return
|
|
||||||
$"unit_test({funcName}, \"{functionToApplyName}\", {index}, \"{expected}\", {parameters.ToLuaTable()}, {tags.ToLuaTable()})";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
145
AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs
Normal file
145
AspectedRouting/IO/itinero2/LuaPrinter2.MainFunction.cs
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AspectedRouting.Language;
|
||||||
|
using AspectedRouting.Language.Typ;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.itinero2
|
||||||
|
{
|
||||||
|
public partial class LuaPrinter2
|
||||||
|
{
|
||||||
|
private string GenerateFactorFunction()
|
||||||
|
{
|
||||||
|
var parameters = new Dictionary<string, IExpression>();
|
||||||
|
foreach (var (name, value) in _profile.DefaultParameters)
|
||||||
|
{
|
||||||
|
parameters[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (name, value) in _profile.Behaviours[_behaviourName])
|
||||||
|
{
|
||||||
|
parameters[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var aspects = new List<string>();
|
||||||
|
|
||||||
|
foreach (var (paramName, expr) in _profile.Priority)
|
||||||
|
{
|
||||||
|
var paramExpr = parameters[paramName].Evaluate(_context);
|
||||||
|
if (!(paramExpr is double weight))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weight == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expression = _profile.Priority[paramName];
|
||||||
|
var exprInLua = _skeleton.ToLua(expression);
|
||||||
|
var subs = new Curry(Typs.Tags, new Var(("a"))).UnificationTable(expression.Types.First());
|
||||||
|
if (subs != null && subs.TryGetValue("$a", out var resultType) &&
|
||||||
|
(resultType.Equals(Typs.Bool) || resultType.Equals(Typs.String)))
|
||||||
|
{
|
||||||
|
_skeleton.AddDep("parse");
|
||||||
|
exprInLua = "parse(" + exprInLua + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
aspects.Add(weight + " * " + exprInLua);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(aspects.Lined());
|
||||||
|
var code = new List<string>()
|
||||||
|
{
|
||||||
|
"--[[",
|
||||||
|
"Generates the factor according to the priorities and the parameters for this behaviour",
|
||||||
|
"Note: 'result' is not actually used",
|
||||||
|
"]]",
|
||||||
|
"function calculate_priority(parameters, tags, result, access, oneway, speed)",
|
||||||
|
" local distance = 1",
|
||||||
|
" local priority = \n " + string.Join(" +\n ", aspects),
|
||||||
|
" return priority",
|
||||||
|
"end"
|
||||||
|
};
|
||||||
|
return code.Lined();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateMainFunction()
|
||||||
|
{
|
||||||
|
var parameters = _profile.Behaviours[_behaviourName];
|
||||||
|
|
||||||
|
_skeleton.AddDependenciesFor(_profile.Access);
|
||||||
|
_skeleton.AddDependenciesFor(_profile.Oneway);
|
||||||
|
_skeleton.AddDependenciesFor(_profile.Speed);
|
||||||
|
|
||||||
|
_skeleton.AddDep("eq");
|
||||||
|
var code = new List<string>
|
||||||
|
{
|
||||||
|
"--[[",
|
||||||
|
_profile.Behaviours[_behaviourName]["description"].Evaluate(_context).ToString(),
|
||||||
|
"]]",
|
||||||
|
"function factor(tags, result)",
|
||||||
|
" ",
|
||||||
|
" -- initialize the result table on the default values",
|
||||||
|
" result.forward_speed = 0",
|
||||||
|
" result.backward_speed = 0",
|
||||||
|
" result.forward = 0",
|
||||||
|
" result.backward = 0",
|
||||||
|
" result.canstop = true",
|
||||||
|
" result.attributes_to_keep = {} -- not actually used anymore, but the code generation still uses this",
|
||||||
|
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
" local parameters = default_parameters()",
|
||||||
|
_parameterPrinter.DeclareParametersFor(parameters),
|
||||||
|
"",
|
||||||
|
" local oneway = " + _skeleton.ToLua(_profile.Oneway),
|
||||||
|
" tags.oneway = oneway",
|
||||||
|
" -- forward calculation",
|
||||||
|
" tags[\"_direction\"] = \"with\"",
|
||||||
|
" local access_forward = " + _skeleton.ToLua(_profile.Access),
|
||||||
|
" if(oneway == \"against\") then",
|
||||||
|
" access_forward = \"no\"",
|
||||||
|
" end",
|
||||||
|
|
||||||
|
" if(access_forward ~= nil and access_forward ~= \"no\") then",
|
||||||
|
" tags.access = access_forward",
|
||||||
|
" result.forward_speed = " + _skeleton.ToLua(_profile.Speed).Indent(),
|
||||||
|
" tags.speed = result.forward_speed",
|
||||||
|
" local priority = calculate_priority(parameters, tags, result, access_forward, oneway, result.forward_speed)",
|
||||||
|
" if (priority <= 0) then",
|
||||||
|
" result.forward_speed = 0",
|
||||||
|
" else",
|
||||||
|
" result.forward = 1 / priority",
|
||||||
|
" end",
|
||||||
|
" end",
|
||||||
|
"",
|
||||||
|
" -- backward calculation",
|
||||||
|
" tags[\"_direction\"] = \"against\"",
|
||||||
|
" local access_backward = " + _skeleton.ToLua(_profile.Access),
|
||||||
|
"",
|
||||||
|
" if(oneway == \"with\") then",
|
||||||
|
" access_backward = \"no\"",
|
||||||
|
" end",
|
||||||
|
"",
|
||||||
|
" if(access_backward ~= nil and access_backward ~= \"no\") then",
|
||||||
|
" tags.access = access_backward" +
|
||||||
|
" result.backward_speed = " + _skeleton.ToLua(_profile.Speed).Indent(),
|
||||||
|
" tags.speed = result.backward_speed",
|
||||||
|
" local priority = calculate_priority(parameters, tags, result, access_backward, oneway, result.backward_speed)",
|
||||||
|
" if (priority <= 0) then",
|
||||||
|
" result.backward_speed = 0",
|
||||||
|
" else",
|
||||||
|
" result.backward = 1 / priority",
|
||||||
|
" end",
|
||||||
|
" end",
|
||||||
|
|
||||||
|
"end"
|
||||||
|
};
|
||||||
|
|
||||||
|
return code.Lined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
AspectedRouting/IO/itinero2/LuaPrinter2.cs
Normal file
104
AspectedRouting/IO/itinero2/LuaPrinter2.cs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using AspectedRouting.IO.itinero1;
|
||||||
|
using AspectedRouting.Language;
|
||||||
|
using AspectedRouting.Language.Expression;
|
||||||
|
using AspectedRouting.Tests;
|
||||||
|
|
||||||
|
namespace AspectedRouting.IO.itinero2
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Lua printer for itinero2-lua format
|
||||||
|
///
|
||||||
|
/// The itinero 2.0 lua profile is a whole lot simpler then the 1.0 format,
|
||||||
|
/// as a single profile there only describes a single behaviour of a vehicle:
|
||||||
|
///
|
||||||
|
/// It has:
|
||||||
|
/// - name: string, e.g. 'bicycle.fastest'
|
||||||
|
/// - factor(attributes, result): void, where 'attributes' are all the tags of the way,
|
||||||
|
/// and result must contain (after calling):
|
||||||
|
/// - 'forward_speed', a double describing the forward speed (in km/h)
|
||||||
|
/// - 'backward_speed', the speed when travelling in the opposite direction (0 if not possible)
|
||||||
|
/// - 'forward', a double describing the forwardfactor
|
||||||
|
/// - 'backward', the backward factor
|
||||||
|
/// - 'canstop', a boolean indicating if stopping along the road is possible
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public partial class LuaPrinter2
|
||||||
|
{
|
||||||
|
private readonly ProfileMetaData _profile;
|
||||||
|
private readonly string _behaviourName;
|
||||||
|
private readonly Context _context;
|
||||||
|
private readonly List<AspectTestSuite> _aspectTests;
|
||||||
|
private readonly IEnumerable<BehaviourTestSuite> _behaviourTestSuite;
|
||||||
|
|
||||||
|
private readonly LuaSkeleton.LuaSkeleton _skeleton;
|
||||||
|
private readonly LuaParameterPrinter _parameterPrinter;
|
||||||
|
|
||||||
|
|
||||||
|
public LuaPrinter2(ProfileMetaData profile, string behaviourName,
|
||||||
|
Context context,
|
||||||
|
List<AspectTestSuite> aspectTests, IEnumerable<BehaviourTestSuite> behaviourTestSuite)
|
||||||
|
{
|
||||||
|
_skeleton = new LuaSkeleton.LuaSkeleton(context);
|
||||||
|
_profile = profile;
|
||||||
|
_behaviourName = behaviourName;
|
||||||
|
_context = context;
|
||||||
|
_aspectTests = aspectTests;
|
||||||
|
_behaviourTestSuite = behaviourTestSuite;
|
||||||
|
_parameterPrinter = new LuaParameterPrinter(_profile, _skeleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToLua()
|
||||||
|
{
|
||||||
|
var header =
|
||||||
|
new List<string>
|
||||||
|
{
|
||||||
|
$"name = \"{_profile.Name}.{_behaviourName}\"",
|
||||||
|
$"generationDate = \"{DateTime.Now:s}\"",
|
||||||
|
$"description = \"{_profile.Description}\""
|
||||||
|
};
|
||||||
|
|
||||||
|
var tests = new LuaTestPrinter(_skeleton, new List<string>() {"unitTestProfile2"}).GenerateFullTestSuite(
|
||||||
|
_behaviourTestSuite.ToList(), new List<AspectTestSuite>());
|
||||||
|
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!
|
||||||
|
"",
|
||||||
|
tests,
|
||||||
|
"",
|
||||||
|
|
||||||
|
"if (itinero == nil) then",
|
||||||
|
" itinero = {}",
|
||||||
|
" itinero.log = print",
|
||||||
|
"",
|
||||||
|
" -- Itinero is not defined -> we are running from a lua interpreter -> the tests are intended",
|
||||||
|
" runTests = true",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"else",
|
||||||
|
" print = itinero.log",
|
||||||
|
"end",
|
||||||
|
"",
|
||||||
|
"test_all()",
|
||||||
|
"if (not failed_tests and not failed_profile_tests and print ~= nil) then",
|
||||||
|
" print(\"Tests OK\")",
|
||||||
|
"end"
|
||||||
|
};
|
||||||
|
|
||||||
|
return all.Lined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
AspectedRouting/IO/lua/legacy.lua
Normal file
17
AspectedRouting/IO/lua/legacy.lua
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
--[[
|
||||||
|
Legacy function to add cycle_colour
|
||||||
|
]]
|
||||||
|
|
||||||
|
function legacy_relation_preprocessor(attributes, result)
|
||||||
|
if (attributes.route == "bicycle") then
|
||||||
|
-- This is a cycling network, the colour is copied
|
||||||
|
if (attributes.colour ~= nil) then
|
||||||
|
result.attributes_to_keep.cycle_network_colour = attributes.colour
|
||||||
|
end
|
||||||
|
|
||||||
|
if (attributes.color ~= nil) then
|
||||||
|
-- for the americans!
|
||||||
|
result.attributes_to_keep.cycle_network_colour = attributes.color
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,20 +1,20 @@
|
||||||
failed_profile_tests = false
|
failed_profile_tests = false
|
||||||
--[[
|
--[[
|
||||||
expected should be a table containing 'access', 'speed' and 'weight'
|
expected should be a table containing 'access', 'speed' and 'priority'
|
||||||
]]
|
]]
|
||||||
function unit_test_profile(profile_function, profile_name, index, expected, tags)
|
function unit_test_profile(profile_function, profile_name, index, expected, tags)
|
||||||
local result = { attributes_to_keep = {} }
|
local result = { attributes_to_keep = {} }
|
||||||
local profile_failed = false
|
local profile_failed = false
|
||||||
profile_function(tags, result)
|
profile_function(tags, result)
|
||||||
|
|
||||||
local accessCorrect = (result.access == 0 and (expected.access == "no" or expected.weight <= 0)) or result.access == 1
|
local accessCorrect = (result.access == 0 and (expected.access == "no" or expected.priority <= 0)) or result.access == 1
|
||||||
if (not accessCorrect) then
|
if (not accessCorrect) then
|
||||||
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".access: expected " .. expected.access .. " but got " .. result.access)
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".access: expected " .. expected.access .. " but got " .. result.access)
|
||||||
profile_failed = true
|
profile_failed = true
|
||||||
failed_profile_tests = true
|
failed_profile_tests = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if (expected.access == "no" or expected.weight <= 0) then
|
if (expected.access == "no" or expected.priority <= 0) then
|
||||||
-- we cannot access this road, the other results are irrelevant
|
-- we cannot access this road, the other results are irrelevant
|
||||||
if (profile_failed) then
|
if (profile_failed) then
|
||||||
print("The used tags for test " .. tostring(index) .. " are:")
|
print("The used tags for test " .. tostring(index) .. " are:")
|
||||||
|
@ -46,8 +46,8 @@ function unit_test_profile(profile_function, profile_name, index, expected, tags
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if (not double_compare(result.factor, 1/expected.weight)) then
|
if (not double_compare(result.factor, 1/expected.priority)) then
|
||||||
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".factor: expected " .. expected.weight .. " but got " .. 1/result.factor)
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".factor: expected " .. expected.priority .. " but got " .. 1/result.factor)
|
||||||
failed_profile_tests = true
|
failed_profile_tests = true
|
||||||
profile_failed = true
|
profile_failed = true
|
||||||
end
|
end
|
||||||
|
|
67
AspectedRouting/IO/lua/unitTestProfile2.lua
Normal file
67
AspectedRouting/IO/lua/unitTestProfile2.lua
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
failed_profile_tests = false
|
||||||
|
--[[
|
||||||
|
Unit test of a behaviour function for an itinero 2.0 profile
|
||||||
|
]]
|
||||||
|
|
||||||
|
function unit_test_profile(profile_function, profile_name, index, expected, tags)
|
||||||
|
-- Note: we don't actually use 'profile_function'
|
||||||
|
|
||||||
|
local result = {}
|
||||||
|
local profile_failed = false
|
||||||
|
factor(tags, result)
|
||||||
|
|
||||||
|
|
||||||
|
local forward_access = result.forward_speed > 0 and result.forward > 0;
|
||||||
|
local backward_access = result.backward_speed > 0 and result.backward > 0;
|
||||||
|
|
||||||
|
if (not forward_access and not backward_access) then
|
||||||
|
|
||||||
|
if (expected.access == "no" or expected.speed <= 0 or expected.priority <= 0) then
|
||||||
|
-- All is fine, we can't access this thing anyway
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
profile_failed = true
|
||||||
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".access: expected " .. expected.access .. " but forward and backward are 0 (for either speed or factor)")
|
||||||
|
end
|
||||||
|
|
||||||
|
if (expected.oneway == "with") then
|
||||||
|
if (backward_access) then
|
||||||
|
-- we can go against the direction, not good
|
||||||
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".oneway: expected " .. expected.oneway .. " but going against the direction is possible")
|
||||||
|
profile_failed = true;
|
||||||
|
end
|
||||||
|
if (not forward_access) then
|
||||||
|
print("Test " .. tostring(index) .. " warning for " .. profile_name .. ".oneway: expected " .. expected.oneway .. " but going with the direction is not possible")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (expected.oneway == "against") then
|
||||||
|
if (forward_access) then
|
||||||
|
-- we can go against the direction, not good
|
||||||
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".oneway: expected " .. expected.oneway .. " but going with the direction is possible")
|
||||||
|
end
|
||||||
|
if (not backward_access) then
|
||||||
|
print("Test " .. tostring(index) .. " warning for " .. profile_name .. ".oneway: expected " .. expected.oneway .. " but going against the direction is not possible")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (result.forward_speed ~= expected.speed and result.backward_speed ~= expected.speed) then
|
||||||
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".speed: expected " .. expected.speed .. " but got " .. result.forward_speed .. " forward and " .. result.backward_speed .. " backward")
|
||||||
|
profile_failed = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (result.forward ~= expected.priority and result.backward ~= expected.priority) then
|
||||||
|
print("Test " .. tostring(index) .. " failed for " .. profile_name .. ".priority: expected " .. expected.priority .. " but got " .. result.forward .. " forward and " .. result.backward .. " backward")
|
||||||
|
profile_failed = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if(profile_failed) then
|
||||||
|
failed_profile_tests = true;
|
||||||
|
debug_table(tags, "tags: ")
|
||||||
|
debug_table(expected, "expected: ")
|
||||||
|
debug_table(result, "result: ")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -207,6 +207,8 @@ namespace AspectedRouting.Language
|
||||||
{
|
{
|
||||||
// Read as: this function calls the value-function
|
// Read as: this function calls the value-function
|
||||||
var result = new Dictionary<string, List<string>>();
|
var result = new Dictionary<string, List<string>>();
|
||||||
|
|
||||||
|
|
||||||
var calledFunctions = new Queue<string>();
|
var calledFunctions = new Queue<string>();
|
||||||
|
|
||||||
void ScanExpression(IExpression e, string inFunction)
|
void ScanExpression(IExpression e, string inFunction)
|
||||||
|
@ -252,6 +254,62 @@ namespace AspectedRouting.Language
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static (HashSet<string> parameterName, HashSet<string> calledFunctionNames) DirectlyAndInderectlyCalled(
|
||||||
|
this List<IExpression> exprs, Context ctx)
|
||||||
|
{
|
||||||
|
var parameters = new HashSet<string>();
|
||||||
|
var dependencies = new HashSet<string>();
|
||||||
|
|
||||||
|
var queue = new Queue<IExpression>();
|
||||||
|
exprs.ForEach(queue.Enqueue);
|
||||||
|
|
||||||
|
while (queue.TryDequeue(out var next))
|
||||||
|
{
|
||||||
|
var (p, deps) = next.DirectlyCalled();
|
||||||
|
parameters.UnionWith(p);
|
||||||
|
var toCheck = deps.Except(dependencies);
|
||||||
|
dependencies.UnionWith(deps);
|
||||||
|
|
||||||
|
foreach (var fName in toCheck)
|
||||||
|
{
|
||||||
|
queue.Enqueue(ctx.GetFunction(fName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (parameters, dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates an overview of the dependencies of the expression, both which parameters it needs and what other functions (builtin or defined) it needs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="expr"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static (HashSet<string> parameterName, HashSet<string> calledFunctionNames) DirectlyCalled(
|
||||||
|
this IExpression expr)
|
||||||
|
{
|
||||||
|
var parameters = new HashSet<string>();
|
||||||
|
var dependencies = new HashSet<string>();
|
||||||
|
|
||||||
|
expr.Visit(e =>
|
||||||
|
{
|
||||||
|
if (e is FunctionCall fc)
|
||||||
|
{
|
||||||
|
dependencies.Add(fc.CalledFunctionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e is Parameter p)
|
||||||
|
{
|
||||||
|
parameters.Add(p.ParamName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return (parameters, dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
public static string TypeBreakdown(this IExpression e)
|
public static string TypeBreakdown(this IExpression e)
|
||||||
{
|
{
|
||||||
var text = "";
|
var text = "";
|
||||||
|
@ -404,12 +462,12 @@ namespace AspectedRouting.Language
|
||||||
var usedTags = new Dictionary<string, HashSet<string>>();
|
var usedTags = new Dictionary<string, HashSet<string>>();
|
||||||
foreach (var expr in exprs)
|
foreach (var expr in exprs)
|
||||||
{
|
{
|
||||||
|
|
||||||
var possible = expr.PossibleTags();
|
var possible = expr.PossibleTags();
|
||||||
if (possible == null)
|
if (possible == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (key, values) in possible)
|
foreach (var (key, values) in possible)
|
||||||
{
|
{
|
||||||
if (!usedTags.TryGetValue(key, out var collection))
|
if (!usedTags.TryGetValue(key, out var collection))
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace AspectedRouting.Language
|
||||||
public class Context
|
public class Context
|
||||||
{
|
{
|
||||||
public readonly Dictionary<string, IExpression> Parameters = new Dictionary<string, IExpression>();
|
public readonly Dictionary<string, IExpression> Parameters = new Dictionary<string, IExpression>();
|
||||||
|
|
||||||
public readonly Dictionary<string, AspectMetadata> DefinedFunctions = new Dictionary<string, AspectMetadata>();
|
public readonly Dictionary<string, AspectMetadata> DefinedFunctions = new Dictionary<string, AspectMetadata>();
|
||||||
|
|
||||||
public readonly string AspectName;
|
public readonly string AspectName;
|
||||||
|
@ -48,6 +49,23 @@ namespace AspectedRouting.Language
|
||||||
DefinedFunctions[name] = function;
|
DefinedFunctions[name] = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AspectMetadata GetAspect(string name)
|
||||||
|
{
|
||||||
|
if (name.StartsWith("$"))
|
||||||
|
{
|
||||||
|
name = name.Substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DefinedFunctions.ContainsKey(name))
|
||||||
|
{
|
||||||
|
return DefinedFunctions[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(
|
||||||
|
$"The aspect {name} is not a defined function. Known functions are " +
|
||||||
|
string.Join(", ", DefinedFunctions.Keys));
|
||||||
|
}
|
||||||
|
|
||||||
public IExpression GetFunction(string name)
|
public IExpression GetFunction(string name)
|
||||||
{
|
{
|
||||||
if (name.StartsWith("$"))
|
if (name.StartsWith("$"))
|
||||||
|
|
|
@ -185,6 +185,8 @@ namespace AspectedRouting.Language.Expression
|
||||||
return Funcs.Id;
|
return Funcs.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (Types.Count() > 1)
|
if (Types.Count() > 1)
|
||||||
{
|
{
|
||||||
|
@ -198,6 +200,18 @@ namespace AspectedRouting.Language.Expression
|
||||||
|
|
||||||
return new Apply(_debugInfo, optimized);
|
return new Apply(_debugInfo, optimized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var arg = new List<IExpression>();
|
||||||
|
if (
|
||||||
|
Deconstruct.UnApplyAny(
|
||||||
|
Deconstruct.IsFunc(Funcs.Id),
|
||||||
|
Deconstruct.Assign(arg)
|
||||||
|
).Invoke(this))
|
||||||
|
{
|
||||||
|
return arg.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var (f, a) = FunctionApplications.Values.First();
|
var (f, a) = FunctionApplications.Values.First();
|
||||||
|
@ -274,6 +288,7 @@ namespace AspectedRouting.Language.Expression
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (_, (f, a)) in FunctionApplications)
|
foreach (var (_, (f, a)) in FunctionApplications)
|
||||||
{
|
{
|
||||||
f.Visit(visitor);
|
f.Visit(visitor);
|
||||||
|
|
|
@ -35,9 +35,9 @@ namespace AspectedRouting.Language.Expression
|
||||||
Author = author;
|
Author = author;
|
||||||
Filename = filename;
|
Filename = filename;
|
||||||
VehicleTyps = vehicleTyps;
|
VehicleTyps = vehicleTyps;
|
||||||
Access = access;
|
Access = access.Optimize();
|
||||||
Oneway = oneway;
|
Oneway = oneway.Optimize();
|
||||||
Speed = speed;
|
Speed = speed.Optimize();
|
||||||
Priority = priority;
|
Priority = priority;
|
||||||
Metadata = metadata;
|
Metadata = metadata;
|
||||||
DefaultParameters = defaultParameters;
|
DefaultParameters = defaultParameters;
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AspectedRouting.IO;
|
using AspectedRouting.IO;
|
||||||
using AspectedRouting.IO.itinero1;
|
using AspectedRouting.IO.itinero1;
|
||||||
|
using AspectedRouting.IO.itinero2;
|
||||||
using AspectedRouting.IO.jsonParser;
|
using AspectedRouting.IO.jsonParser;
|
||||||
using AspectedRouting.Language;
|
using AspectedRouting.Language;
|
||||||
using AspectedRouting.Language.Expression;
|
using AspectedRouting.Language.Expression;
|
||||||
|
@ -13,7 +14,7 @@ namespace AspectedRouting
|
||||||
{
|
{
|
||||||
static class Program
|
static class Program
|
||||||
{
|
{
|
||||||
public static IEnumerable<(AspectMetadata aspect, AspectTestSuite tests)> ParseAspects(
|
public static List<(AspectMetadata aspect, AspectTestSuite tests)> ParseAspects(
|
||||||
this IEnumerable<string> jsonFileNames, List<string> testFileNames, Context context)
|
this IEnumerable<string> jsonFileNames, List<string> testFileNames, Context context)
|
||||||
{
|
{
|
||||||
var aspects = new List<(AspectMetadata aspect, AspectTestSuite tests)>();
|
var aspects = new List<(AspectMetadata aspect, AspectTestSuite tests)>();
|
||||||
|
@ -55,42 +56,11 @@ namespace AspectedRouting
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LuaPrinter GenerateLua(Context context,
|
|
||||||
IEnumerable<(AspectMetadata aspect, AspectTestSuite tests)> aspects,
|
|
||||||
ProfileMetaData profile, List<ProfileTestSuite> profileTests)
|
|
||||||
{
|
|
||||||
var luaPrinter = new LuaPrinter(context);
|
|
||||||
|
|
||||||
var usedFunctions = profile.CalledFunctionsRecursive(context).Values.SelectMany(v => v).ToHashSet();
|
private static List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)> ParseProfiles(
|
||||||
|
|
||||||
foreach (var (aspect, tests) in aspects)
|
|
||||||
{
|
|
||||||
if (!usedFunctions.Contains(aspect.Name))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
luaPrinter.AddFunction(aspect);
|
|
||||||
if (tests != null)
|
|
||||||
{
|
|
||||||
luaPrinter.AddTestSuite(tests);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
luaPrinter.AddProfile(profile);
|
|
||||||
foreach (var testSuite in profileTests)
|
|
||||||
{
|
|
||||||
luaPrinter.AddTestSuite(testSuite);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return luaPrinter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<(ProfileMetaData profile, List<ProfileTestSuite> profileTests)> ParseProfiles(
|
|
||||||
IEnumerable<string> jsonFiles, IReadOnlyCollection<string> testFiles, Context context)
|
IEnumerable<string> jsonFiles, IReadOnlyCollection<string> testFiles, Context context)
|
||||||
{
|
{
|
||||||
var result = new List<(ProfileMetaData profile, List<ProfileTestSuite> profileTests)>();
|
var result = new List<(ProfileMetaData profile, List<BehaviourTestSuite> profileTests)>();
|
||||||
foreach (var jsonFile in jsonFiles)
|
foreach (var jsonFile in jsonFiles)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -104,13 +74,13 @@ namespace AspectedRouting
|
||||||
|
|
||||||
profile.SanityCheckProfile(context);
|
profile.SanityCheckProfile(context);
|
||||||
|
|
||||||
var profileTests = new List<ProfileTestSuite>();
|
var profileTests = new List<BehaviourTestSuite>();
|
||||||
foreach (var behaviourName in profile.Behaviours.Keys)
|
foreach (var behaviourName in profile.Behaviours.Keys)
|
||||||
{
|
{
|
||||||
var path = testFiles.FindTest($"{profile.Name}.{behaviourName}.behaviour_test.csv");
|
var path = testFiles.FindTest($"{profile.Name}.{behaviourName}.behaviour_test.csv");
|
||||||
if (path != null && File.Exists(path))
|
if (path != null && File.Exists(path))
|
||||||
{
|
{
|
||||||
var test = ProfileTestSuite.FromString(context, profile, behaviourName,
|
var test = BehaviourTestSuite.FromString(context, profile, behaviourName,
|
||||||
File.ReadAllText(path));
|
File.ReadAllText(path));
|
||||||
profileTests.Add(test);
|
profileTests.Add(test);
|
||||||
}
|
}
|
||||||
|
@ -201,6 +171,23 @@ namespace AspectedRouting
|
||||||
Console.WriteLine($"Error in the file {file}:\n {msg}");
|
Console.WriteLine($"Error in the file {file}:\n {msg}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void PrintUsedTags(ProfileMetaData profile, Context context)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\n\n\n---------- " + profile.Name + " --------------");
|
||||||
|
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 static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length < 2)
|
if (args.Length < 2)
|
||||||
|
@ -255,24 +242,26 @@ namespace AspectedRouting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine("\n\n\n---------- " + profile.Name + " --------------");
|
PrintUsedTags(profile, context);
|
||||||
foreach (var (key, values) in profile.AllExpressions(context).PossibleTags())
|
|
||||||
|
var aspectTests = aspects.Select(a => a.tests).ToList();
|
||||||
|
var luaProfile = new LuaPrinter1(profile, context,
|
||||||
|
aspectTests,
|
||||||
|
profileTests
|
||||||
|
).ToLua();
|
||||||
|
File.WriteAllText(outputDir + "/" + profile.Name + ".lua", luaProfile);
|
||||||
|
|
||||||
|
foreach (var (behaviourName, behaviourParameters) in profile.Behaviours)
|
||||||
{
|
{
|
||||||
var vs = "*";
|
var lua2behaviour = new LuaPrinter2(
|
||||||
if (values.Any())
|
profile,
|
||||||
{
|
behaviourName,
|
||||||
vs = string.Join(", ", values);
|
context,
|
||||||
}
|
aspectTests,
|
||||||
|
profileTests.Where(testsSuite => testsSuite.BehaviourName == behaviourName)
|
||||||
Console.WriteLine(key + ": " + vs);
|
).ToLua();
|
||||||
|
File.WriteAllText($"{outputDir}/itinero2/{profile.Name}.{behaviourName}.lua", lua2behaviour);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("\n\n\n------------------------");
|
|
||||||
|
|
||||||
var luaPrinter = GenerateLua(context, aspects, profile, profileTests);
|
|
||||||
|
|
||||||
|
|
||||||
File.WriteAllText(outputDir + "/" + profile.Name + ".lua", luaPrinter.ToLua());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Repl(context,
|
Repl(context,
|
||||||
|
|
|
@ -8,13 +8,13 @@ using AspectedRouting.Language.Typ;
|
||||||
|
|
||||||
namespace AspectedRouting.Tests
|
namespace AspectedRouting.Tests
|
||||||
{
|
{
|
||||||
public class ProfileTestSuite
|
public class BehaviourTestSuite
|
||||||
{
|
{
|
||||||
public readonly ProfileMetaData Profile;
|
public readonly ProfileMetaData Profile;
|
||||||
public readonly string BehaviourName;
|
public readonly string BehaviourName;
|
||||||
public readonly IEnumerable<(ProfileResult, Dictionary<string, string> tags)> Tests;
|
public readonly IEnumerable<(ProfileResult, Dictionary<string, string> tags)> Tests;
|
||||||
|
|
||||||
public static ProfileTestSuite FromString(Context c, ProfileMetaData function, string profileName,
|
public static BehaviourTestSuite FromString(Context c, ProfileMetaData function, string behaviourName,
|
||||||
string csvContents)
|
string csvContents)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -109,21 +109,21 @@ namespace AspectedRouting.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProfileTestSuite(function, profileName, tests);
|
return new BehaviourTestSuite(function, behaviourName, tests);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
throw new Exception("In the profile test file for " + profileName, e);
|
throw new Exception("In the profile test file for " + behaviourName, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileTestSuite(
|
public BehaviourTestSuite(
|
||||||
ProfileMetaData profile,
|
ProfileMetaData profile,
|
||||||
string profileName,
|
string behaviourName,
|
||||||
IEnumerable<(ProfileResult, Dictionary<string, string> tags)> tests)
|
IEnumerable<(ProfileResult, Dictionary<string, string> tags)> tests)
|
||||||
{
|
{
|
||||||
Profile = profile;
|
Profile = profile;
|
||||||
BehaviourName = profileName;
|
BehaviourName = behaviourName;
|
||||||
Tests = tests;
|
Tests = tests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,16 @@ namespace AspectedRouting
|
||||||
return s.Replace("\n", "\n ");
|
return s.Replace("\n", "\n ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<T> InList<T>(this T t)
|
||||||
|
{
|
||||||
|
return new List<T> {t};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Lined(this IEnumerable<string> lines)
|
||||||
|
{
|
||||||
|
return string.Join("\n", lines);
|
||||||
|
}
|
||||||
|
|
||||||
public static int Multiply(this IEnumerable<int> ints)
|
public static int Multiply(this IEnumerable<int> ints)
|
||||||
{
|
{
|
||||||
var factor = 1;
|
var factor = 1;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue