1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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;
|