summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-stdlib/lib/std/_base.lua
blob: 0c623d4b5f3025aa8fcb4b55467b84b9319c3dd8 (plain)
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,
   },
}