summaryrefslogtreecommitdiffstats
path: root/nselib/listop.lua
diff options
context:
space:
mode:
Diffstat (limited to 'nselib/listop.lua')
-rw-r--r--nselib/listop.lua184
1 files changed, 184 insertions, 0 deletions
diff --git a/nselib/listop.lua b/nselib/listop.lua
new file mode 100644
index 0000000..7dd8386
--- /dev/null
+++ b/nselib/listop.lua
@@ -0,0 +1,184 @@
+---
+-- Functional-style list operations.
+--
+-- People used to programming in functional languages, such as Lisp
+-- or Haskell, appreciate their handling of lists very much. The
+-- <code>listop</code> module tries to bring much of the functionality from
+-- functional languages to Lua using Lua's central data structure, the table, as
+-- a base for its list operations. Highlights include a <code>map</code>
+-- function applying a given function to each element of a list.
+-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html
+
+local stdnse = require "stdnse"
+local table = require "table"
+_ENV = stdnse.module("listop", stdnse.seeall)
+
+--[[
+--
+Functional programming style 'list' operations
+
+ bool is_empty(list)
+ bool is_list(value)
+
+ value apply(function, list)
+ list map(function, list)
+ list filter(function, list)
+ list flatten(list)
+ list append(list1, list2)
+ list cons(value1, value2)
+ list reverse(list)
+
+ value car(list)
+ value ncar(list, x)
+ list cdr(list)
+ list ncdr(list, x)
+
+ where 'list' is an indexed table
+ where 'value' is an lua datatype
+--]]
+
+--- Returns true if the given list is empty.
+-- @param l A list.
+-- @return True or false.
+function is_empty(l)
+ return #l == 0 and true or false;
+end
+
+--- Returns true if the given value is a list (or rather a table).
+-- @param l Any value.
+-- @return True or false.
+function is_list(l)
+ return type(l) == 'table' and true or false;
+end
+
+--- Calls <code>f</code> for each element in the list. The returned list
+--contains the results of each function call.
+-- @usage
+-- listop.map(tostring,{1,2,true}) --> {"1","2","true"}
+-- @param f The function to call.
+-- @param l A list.
+-- @return List of function results.
+function map(f, l)
+ local results = {}
+ for _, v in ipairs(l) do
+ results[#results+1] = f(v);
+ end
+ return results;
+end
+
+--- Calls the function with all the elements in the list as the parameters.
+-- @usage
+-- listop.apply(math.max,{1,5,6,7,50000}) --> 50000
+-- @param f The function to call.
+-- @param l A list.
+-- @return Results from <code>f</code>.
+function apply(f, l)
+ return f(table.unpack(l))
+end
+
+--- Returns a list containing only those elements for which a predicate
+-- function returns true.
+--
+-- The predicate has to be a function taking one argument and returning
+-- a Boolean. If it returns true, the argument is appended to the return value
+-- of filter.
+-- @usage
+-- listop.filter(isnumber,{1,2,3,"foo",4,"bar"}) --> {1,2,3,4}
+-- @param f The function.
+-- @param l The list.
+-- @return Filtered list.
+function filter(f, l)
+ local results = {}
+ for i, v in ipairs(l) do
+ if(f(v)) then
+ results[#results+1] = v;
+ end
+ end
+ return results
+end
+
+--- Fetch the first element of a list.
+-- @param l The list.
+-- @return The first element.
+function car(l)
+ return l[1]
+end
+
+--- Fetch all elements following the first in a new list.
+-- @param l The list.
+-- @return Elements after the first.
+function cdr(l)
+ return {table.unpack(l, 2)}
+end
+
+--- Fetch element at index <code>x</code> from <code>l</code>.
+-- @param l The list.
+-- @param x Element index.
+-- @return Element at index <code>x</code> or at index <code>1</code> if
+-- <code>x</code> is not given.
+function ncar(l, x)
+ return l[x or 1];
+end
+
+--- Fetch all elements following the element at index <code>x</code>.
+-- @param l The list.
+-- @param x Element index.
+-- @return Elements after index <code>x</code> or after index <code>1</code> if
+-- <code>x</code> is not given.
+function ncdr(l, x)
+ return {table.unpack(l, x or 2)};
+end
+
+--- Prepend a value or list to another value or list.
+-- @param v1 value or list.
+-- @param v2 value or list.
+-- @return New list.
+function cons(v1, v2)
+ return{ is_list(v1) and {table.unpack(v1)} or v1, is_list(v2) and {table.unpack(v2)} or v2}
+end
+
+--- Concatenate two lists and return the result.
+-- @param l1 List.
+-- @param l2 List.
+-- @return List.
+function append(l1, l2)
+ local results = {table.unpack(l1)}
+
+ for _, v in ipairs(l2) do
+ results[#results+1] = v;
+ end
+ return results
+end
+
+--- Return a list in reverse order.
+-- @param l List.
+-- @return Reversed list.
+function reverse(l)
+ local results = {}
+ for i=#l, 1, -1 do
+ results[#results+1] = l[i];
+ end
+ return results
+end
+
+--- Return a flattened version of a list. The flattened list contains
+-- only non-list values.
+-- @usage
+-- listop.flatten({1,2,3,"foo",{4,5,{"bar"}}}) --> {1,2,3,"foo",4,5,"bar"}
+-- @param l The list to flatten.
+-- @return Flattened list.
+function flatten(l)
+ local function flat(r, t)
+ for i, v in ipairs(t) do
+ if(type(v) == 'table') then
+ flat(r, v)
+ else
+ table.insert(r, v)
+ end
+ end
+ return r
+ end
+ return flat({}, l)
+end
+
+return _ENV;