Clarify behaviour of null on aggregate functions, small fixes

This commit is contained in:
Pieter Vander Vennet 2020-09-07 18:47:24 +02:00
parent 4ebddfd807
commit b1e4aa29a3
7 changed files with 42 additions and 15 deletions

View file

@ -10,7 +10,7 @@ namespace AspectedRouting.Language.Functions
private static Var b = new Var("b");
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` or the boolean `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`)" +
"If the `else` branch is not set, `null` is returned in the condition is false.";
public override List<string> ArgNames { get; } = new List<string> {"condition", "then", "else"};

View file

@ -16,7 +16,8 @@ namespace AspectedRouting.Language.Functions
"`(ifDotted fc fthen felse) a` === `(if (fc a) (fthen a) (felse a)" +
"Selects either one of the branches, depending on the condition." +
" The 'then' branch is returned if the condition returns the string `yes` or `true` or the boolean `true`" +
"If the `else` branch is not set, `null` is returned in the condition is false.";
"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.";
public override List<string> ArgNames { get; } = new List<string> {"condition", "then", "else"};
public IfDotted() : base("if_then_else_dotted", true,
@ -73,7 +74,7 @@ namespace AspectedRouting.Language.Functions
}
else
{
return elsefunc.Apply(argument).Evaluate(c);
return elsefunc?.Apply(argument)?.Evaluate(c);
}
}

View file

@ -8,7 +8,7 @@ namespace AspectedRouting.Language.Functions
public class Min : Function
{
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`";
"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"};

View file

@ -8,7 +8,7 @@ namespace AspectedRouting.Language.Functions
public class Multiply : Function
{
public override string Description { get; } =
"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', 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"};

View file

@ -1,13 +1,16 @@
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 Parse : Function
{
public override string Description { get; } = "Parses a string into a numerical value";
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 Parse() : base("parse", true,
@ -38,13 +41,33 @@ namespace AspectedRouting.Language.Functions
{
var arg = (string) arguments[0].Evaluate(c);
var expectedType = ((Curry) Types.First()).ResultType;
switch (expectedType)
var duration = Regex.Match(arg, @"^(\d+):(\d+)$");
if (duration.Success)
{
case PDoubleType _:
case DoubleType _:
return double.Parse(arg);
default: return int.Parse(arg);
// This is a duration of the form 'hh:mm' -> we return the total minute count
var hours = int.Parse(duration.Groups[1].Value);
var minutes = int.Parse(duration.Groups[2].Value);
return hours * 60 + minutes;
}
try
{
switch (expectedType)
{
case PDoubleType _:
case DoubleType _:
return double.Parse(arg);
default: return int.Parse(arg);
}
}
catch (Exception e)
{
Console.Error.WriteLine("Could not parse " + arg + " as " + expectedType);
return null;
}
}
}
}

View file

@ -7,7 +7,7 @@ namespace AspectedRouting.Language.Functions
{
public class Sum : Function
{
public override string Description { get; } = "Sums all the numbers in the given list. If the list contains bool, `yes` or `true` will be considered to equal `1`";
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 Sum() : base("sum", true,
@ -26,7 +26,7 @@ namespace AspectedRouting.Language.Functions
}
private Sum(IEnumerable<Type> specializedTypes) : base("max", specializedTypes)
private Sum(IEnumerable<Type> specializedTypes) : base("sum", specializedTypes)
{
}
@ -44,7 +44,9 @@ namespace AspectedRouting.Language.Functions
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;
switch (expectedType)

View file

@ -14,7 +14,8 @@ namespace AspectedRouting.Language.Typ
ArgType = argType;
ResultType = resultType;
}
private static string ToString(Type argType, Type resultType)
{
var arg = argType.ToString();