├── README.md ├── __meta.lua ├── xsys-1.0.2-1.rockspec ├── LICENSE.TXT ├── _dep └── templet │ └── init.lua └── init.lua /README.md: -------------------------------------------------------------------------------- 1 | Xsys 2 | ==== 3 | 4 | This is a MIT licensed library that provides a small number of general purpose routines and extends the global `table` and `string` libraries. 5 | 6 | Info: http://scilua.org/xsys.html 7 | -------------------------------------------------------------------------------- /__meta.lua: -------------------------------------------------------------------------------- 1 | return { 2 | name = "xsys", 3 | version = "1.0.2", 4 | require = { 5 | luajit = "2.0" 6 | }, 7 | license = "MIT ", 8 | homepage = "http://scilua.org/xsys.html", 9 | description = "extended Lua system", 10 | } -------------------------------------------------------------------------------- /xsys-1.0.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "xsys" 2 | version = "1.0.2-1" 3 | 4 | source = { 5 | url = "https://github.com/stepelu/lua-xsys/archive/v1.0.2.tar.gz", 6 | dir = "lua-xsys-1.0.2" 7 | } 8 | description = { 9 | summary = "LuaJIT General Purpose Routines", 10 | detailed = "This is a MIT licensed library that provides a small number of general purpose routines and extends the global `table` and `string` libraries.", 11 | homepage = "http://scilua.org/xsys.html", 12 | license = "MIT" 13 | } 14 | dependencies = { 15 | "lua >= 5.1, < 5.4" 16 | } 17 | build = { 18 | type = "builtin", 19 | modules = { 20 | ["xsys._dep.templet.init"] = "_dep/templet/init.lua", 21 | ["xsys._xsys"] = "_xsys.lua", 22 | ["xsys.init"] = "init.lua" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | License: MIT (http://www.opensource.org/licenses/mit-license.php), full text 2 | follows: 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. -------------------------------------------------------------------------------- /_dep/templet/init.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Templet for Lua. 3 | -- Copyright © 2012 Peter Colberg. 4 | -- For conditions of distribution and use, see copyright notice in LICENSE. 5 | -- 6 | 7 | local _M = {} 8 | 9 | -- Cache library functions. 10 | local insert, concat = table.insert, table.concat 11 | local find, format, sub = string.find, string.format, string.sub 12 | 13 | -- Parse verbatim blocks containing template expressions. 14 | local function parse_expression(result, chunk) 15 | local i, n = 1, #chunk 16 | while i <= n do 17 | local s, e, expr = find(chunk, "$(%b{})", i) 18 | if not s or s > i then 19 | insert(result, format("_put(%q)", sub(chunk, i, s and s - 1))) 20 | end 21 | if not s then break end 22 | insert(result, format("_put(%s)", sub(expr, 2, -2))) 23 | i = e + 1 24 | end 25 | end 26 | 27 | -- Parse template statements. 28 | local function parse_statement(result, chunk) 29 | local i, n = 1, #chunk 30 | while i <= n do 31 | local s, e, stmt = find(chunk, "%f[^%z\n]%s*|([^\n]*\n?)", i) 32 | if not s or s > i then 33 | parse_expression(result, sub(chunk, i, s and s - 1)) 34 | end 35 | if not s then break end 36 | insert(result, stmt) 37 | i = e + 1 38 | end 39 | end 40 | 41 | -- Lua 5.1 uses setfenv, Lua 5.2 uses _ENV 42 | local setfenv = setfenv 43 | 44 | local render_to_function 45 | if setfenv then 46 | function render_to_function(render, f, env) 47 | setfenv(render, env) 48 | local status, err = pcall(render, f) 49 | if not status then return error(err) end 50 | end 51 | else 52 | function render_to_function(render, f, env) 53 | local status, err = pcall(render, f, env) 54 | if not status then return error(err) end 55 | end 56 | end 57 | 58 | local function render_to_string(render, env) 59 | local t = {} 60 | local f = function(s) 61 | if s ~= nil then insert(t, tostring(s)) end 62 | end 63 | local status, err = pcall(render_to_function, render, f, env) 64 | if not status then return error(err) end 65 | return concat(t) 66 | end 67 | 68 | --- Lua 5.2 deprecates loadstring 69 | local load = loadstring or load 70 | 71 | local function loadtemplate(s, source) 72 | local result = {"local _put, _ENV = ..."} 73 | parse_statement(result, s) 74 | local render, err = load(concat(result), source) 75 | if not render then return error(err) end 76 | return function(env, f) 77 | local env = env or _G 78 | if not f then 79 | return render_to_string(render, env) 80 | else 81 | return render_to_function(render, f, env) 82 | end 83 | end 84 | end 85 | 86 | function _M.loadstring(s) 87 | local status, result = pcall(loadtemplate, s, s) 88 | if not status then return error(result) end 89 | return result 90 | end 91 | 92 | function _M.loadfile(filename) 93 | local f, err = io.open(filename, "r") 94 | if not f then return error(err) end 95 | local s = f:read("*a") 96 | local status, result = pcall(loadtemplate, s, "@" .. filename) 97 | if not status then return error(result) end 98 | f:close() 99 | return result 100 | end 101 | 102 | return _M 103 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- A general purpose library that extends Lua standard libraries. 3 | -- 4 | -- Copyright (C) 2011-2016 Stefano Peluchetti. All rights reserved. 5 | -- 6 | -- Features, documentation and more: http://www.scilua.org . 7 | -- 8 | -- This file is part of the Xsys library, which is released under the MIT 9 | -- license: full text in file LICENSE.TXT in the library's root folder. 10 | -------------------------------------------------------------------------------- 11 | 12 | -- TODO: Design exec API logging so that files are generated (useful for 13 | -- TODO: debugging and profiling). 14 | 15 | local ffi = require "ffi" 16 | local bit = require "bit" 17 | -- CREDIT: Peter Colberg's templet library: 18 | local templet = require "xsys._dep.templet" 19 | 20 | local select, pairs, error, setmetatable = select, pairs, error, setmetatable 21 | local type, loadstring, setfenv, unpack = type, loadstring, setfenv, unpack 22 | local pcall = pcall 23 | local insert, concat = table.insert, table.concat 24 | local format = string.format 25 | local abs = math.abs 26 | 27 | -- Table ----------------------------------------------------------------------- 28 | -- TODO: Introduce optional trailing 'resv = onconflict(key, v, newv)'. 29 | local function union(...) 30 | local o = {} 31 | local arg, n = { ... }, select("#", ...) 32 | for a=1,n do 33 | for k,v in pairs(arg[a]) do 34 | if type(o[k]) ~= "nil" then 35 | error("key '"..tostring(k).."' is not unique among tables to be merged") 36 | end 37 | o[k] = v 38 | end 39 | end 40 | return o 41 | end 42 | 43 | local function append(...) 44 | local o = { } 45 | local arg, n = { ... }, select("#", ...) 46 | local c = 0 47 | for a=1,n do 48 | local t = arg[a] 49 | for i=1,#t do 50 | c = c + 1 51 | local v = t[i] 52 | if type(v) == "nil" then 53 | error("argument #"..a.." is not a proper array: no nil values allowed") 54 | end 55 | o[c] = v 56 | end 57 | end 58 | return o 59 | end 60 | 61 | -- Another module might have modified the standard libraries, overwrite: 62 | local table = union(table) 63 | table.union = union 64 | table.append = append 65 | 66 | -- Tonumber -------------------------------------------------------------------- 67 | local function getton(x) 68 | return x.__tonumber 69 | end 70 | 71 | local function tonumberx(x) 72 | if type(x) ~= "table" and type(x) ~= "cdata" then 73 | return tonumber(x) 74 | else 75 | local haston, ton = pcall(getton, x) 76 | return (haston and ton) and ton(x) or tonumber(x) 77 | end 78 | end 79 | 80 | -- String ---------------------------------------------------------------------- 81 | -- CREDIT: Steve Dovan snippet. 82 | -- TODO: Clarify corner cases, make more robust. 83 | local function split(s, re) 84 | local i1, ls = 1, { } 85 | if not re then re = '%s+' end 86 | if re == '' then return { s } end 87 | while true do 88 | local i2, i3 = s:find(re, i1) 89 | if not i2 then 90 | local last = s:sub(i1) 91 | if last ~= '' then insert(ls, last) end 92 | if #ls == 1 and ls[1] == '' then 93 | return { } 94 | else 95 | return ls 96 | end 97 | end 98 | insert(ls, s:sub(i1, i2 - 1)) 99 | i1 = i3 + 1 100 | end 101 | end 102 | 103 | -- TODO: what = "lr" 104 | local function trim(s) 105 | return (s:gsub("^%s*(.-)%s*$", "%1")) 106 | end 107 | 108 | local function adjustexp(s) 109 | if s:sub(-3, -3) == "+" or s:sub(-3, -3) == "-" then 110 | return s:sub(1, -3).."0"..s:sub(-2) 111 | else 112 | return s 113 | end 114 | end 115 | 116 | local function width(x, chars) 117 | chars = chars or 9 118 | if chars < 9 then 119 | error("at least 9 characters required") 120 | end 121 | if type(x) == "nil" then 122 | return (" "):rep(chars - 3).."nil" 123 | elseif type(x) == "boolean" then 124 | local s = tostring(x) 125 | return (" "):rep(chars - #s)..s 126 | elseif type(x) == "string" then 127 | if #x > chars then 128 | return x:sub(1, chars - 2)..".." 129 | else 130 | return (" "):rep(chars - #x)..x 131 | end 132 | else 133 | local formatf = "%+"..chars.."."..(chars - 3).."f" 134 | local formate = "%+."..(chars - 8).."e" 135 | x = tonumberx(x) -- Could be cdata. 136 | local s = format(formatf, x) 137 | if x ~= x or abs(x) == 1/0 then return s end 138 | if tonumberx(s:sub(2, chars)) == 0 then -- It's small. 139 | if abs(x) ~= 0 then -- And not zero. 140 | s = adjustexp(format(formate, x)) 141 | end 142 | else 143 | s = s:sub(1, chars) 144 | if not s:sub(3, chars - 1):find('%.') then -- It's big. 145 | s = adjustexp(format(formate, x)) 146 | end 147 | end 148 | return s 149 | end 150 | end 151 | 152 | -- Another module might have modified the standard libraries, overwrite: 153 | local string = union(string) 154 | string.split = split 155 | string.trim = trim 156 | string.width = width 157 | 158 | -- Exec ------------------------------------------------------------------------ 159 | local function testexec(chunk, chunkname, fenv, ok, ...) 160 | if not ok then 161 | local err = select(1, ...) 162 | error("execution error: "..err) 163 | end 164 | return ... 165 | end 166 | 167 | local function exec(chunk, chunkname, fenv) 168 | chunkname = chunkname or chunk 169 | local f, err = loadstring(chunk, chunkname) 170 | if not f then 171 | error("parsing error: "..err) 172 | end 173 | if fenv then 174 | setfenv(f, fenv) 175 | end 176 | return testexec(chunk, chunkname, fenv, pcall(f)) 177 | end 178 | 179 | -- From ------------------------------------------------------------------------ 180 | local function from(what, keystr) 181 | local keys = split(keystr, ",") 182 | local o = { } 183 | for i=1,#keys do 184 | o[i] = "x."..trim(keys[i]) 185 | end 186 | o = concat(o, ",") 187 | local s = "return function(x) return "..o.." end" 188 | return exec(s, "from<"..keystr..">")(what) 189 | end 190 | 191 | -- Bit ------------------------------------------------------------------------- 192 | local tobit, lshift, rshift, band = bit.tobit, bit.lshift, bit.rshift, bit.band 193 | 194 | -- 99 == not used. 195 | local lsb_array = ffi.new("const int32_t[64]", {32, 0, 1, 12, 2, 6, 99, 13, 196 | 3, 99, 7, 99, 99, 99, 99, 14, 10, 4, 99, 99, 8, 99, 99, 25, 99, 99, 99, 99, 197 | 99, 21, 27, 15, 31, 11, 5, 99, 99, 99, 99, 99, 9, 99, 99, 24, 99, 99, 20, 26, 198 | 30, 99, 99, 99, 99, 23, 99, 19, 29, 99, 22, 18, 28, 17, 16, 99}) 199 | 200 | -- Compute position of least significant bit, starting with 0 for the tail of 201 | -- the bit representation and ending with 31 for the head of the bit 202 | -- representation (right to left). If all bits are 0 then 32 is returned. 203 | -- This corresponds to finding the i in 2^i if the 4-byte value is set to 2^i. 204 | -- Branch free version. 205 | local function lsb(x) 206 | x = band(x, -x) 207 | x = tobit(lshift(x, 4) + x) 208 | x = tobit(lshift(x, 6) + x) 209 | x = tobit(lshift(x, 16) - x) 210 | return lsb_array[rshift(x, 26)] 211 | end 212 | 213 | -- Another module might have modified the standard libraries, overwrite: 214 | local bit = union(bit) 215 | bit.lsb = lsb -- TODO: Document. 216 | 217 | -- Export ---------------------------------------------------------------------- 218 | 219 | return { 220 | template = templet.loadstring, 221 | exec = exec, 222 | from = from, 223 | tonumber = tonumberx, 224 | table = table, 225 | string = string, 226 | bit = bit, 227 | } 228 | --------------------------------------------------------------------------------