--- Lua operators available as functions.
--
-- (similar to the Python module of the same name)
--
-- There is a module field `optable` which maps the operator strings
-- onto these functions, e.g. `operator.optable['()']==operator.call`
--
-- Operator strings like '>' and '{}' can be passed to most Penlight functions
-- expecting a function argument.
--
-- Dependencies: `pl.utils`
-- @module pl.operator

local strfind = string.find
local utils = require 'pl.utils'

local operator = {}

--- apply function to some arguments ()
-- @param fn a function or callable object
-- @param ... arguments
function operator.call(fn,...)
    return fn(...)
end

--- get the indexed value from a table []
-- @param t a table or any indexable object
-- @param k the key
function  operator.index(t,k)
    return t[k]
end

--- returns true if arguments are equal ==
-- @param a value
-- @param b value
function  operator.eq(a,b)
    return a==b
end

--- returns true if arguments are not equal ~=
 -- @param a value
-- @param b value
function  operator.neq(a,b)
    return a~=b
end

--- returns true if a is less than b <
-- @param a value
-- @param b value
function  operator.lt(a,b)
    return a < b
end

--- returns true if a is less or equal to b <=
-- @param a value
-- @param b value
function  operator.le(a,b)
    return a <= b
end

--- returns true if a is greater than b >
-- @param a value
-- @param b value
function  operator.gt(a,b)
    return a > b
end

--- returns true if a is greater or equal to b >=
-- @param a value
-- @param b value
function  operator.ge(a,b)
    return a >= b
end

--- returns length of string or table #
-- @param a a string or a table
function  operator.len(a)
    return #a
end

--- add two values +
-- @param a value
-- @param b value
function  operator.add(a,b)
    return a+b
end

--- subtract b from a -
-- @param a value
-- @param b value
function  operator.sub(a,b)
    return a-b
end

--- multiply two values *
-- @param a value
-- @param b value
function  operator.mul(a,b)
    return a*b
end

--- divide first value by second /
-- @param a value
-- @param b value
function  operator.div(a,b)
    return a/b
end

--- raise first to the power of second ^
-- @param a value
-- @param b value
function  operator.pow(a,b)
    return a^b
end

--- modulo; remainder of a divided by b %
-- @param a value
-- @param b value
function  operator.mod(a,b)
    return a%b
end

--- concatenate two values (either strings or __concat defined) ..
-- @param a value
-- @param b value
function  operator.concat(a,b)
    return a..b
end

--- return the negative of a value -
-- @param a value
-- @param b value
function  operator.unm(a)
    return -a
end

--- false if value evaluates as true not
-- @param a value
function  operator.lnot(a)
    return not a
end

--- true if both values evaluate as true and
-- @param a value
-- @param b value
function  operator.land(a,b)
    return a and b
end

--- true if either value evaluate as true or
-- @param a value
-- @param b value
function  operator.lor(a,b)
    return a or b
end

--- make a table from the arguments {}
-- @param ... non-nil arguments
-- @return a table
function  operator.table (...)
    return {...}
end

--- match two strings ~
-- uses @{string.find}
function  operator.match (a,b)
    return strfind(a,b)~=nil
end

--- the null operation.
-- @param ... arguments
-- @return the arguments
function  operator.nop (...)
    return ...
end

 operator.optable = {
    ['+']=operator.add,
    ['-']=operator.sub,
    ['*']=operator.mul,
    ['/']=operator.div,
    ['%']=operator.mod,
    ['^']=operator.pow,
    ['..']=operator.concat,
    ['()']=operator.call,
    ['[]']=operator.index,
    ['<']=operator.lt,
    ['<=']=operator.le,
    ['>']=operator.gt,
    ['>=']=operator.ge,
    ['==']=operator.eq,
    ['~=']=operator.neq,
    ['#']=operator.len,
    ['and']=operator.land,
    ['or']=operator.lor,
    ['{}']=operator.table,
    ['~']=operator.match,
    ['']=operator.nop,
}

return operator
