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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
--[[
General Lua Libraries for Lua 5.1, 5.2 & 5.3
Copyright (C) 2002-2018 stdlib authors
]]
--[[--
Prevent dependency loops with key function implementations.
A few key functions are used in several stdlib modules; we implement those
functions in this internal module to prevent dependency loops in the first
instance, and to minimise coupling between modules where the use of one of
these functions might otherwise load a whole selection of other supporting
modules unnecessarily.
Although the implementations are here for logistical reasons, we re-export
them from their respective logical modules so that the api is not affected
as far as client code is concerned. The functions in this file do not make
use of `argcheck` or similar, because we know that they are only called by
other stdlib functions which have already performed the necessary checking
and neither do we want to slow everything down by recheckng those argument
types here.
This implies that when re-exporting from another module when argument type
checking is in force, we must export a wrapper function that can check the
user's arguments fully at the API boundary.
]]
local _ENV = require 'std.normalize' {
concat = 'table.concat',
dirsep = 'package.dirsep',
find = 'string.find',
gsub = 'string.gsub',
insert = 'table.insert',
min = 'math.min',
shallow_copy = 'table.merge',
sort = 'table.sort',
sub = 'string.sub',
table_maxn = table.maxn,
wrap = 'coroutine.wrap',
yield = 'coroutine.yield',
}
--[[ ============================ ]]--
--[[ Enhanced Core Lua functions. ]]--
--[[ ============================ ]]--
-- These come as early as possible, because we want the rest of the code
-- in this file to use these versions over the core Lua implementation
-- (which have slightly varying semantics between releases).
local maxn = table_maxn or function(t)
local n = 0
for k in pairs(t) do
if type(k) == 'number' and k > n then
n = k
end
end
return n
end
--[[ ============================ ]]--
--[[ Shared Stdlib API functions. ]]--
--[[ ============================ ]]--
-- No need to recurse because functables are second class citizens in
-- Lua:
-- func = function() print 'called' end
-- func() --> 'called'
-- functable=setmetatable({}, {__call=func})
-- functable() --> 'called'
-- nested=setmetatable({}, {__call=functable})
-- nested()
-- --> stdin:1: attempt to call a table value(global 'd')
-- --> stack traceback:
-- --> stdin:1: in main chunk
-- --> [C]: in ?
local function callable(x)
if type(x) == 'function' then
return x
end
return (getmetatable(x) or {}).__call
end
local function catfile(...)
return concat({...}, dirsep)
end
local function compare(l, m)
local lenl, lenm = len(l), len(m)
for i = 1, min(lenl, lenm) do
local li, mi = tonumber(l[i]), tonumber(m[i])
if li == nil or mi == nil then
li, mi = l[i], m[i]
end
if li < mi then
return -1
elseif li > mi then
return 1
end
end
if lenl < lenm then
return -1
elseif lenl > lenm then
return 1
end
return 0
end
local function escape_pattern(s)
return (gsub(s, '[%^%$%(%)%%%.%[%]%*%+%-%?]', '%%%0'))
end
local function invert(t)
local i = {}
for k, v in pairs(t) do
i[v] = k
end
return i
end
local function leaves(it, tr)
local function visit(n)
if type(n) == 'table' then
for _, v in it(n) do
visit(v)
end
else
yield(n)
end
end
return wrap(visit), tr
end
local function split(s, sep)
local r, patt = {}
if sep == '' then
patt = '(.)'
insert(r, '')
else
patt = '(.-)' ..(sep or '%s+')
end
local b, slen = 0, len(s)
while b <= slen do
local e, n, m = find(s, patt, b + 1)
insert(r, m or sub(s, b + 1, slen))
b = n or slen + 1
end
return r
end
--[[ ============= ]]--
--[[ Internal API. ]]--
--[[ ============= ]]--
-- For efficient use within stdlib, these functions have no type-checking.
-- In debug mode, type-checking wrappers are re-exported from the public-
-- facing modules as necessary.
--
-- Also, to provide some sanity, we mirror the subtable layout of stdlib
-- public API here too, which means everything looks relatively normal
-- when importing the functions into stdlib implementation modules.
return {
io = {
catfile = catfile,
},
list = {
compare = compare,
},
object = {
Module = Module,
mapfields = mapfields,
},
string = {
escape_pattern = escape_pattern,
split = split,
},
table = {
invert = invert,
maxn = maxn,
},
tree = {
leaves = leaves,
},
}
|