Skip to content

Latest commit

 

History

History
1058 lines (739 loc) · 22.3 KB

TypesAndFunctions.md

File metadata and controls

1058 lines (739 loc) · 22.3 KB

Types

  • double
  • pdouble
  • nat
  • int
  • string
  • tags
  • bool

Builtin functions

  • eq
  • notEq
  • not
  • inv
  • default
  • parse
  • to_string
  • concat
  • containedIn
  • min
  • and
  • max
  • or
  • sum
  • plus
  • add
  • multiply
  • atleast
  • firstMatchOf
  • mustMatch
  • memberOf
  • if_then_else
  • if
  • if_then_else_dotted
  • ifdotted
  • ifDotted
  • id
  • const
  • constRight
  • dot
  • listDot
  • eitherFunc
  • stringToTags
  • head

Function overview

eq

a b returns
$a $a bool
$a $a string

Returns 'yes' if both values are the same

Lua implementation:

function eq(a, b)
    if (a == b) then
        return "yes"
    else
        return "no"
    end
end

notEq

a b returns
$a $a bool
$a $a string
bool bool

OVerloaded function, either boolean not or returns 'yes' if the two passed in values are not the same;

Lua implementation:

function notEq(a, b)
    if (b == nil) then
        b = "yes"
    end
    
    if (a ~= b) then
        return "yes"
    else
        return "no"
    end
end

not

a b returns
$a $a bool
$a $a string
bool bool

OVerloaded function, either boolean not or returns 'yes' if the two passed in values are not the same;

Lua implementation:

function notEq(a, b)
    if (b == nil) then
        b = "yes"
    end
    
    if (a ~= b) then
        return "yes"
    else
        return "no"
    end
end

inv

d returns
pdouble pdouble
double double

Calculates 1/d

Lua implementation:

function inv(n)
    return 1/n
end

default

defaultValue f returns
$a $b -> $a $b

Calculates function f for the given argument. If the result is null, the default value is returned instead

Lua implementation:

function default(defaultValue, realValue)
    if(realValue ~= nil) then
        return realValue
    end
    return defaultValue
end

parse

s returns
string double
string pdouble

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

Lua implementation:

function parse(string)
    if (string == nil) then
        return 0
    end
    if (type(string) == "number") then
        return string
    end

    if (string == "yes" or string == "true") then
        return 1
    end

    if (string == "no" or string == "false") then
        return 0
    end

    if (type(string) == "boolean") then
        if (string) then
            return 1
        else
            return 0
        end
    end

    if(string:match("%d+:%d+")) then
        -- duration in minute
        local duration = 0
        for part in string:gmatch "%d+" do
            duration = duration * 60 + tonumber(part)
        end
        return duration
    end


    return tonumber(string)
end

to_string

obj returns
$a string

Converts a value into a human readable string

Lua implementation:

function to_string(o)
    return o;
end

concat

a b returns
string string string

Concatenates two strings

Lua implementation:

function concat(a, b)
    return a .. b
end

containedIn

list a returns
list ($a) $a bool

Given a list of values, checks if the argument is contained in the list.

Lua implementation:

function containedIn(list, a)
    for _, value in pairs(list) do
        if (value == a) then
            return true
        end
    end

    return false;
end

min

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) bool

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.

Lua implementation:

function min(list)
    local min
    for _, value in pairs(list) do
        if(value ~= nil) then
            if (min == nil) then
                min = value
            elseif (value < min) then
                min = value
            end
        end
    end

    return min;
end

and

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) bool

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.

Lua implementation:

function min(list)
    local min
    for _, value in pairs(list) do
        if(value ~= nil) then
            if (min == nil) then
                min = value
            elseif (value < min) then
                min = value
            end
        end
    end

    return min;
end

max

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) bool

Returns the biggest value in the list. For a list of booleans, this acts as 'or'

Lua implementation:

function max(list)
    local max
    for _, value in pairs(list) do
        if (value ~= nil) then
            if (max == nil) then
                max = value
            elseif (max < value) then
                max = value
            end
        end
    end

    return max;
end

or

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) bool

Returns the biggest value in the list. For a list of booleans, this acts as 'or'

Lua implementation:

function max(list)
    local max
    for _, value in pairs(list) do
        if (value ~= nil) then
            if (max == nil) then
                max = value
            elseif (max < value) then
                max = value
            end
        end
    end

    return max;
end

sum

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) int

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)

Lua implementation:

function sum(list)
    local sum = 0
    for _, value in pairs(list) do
        if(value ~= nil) then
            if(value == 'yes' or value == 'true') then
                value = 1
            end
            sum = sum + value
        end
    end
    return sum;
end

plus

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) int

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)

Lua implementation:

