aboutsummaryrefslogtreecommitdiffstats
path: root/testing/lua-microlight/ml.lua
diff options
context:
space:
mode:
Diffstat (limited to 'testing/lua-microlight/ml.lua')
-rw-r--r--testing/lua-microlight/ml.lua543
1 files changed, 0 insertions, 543 deletions
diff --git a/testing/lua-microlight/ml.lua b/testing/lua-microlight/ml.lua
deleted file mode 100644
index 2bbb01662d..0000000000
--- a/testing/lua-microlight/ml.lua
+++ /dev/null
@@ -1,543 +0,0 @@
------------------
--- Microlight - a very compact Lua utilities module
---
--- Steve Donovan, 2012; License MIT
--- @module ml
-
-local ml = {}
-
---- String utilties.
--- @section string
-
---- split a string into a list of strings separated by a delimiter.
--- @param s The input string
--- @param re A Lua string pattern; defaults to '%s+'
--- @param n optional maximum number of splits
--- @return a list
-function ml.split(s,re,n)
- local find,sub,append = string.find, string.sub, table.insert
- local i1,ls = 1,{}
- if not re then re = '%s+' end
- if re == '' then return {s} end
- while true do
- local i2,i3 = find(s,re,i1)
- if not i2 then
- local last = sub(s,i1)
- if last ~= '' then append(ls,last) end
- if #ls == 1 and ls[1] == '' then
- return {}
- else
- return ls
- end
- end
- append(ls,sub(s,i1,i2-1))
- if n and #ls == n then
- ls[#ls] = sub(s,i1)
- return ls
- end
- i1 = i3+1
- end
-end
-
---- escape any 'magic' characters in a string
--- @param s The input string
--- @return an escaped string
-function ml.escape(s)
- return (s:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1'))
-end
-
---- expand a string containing any ${var} or $var.
--- @param s the string
--- @param subst either a table or a function (as in `string.gsub`)
--- @return expanded string
-function ml.expand (s,subst)
- local res = s:gsub('%${([%w_]+)}',subst)
- return (res:gsub('%$([%w_]+)',subst))
-end
-
---- return the contents of a file as a string
--- @param filename The file path
--- @param is_bin open in binary mode, default false
--- @return file contents
-function ml.readfile(filename,is_bin)
- local mode = is_bin and 'b' or ''
- local f,err = io.open(filename,'r'..mode)
- if not f then return nil,err end
- local res,err = f:read('*a')
- f:close()
- if not res then return nil,err end
- return res
-end
-
---- File and Path functions
--- @section file
-
---~ exists(filename)
---- Does a file exist?
--- @param filename a file path
--- @return the file path, otherwise nil
--- @usage exists 'readme' or exists 'readme.txt' or exists 'readme.md'
-function ml.exists (filename)
- local f = io.open(filename)
- if not f then
- return nil
- else
- f:close()
- return filename
- end
-end
-
-local sep, other_sep = package.config:sub(1,1),'/'
-
-
---- split a file path.
--- if there's no directory part, the first value will be the empty string
--- @param P A file path
--- @return the directory part
--- @return the file part
-function ml.splitpath(P)
- local i = #P
- local ch = P:sub(i,i)
- while i > 0 and ch ~= sep and ch ~= other_sep do
- i = i - 1
- ch = P:sub(i,i)
- end
- if i == 0 then
- return '',P
- else
- return P:sub(1,i-1), P:sub(i+1)
- end
-end
-
---- given a path, return the root part and the extension part.
--- if there's no extension part, the second value will be empty
--- @param P A file path
--- @return the name part
--- @return the extension
-function ml.splitext(P)
- local i = #P
- local ch = P:sub(i,i)
- while i > 0 and ch ~= '.' do
- if ch == sep or ch == other_sep then
- return P,''
- end
- i = i - 1
- ch = P:sub(i,i)
- end
- if i == 0 then
- return P,''
- else
- return P:sub(1,i-1),P:sub(i)
- end
-end
-
---- Extended table functions.
--- 'list' here is shorthand for 'list-like table'; these functions
--- only operate over the numeric `1..#t` range of a table and are
--- particularly efficient for this purpose.
--- @section table
-
-local function quote (v)
- if type(v) == 'string' then
- return ('%q'):format(v)
- else
- return tostring(v)
- end
-end
-
-local tbuff
-function tbuff (t,buff,k)
- buff[k] = "{"
- k = k + 1
- for key,value in pairs(t) do
- key = quote(key)
- if type(value) ~= 'table' then
- value = quote(value)
- buff[k] = ('[%s]=%s'):format(key,value)
- k = k + 1
- if buff.limit and k > buff.limit then
- buff[k] = "..."
- error("buffer overrun")
- end
- else
- if not buff.tables then buff.tables = {} end
- if not buff.tables[value] then
- k = tbuff(value,buff,k)
- buff.tables[value] = true
- else
- buff[k] = "<cycle>"
- k = k + 1
- end
- end
- buff[k] = ","
- k = k + 1
- end
- if buff[k-1] == "," then k = k - 1 end
- buff[k] = "}"
- k = k + 1
- return k
-end
-
---- return a string representation of a Lua table.
--- Cycles are detected, and a limit on number of items can be imposed.
--- @param t the table
--- @param limit the limit on items, default 1000
--- @return a string
-function ml.tstring (t,limit)
- local buff = {limit = limit or 1000}
- pcall(tbuff,t,buff,1)
- return table.concat(buff)
-end
-
---- dump a Lua table to a file object.
--- @param t the table
--- @param f the file object (anything supporting f.write)
-function ml.tdump(t,...)
- local f = select('#',...) > 0 and select(1,...) or io.stdout
- f:write(ml.tstring(t),'\n')
-end
-
---- map a function over a list.
--- The output must always be the same length as the input, so
--- any `nil` values are mapped to `false`.
--- @param f a function of one or more arguments
--- @param t the table
--- @param ... any extra arguments to the function
--- @return a list with elements `f(t[i])`
-function ml.imap(f,t,...)
- f = ml.function_arg(f)
- local res = {}
- for i = 1,#t do
- local val = f(t[i],...)
- if val == nil then val = false end
- res[i] = val
- end
- return res
-end
-
---- filter a list using a predicate.
--- @param t a table
--- @param pred the predicate function
--- @param ... any extra arguments to the predicate
--- @return a list such that `pred(t[i])` is true
-function ml.ifilter(t,pred,...)
- local res,k = {},1
- pred = ml.function_arg(pred)
- for i = 1,#t do
- if pred(t[i],...) then
- res[k] = t[i]
- k = k + 1
- end
- end
- return res
-end
-
---- find an item in a list using a predicate.
--- @param t the list
--- @param pred a function of at least one argument
--- @param ... any extra arguments
--- @return the item value
-function ml.ifind(t,pred,...)
- pred = ml.function_arg(pred)
- for i = 1,#t do
- if pred(t[i],...) then
- return t[i]
- end
- end
-end
-
---- return the index of an item in a list.
--- @param t the list
--- @param value item value
--- @return index, otherwise `nil`
-function ml.index (t,value)
- for i = 1,#t do
- if t[i] == value then return i end
- end
-end
-
---- return a slice of a list.
--- Like string.sub, the end index may be negative.
--- @param t the list
--- @param i1 the start index
--- @param i2 the end index, default #t
-function ml.sub(t,i1,i2)
- if not i2 or i2 > #t then
- i2 = #t
- elseif i2 < 0 then
- i2 = #t + i2 + 1
- end
- local res,k = {},1
- for i = i1,i2 do
- res[k] = t[i]
- k = k + 1
- end
- return res
-end
-
---- map a function over a Lua table.
--- @param f a function of one or more arguments
--- @param t the table
--- @param ... any optional arguments to the function
-function ml.tmap(f,t,...)
- f = ml.function_arg(f)
- local res = {}
- for k,v in pairs(t) do
- res[k] = f(v,...)
- end
- return res
-end
-
---- filter a table using a predicate.
--- @param t a table
--- @param pred the predicate function
--- @param ... any extra arguments to the predicate
--- @usage tfilter({a=1,b='boo'},tonumber) == {a=1}
-function ml.tfilter (t,pred,...)
- local res = {}
- pred = ml.function_arg(pred)
- for k,v in pairs(t) do
- if pred(v,...) then
- res[k] = v
- end
- end
- return res
-end
-
---- add the key/value pairs of `other` to `t`.
--- For sets, this is their union. For the same keys,
--- the values from the first table will be overwritten
--- @param t table to be updated
--- @param other table
--- @return the updated table
-function ml.update(t,other)
- for k,v in pairs(other) do
- t[k] = v
- end
- return t
-end
-
---- extend a list using values from another.
--- @param t the list to be extended
--- @param other a list
--- @return the extended list
-function ml.extend(t,other)
- local n = #t
- for i = 1,#other do
- t[n+i] = other[i]
- end
- return t
-end
-
---- make a set from a list.
--- @param t a list of values
--- @return a table where the keys are the values
--- @usage set{'one','two'} == {one=true,two=true}
-function ml.set(t)
- local res = {}
- for i = 1,#t do
- res[t[i]] = true
- end
- return res
-end
-
---- extract the keys of a table as a list.
--- This is the opposite operation to tset
--- @param t a table
--- @param a list of keys
-function ml.keys(t)
- local res,k = {},1
- for key in pairs(t) do
- res[k] = key
- k = k + 1
- end
- return res
-end
-
---- is `other` a subset of `t`?
--- @param t a set
--- @param other a possible subset
--- @return true or false
-function ml.subset(t,other)
- for k,v in pairs(other) do
- if t[k] ~= v then return false end
- end
- return true
-end
-
---- are these two tables equal?
--- This is shallow equality.
--- @param t a table
--- @param other a table
--- @return true or false
-function ml.tequal(t,other)
- return ml.subset(t,other) and ml.subset(other,t)
-end
-
---- the intersection of two tables.
--- Works as expected for sets, otherwise note that the first
--- table's values are preseved
--- @param t a table
--- @param other a table
--- @return the intersection of the tables
-function ml.intersect(t,other)
- local res = {}
- for k,v in pairs(t) do
- if other[k] then
- res[k] = v
- end
- end
- return res
-end
-
---- collect the values of an iterator into a list.
--- @param iter a single or double-valued iterator
--- @param count an optional number of values to collect
--- @return a list of values.
--- @usage collect(ipairs{10,20}) == {{1,10},{2,20}}
-function ml.collect (iter, count)
- local res,k = {},1
- local v1,v2 = iter()
- local dbl = v2 ~= nil
- while v1 do
- if dbl then v1 = {v1,v2} end
- res[k] = v1
- k = k + 1
- if count and k > count then break end
- v1,v2 = iter()
- end
- return res
-end
-
---- Functional helpers.
--- @section function
-
---- create a function which will throw an error on failure.
--- @param f a function that returns nil,err if it fails
--- @return an equivalent function that raises an error
-function ml.throw(f)
- f = ml.function_arg(f)
- return function(...)
- local res,err = f(...)
- if err then error(err) end
- return res
- end
-end
-
---- create a function which will never throw an error.
--- This is the opposite situation to throw; if the
--- original function throws an error e, then this
--- function will return nil,e.
--- @param f a function which can throw an error
--- @return a function which returns nil,error when it fails
-function ml.safe(f)
- f = ml.function_arg(f)
- return function(...)
- local ok,r1,r2,r3 = pcall(f,...)
- if ok then return r1,r2,r3
- else
- return nil,r1
- end
- end
-end
---memoize(f)
-
---- bind the value `v` to the first argument of function `f`.
--- @param f a function of at least one argument
--- @param v a value
--- @return a function of one less argument
--- @usage (bind1(string.match,'hello')('^hell') == 'hell'
-function ml.bind1(f,v)
- f = ml.function_arg(f)
- return function(...)
- return f(v,...)
- end
-end
-
---- compose two functions.
--- For instance, `printf` can be defined as `compose(io.write,string.format)`
--- @param f1 a function
--- @param f2 a function
--- @return f1(f2(...))
-function ml.compose(f1,f2)
- f1 = ml.function_arg(f1)
- f2 = ml.function_arg(f2)
- return function(...)
- return f1(f2(...))
- end
-end
-
---- is the object either a function or a callable object?.
--- @param obj Object to check.
--- @return true if callable
-function ml.callable (obj)
- return type(obj) == 'function' or getmetatable(obj) and getmetatable(obj).__call
-end
-
-function ml.function_arg(f)
- assert(ml.callable(f),"expecting a function or callable object")
- return f
-end
-
---- Classes.
--- @section class
-
---- create a class with an optional base class.
--- The resulting table has a new() function for invoking
--- the constructor, which must be named `_init`. If the base
--- class has a constructor, you can call it as the `super()` method.
--- The `__tostring` metamethod is also inherited, but others need
--- to be brought in explicitly.
--- @param base optional base class
--- @return the metatable representing the class
-function ml.class(base)
- local klass, base_ctor = {}
- klass.__index = klass
- if base then
- setmetatable(klass,base)
- klass._base = base
- base_ctor = rawget(base,'_init')
- klass.__tostring = base.__tostring
- end
- function klass.new(...)
- local self = setmetatable({},klass)
- if rawget(klass,'_init') then
- klass.super = base_ctor -- make super available for ctor
- klass._init(self,...)
- elseif base_ctor then -- call base ctor automatically
- base_ctor(self,...)
- end
- return self
- end
- return klass
-end
-
---- is an object derived from a class?
--- @param self the object
--- @param klass a class created with `class`
--- @return true or false
-function ml.is_a(self,klass)
- local m = getmetatable(self)
- if not m then return false end --*can't be an object!
- while m do
- if m == klass then return true end
- m = rawget(m,'_base')
- end
- return false
-end
-
-local _type = type
-
---- extended type of an object.
--- The type of a table is its metatable, otherwise works like standard type()
--- @param obj a value
--- @return the type, either a string or the metatable
-function ml.type (obj)
- if _type(obj) == 'table' then
- return getmetatable(obj) or 'table'
- else
- return _type(obj)
- end
-end
-
-return ml