function sum(list)
    local sum = 0
    for _, value in pairs(list) do
        if(value ~= nil) then
            if(value == 'yes' or value == 'true') then
                value = 1
            end
            sum = sum + value
        end
    end
    return sum;
end

add

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) int

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)

Lua implementation:

function sum(list)
    local sum = 0
    for _, value in pairs(list) do
        if(value ~= nil) then
            if(value == 'yes' or value == 'true') then
                value = 1
            end
            sum = sum + value
        end
    end
    return sum;
end

multiply

list returns
list (nat) nat
list (int) int
list (pdouble) pdouble
list (double) double
list (bool) bool

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

Lua implementation:

function multiply(list)
    local factor = 1
    for _, value in pairs(list) do
        if (value ~= nil) then
            factor = factor * value
        end
    end
    return factor;
end

atleast

minimum f then else returns
double $b -> double $a $a $b

Returns 'yes' if the second argument is bigger then the first argument. (Works great in combination with $dot)

Lua implementation:

function atleast(minimumExpected, actual, thn, els)
    if (minimumExpected <= actual) then
        return thn;
    end
    return els
end

firstMatchOf

s returns
list (string) tags -> list ($a)

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.

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.

Lua implementation:

function first_match_of(tags, result, order_of_keys, table)
    for _, key in pairs(order_of_keys) do
        local v = tags[key]
        if (v ~= nil) then

            local mapping = table[key]
            if (type(mapping) == "table") then
                local resultValue = mapping[v]
                if (resultValue ~= nil) then
                    result.attributes_to_keep[key] = v
                    return resultValue
                end
            else
                result.attributes_to_keep[key] = v
                return mapping
            end
        end
    end
    return nil;
end

mustMatch

neededKeys (filled in by parser) f returns
list (string) tags -> list (string) tags

Checks that every specified key is present and gives a non-false value . 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' Note that this is a privileged builtin function, as the parser will automatically inject the keys used in the called function.

Lua implementation:

--[[
must_match checks that a collection of tags matches a specification.

The function is not trivial and contains a few subtilities.

Consider the following source:

{"$mustMatch":{ "a":"X", "b":{"not":"Y"}}}

This is desugared into

{"$mustMatch":{ "a":{"$eq":"X"}, "b":{"not":"Y"}}}

When applied on the tags {"a" : "X"}, this yields the table {"a":"yes", "b":"yes} (as `notEq` "Y" "nil") yields "yes"..
MustMatch checks that every key in this last table yields yes - even if it is not in the original tags!


]]
function must_match(tags, result, needed_keys, table)
    for _, key in ipairs(needed_keys) do
        local v = table[key] -- use the table here, as a tag that must _not_ match might be 'nil' in the tags
        if (v == nil) then
            return false
        end

        local mapping = table[key]
        if (type(mapping) == "table") then
            local resultValue = mapping[v]
            if (resultValue == nil or
                    resultValue == false or
                    resultValue == "no" or
                    resultValue == "false") then
                return false
            end
        elseif (type(mapping) == "string") then
            local bool = mapping
            if (bool == "no" or bool == "0") then
                return false
            end

            if (bool ~= "yes" and bool ~= "1") then
                error("MustMatch got a string value it can't handle: " .. bool)
            end
        elseif (type(mapping) == "boolean") then
            if(not mapping) then
                return false
            end
        else
            error("The mapping is not a table. This is not supported. We got " .. tostring(mapping) .. " (" .. type(mapping)..")")
        end
    end

    -- Now that we know for sure that every key matches, we add them all
    for _, key in ipairs(needed_keys) do
        local v = tags[key] -- this is the only place where we use the original tags
        if (v ~= nil) then
            result.attributes_to_keep[key] = v
        end
    end

    return true
end

memberOf

f tags returns
tags -> bool tags bool

This function returns true, if the way is member of a relation matching the specified function.

In order to use this for itinero 1.0, the membership must be the top level expression.

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.

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. 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, yieldingcountOf(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

Lua implementation:

function member_of(calledIn, parameters, tags, result)
    local k = "_relation:" .. calledIn
    -- This tag is conventiently setup by all the preprocessors, which take the parameters into account
    local doesMatch = tags[k]
    if (doesMatch == "yes") then
        result.attributes_to_keep[k] = "yes"
        return true
    end
    return false
end

if_then_else

condition then else returns
bool $a $a $a
bool $a $a
string $a $a $a
string $a $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. 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.

Lua implementation:

function if_then_else(condition, thn, els)
    if (condition ~= nil and (condition == "yes" or condition == true or condition == "true") then
        return thn
    else
        return els -- if no third parameter is given, 'els' will be nil
    end
end

if

condition then else returns
bool $a $a $a
bool $a $a
string $a $a $a
string $a $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. 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.

Lua implementation:

function if_then_else(condition, thn, els)
    if (condition ~= nil and (condition == "yes" or condition == true or condition == "true") then
        return thn
    else
        return els -- if no third parameter is given, 'els' will be nil
    end
end

if_then_else_dotted

condition then else returns
$b -> bool $b -> $a $b $a
$b -> string $b -> $a $b $a
$b -> bool $b -> $a $b -> $a $b
$b -> string $b -> $a $b -> $a $b

An if_then_else, but one which takes an extra argument and applies it on the condition, then and else. Consider fc, fthen and felse are all functions taking an a, then: (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 yesortrueor the booleantrueIf the elsebranch is not set,null` is returned in the condition is false.In case the condition returns 'null', then the 'else'-branch is taken.

Lua implementation:

function applyIfNeeded(f, arg)
    if(f == nil) then
        return nil
    end
    if(type(f) == "function") then
        return f(arg)
     else
        return f
    end
end

function if_then_else_dotted(conditionf, thnf, elsef, arg)
    local condition = applyIfNeeded(conditionf, arg); 
    if (condition) then
        return applyIfNeeded(thnf, arg)
    else
        return applyIfNeeded(elsef, arg) -- if no third parameter is given, 'els' will be nil
    end
end

ifdotted

condition then else returns
$b -> bool $b -> $a $b $a
$b -> string $b -> $a $b $a
$b -> bool $b -> $a $b -> $a $b
$b -> string $b -> $a $b -> $a $b

An if_then_else, but one which takes an extra argument and applies it on the condition, then and else. Consider fc, fthen and felse are all functions taking an a, then: (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 yesortrueor the booleantrueIf the elsebranch is not set,null` is returned in the condition is false.In case the condition returns 'null', then the 'else'-branch is taken.

Lua implementation:

function applyIfNeeded(f, arg)
    if(f == nil) then
        return nil
    end
    if(type(f) == "function") then
        return f(arg)
     else
        return f
    end
end

function if_then_else_dotted(conditionf, thnf, elsef, arg)
    local condition = applyIfNeeded(conditionf, arg); 
    if (condition) then
        return applyIfNeeded(thnf, arg)
    else
        return applyIfNeeded(elsef, arg) -- if no third parameter is given, 'els' will be nil
    end
end

ifDotted

condition then else returns
$b -> bool $b -> $a $b $a
$b -> string $b -> $a $b $a
$b -> bool $b -> $a $b -> $a $b
$b -> string $b -> $a $b -> $a $b

An if_then_else, but one which takes an extra argument and applies it on the condition, then and else. Consider fc, fthen and felse are all functions taking an a, then: (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 yesortrueor the booleantrueIf the elsebranch is not set,null` is returned in the condition is false.In case the condition returns 'null', then the 'else'-branch is taken.

Lua implementation:

function applyIfNeeded(f, arg)
    if(f == nil) then
        return nil
    end
    if(type(f) == "function") then
        return f(arg)
     else
        return f
    end
end

function if_then_else_dotted(conditionf, thnf, elsef, arg)
    local condition = applyIfNeeded(conditionf, arg); 
    if (condition) then
        return applyIfNeeded(thnf, arg)
    else
        return applyIfNeeded(elsef, arg) -- if no third parameter is given, 'els' will be nil
    end
end

id

a returns
$a $a

Returns the argument unchanged - the identity function. Seems useless at first sight, but useful in parsing

Lua implementation:

function id(v)
    return v
end

const

a b returns
$a $b $a

Small utility function, which takes two arguments a and b and returns a. Used extensively to insert freedom

Lua implementation:

function const(a, b)
    return a
end

constRight

a b returns
$a $b $b

Small utility function, which takes two arguments a and b and returns b. Used extensively to insert freedom

Lua implementation:

dot

f g a returns
$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, which allows the argument to be lifted out of the expression

Lua implementation:

listDot

list a returns
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 function.It conveniently lifts the argument out of the list.

Lua implementation:

-- TODO 
-- listDot

eitherFunc

f g a returns
$a -> $b $c -> $d $a $b
$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 the types.

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.

Disclaimer: you should never ever need this in your profiles

Lua implementation:

stringToTags

f tags returns
string -> string -> $a tags list ($a)

stringToTags converts a function string -> string -> a into a function tags -> [a]

Lua implementation:

print("ERROR: stringToTag is needed. This should not happen")

head

ls returns
list ($a) $a

Select the first non-null value of a list; returns 'null' on empty list or on null

Lua implementation:

function head(ls)
   if(ls == nil) then
       return nil
   end
   for _, v in pairs(ls) do
       if(v ~= nil) then
           return v
       end
   end
   return nil
end