diff --git a/.gitignore b/.gitignore index ac66fe4..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +0,0 @@ -/*.lua -/*.lua.c -/moonbuild diff --git a/moonbuild/fsutil.lua b/moonbuild/fsutil.lua new file mode 100644 index 0000000..f4de9ba --- /dev/null +++ b/moonbuild/fsutil.lua @@ -0,0 +1,155 @@ +local dir, attributes +do + local _obj_0 = require('lfs') + dir, attributes = _obj_0.dir, _obj_0.attributes +end +local gmatch, match, gsub, sub +do + local _obj_0 = string + gmatch, match, gsub, sub = _obj_0.gmatch, _obj_0.match, _obj_0.gsub, _obj_0.sub +end +local insert, concat +do + local _obj_0 = table + insert, concat = _obj_0.insert, _obj_0.concat +end +local ls +ls = function(d) + local _accum_0 = { } + local _len_0 = 1 + for f in dir(d) do + if f ~= '.' and f ~= '..' then + _accum_0[_len_0] = f + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end +local lswithpath +lswithpath = function(d) + if d == '' then + return ls('.') + end + local _accum_0 = { } + local _len_0 = 1 + for f in dir(d) do + if f ~= '.' and f ~= '..' then + _accum_0[_len_0] = d .. '/' .. f + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end +local exists +exists = function(f) + return (attributes(f)) ~= nil +end +local isdir +isdir = function(f) + local a = attributes(f) + return a and a.mode == 'directory' or false +end +local mtime +mtime = function(f) + local a = attributes(f) + return a and a.modification +end +local matchglob +matchglob = function(str, glob) + local patt = '^' .. (gsub((gsub(glob, '%*%*', '.*')), '%*', '[^/]*')) .. '$' + local rst + if (type(str)) == 'table' then + local results, i = { }, 1 + for _index_0 = 1, #str do + local s = str[_index_0] + rst = (match(s, patt)) and s + if rst then + results[i], i = rst, i + 1 + end + end + rst = results + else + rst = (match(str, patt)) and str + end + return rst +end +local wildcard +wildcard = function(glob) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for part in gmatch(glob, '[^/]+') do + _accum_0[_len_0] = part + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + local absolute = (sub(glob, 1, 1)) == '/' + for i, part in ipairs(parts) do + local prevpath = (absolute and '/' or '') .. concat(parts, '/', 1, i - 1) + local currpath = prevpath .. '/' .. part + if match(part, '%*%*.*%*%*') then + error("Two '**' in the same path component in a wildcard") + end + if match(part, '%*%*') then + local prefix = match(currpath, '^(.*)%*%*') + local suffix = (match(part, '%*%*(.*)$')) .. (i == #parts and '' or ('/' .. concat(parts, '/', i + 1, #parts))) + local files = lswithpath(prevpath) + local results = { } + for _index_0 = 1, #files do + local file = files[_index_0] + if matchglob(file, currpath) then + if i == #parts then + insert(results, file) + elseif isdir(file) then + local _list_0 = wildcard(file .. '/' .. concat(parts, '/', i + 1, #parts)) + for _index_1 = 1, #_list_0 do + local result = _list_0[_index_1] + insert(results, result) + end + end + end + if (matchglob(file, prefix .. '**')) and isdir(file) then + local _list_0 = wildcard(file .. '/**' .. suffix) + for _index_1 = 1, #_list_0 do + local result = _list_0[_index_1] + insert(results, result) + end + end + end + return results + end + if match(part, '%*') then + local files = lswithpath(prevpath) + if i == #parts then + return matchglob(files, glob) + end + local results = { } + for _index_0 = 1, #files do + local file = files[_index_0] + if (matchglob(file, currpath)) and isdir(file) then + local _list_0 = wildcard(file .. '/' .. concat(parts, '/', i + 1, #parts)) + for _index_1 = 1, #_list_0 do + local result = _list_0[_index_1] + insert(results, result) + end + end + end + return results + end + end + if exists(glob) then + return { + glob + } + else + return { } + end +end +return { + wildcard = wildcard, + exists = exists, + isdir = isdir, + mtime = mtime +} diff --git a/moonbuild/fsutil.moon b/moonbuild/fsutil.moon new file mode 100644 index 0000000..de42388 --- /dev/null +++ b/moonbuild/fsutil.moon @@ -0,0 +1,88 @@ +import dir, attributes from require 'lfs' + +import gmatch, match, gsub, sub from string +import insert, concat from table + +ls = (d) -> + [f for f in dir d when f!='.' and f!='..'] + +lswithpath = (d) -> + if d=='' + return ls '.' + [d..'/'..f for f in dir d when f!='.' and f!='..'] + +exists = (f) -> + (attributes f) != nil + +isdir = (f) -> + a = attributes f + a and a.mode == 'directory' or false + +mtime = (f) -> + a = attributes f + a and a.modification + +matchglob = (str, glob) -> + patt = '^'..(gsub (gsub glob, '%*%*', '.*'), '%*', '[^/]*')..'$' + rst = if (type str)=='table' + results, i = {}, 1 + for s in *str + rst = (match s, patt) and s + results[i], i = rst, i+1 if rst + results + else + (match str, patt) and str + rst + +wildcard = (glob) -> + parts = [part for part in gmatch glob, '[^/]+'] + absolute = (sub glob, 1, 1)=='/' + + for i, part in ipairs parts + prevpath = (absolute and '/' or '') .. concat parts, '/', 1, i-1 + currpath = prevpath .. '/' .. part + + if match part, '%*%*.*%*%*' + error "Two '**' in the same path component in a wildcard" + + if match part, '%*%*' + prefix = match currpath, '^(.*)%*%*' + suffix = (match part, '%*%*(.*)$') .. (i==#parts and '' or ('/'..concat parts, '/', i+1, #parts)) + files = lswithpath prevpath + + results = {} + for file in *files + if matchglob file, currpath + if i==#parts + insert results, file + elseif isdir file + for result in *wildcard file .. '/' .. concat parts, '/', i+1, #parts + insert results, result + if (matchglob file, prefix..'**') and isdir file + for result in *wildcard file .. '/**' .. suffix + insert results, result + return results + + if match part, '%*' + files = lswithpath prevpath + + if i==#parts + return matchglob files, glob + + results = {} + for file in *files + if (matchglob file, currpath) and isdir file + for result in *wildcard file .. '/' .. concat parts, '/', i+1, #parts + insert results, result + return results + + if exists glob + return {glob} + else + return {} + +{ + :wildcard + :exists, :isdir + :mtime +} diff --git a/moonbuild/stringutil.lua b/moonbuild/stringutil.lua new file mode 100644 index 0000000..d5b4e35 --- /dev/null +++ b/moonbuild/stringutil.lua @@ -0,0 +1,52 @@ +local match, gmatch, sub +do + local _obj_0 = string + match, gmatch, sub = _obj_0.match, _obj_0.gmatch, _obj_0.sub +end +local upper, lower +do + local _obj_0 = string + upper, lower = _obj_0.upper, _obj_0.lower +end +local GLOB_PATT = '^([^%%]*)%%([^%%]*)$' +local patsubst +patsubst = function(str, pattern, replacement) + if (type(str)) == 'table' then + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #str do + local s = str[_index_0] + _accum_0[_len_0] = patsubst(s, pattern, replacement) + _len_0 = _len_0 + 1 + end + return _accum_0 + end + local prefix, suffix = match(pattern, GLOB_PATT) + if not (prefix) then + return str + end + local reprefix, resuffix = match(replacement, GLOB_PATT) + if not (reprefix) then + return replacement + end + if (sub(str, 1, #prefix)) == prefix and (sub(str, -#suffix)) == suffix then + return reprefix .. (sub(str, #prefix + 1, -#suffix - 1)) .. resuffix + end + return str +end +local splitsp +splitsp = function(str) + local _accum_0 = { } + local _len_0 = 1 + for elem in gmatch(str, '%S+') do + _accum_0[_len_0] = elem + _len_0 = _len_0 + 1 + end + return _accum_0 +end +return { + patsubst = patsubst, + splitsp = splitsp, + upper = upper, + lower = lower +} diff --git a/moonbuild/stringutil.moon b/moonbuild/stringutil.moon new file mode 100644 index 0000000..91aeab8 --- /dev/null +++ b/moonbuild/stringutil.moon @@ -0,0 +1,25 @@ +import match, gmatch, sub from string +import upper, lower from string + +GLOB_PATT='^([^%%]*)%%([^%%]*)$' + +patsubst = (str, pattern, replacement) -> + return [patsubst s, pattern, replacement for s in *str] if (type str)=='table' + prefix, suffix = match pattern, GLOB_PATT + return str unless prefix + reprefix, resuffix = match replacement, GLOB_PATT + return replacement unless reprefix + + if (sub str, 1, #prefix)==prefix and (sub str, -#suffix)==suffix + return reprefix..(sub str, #prefix+1, -#suffix-1)..resuffix + str + +splitsp = (str) -> + [elem for elem in gmatch str, '%S+'] + +{ + :patsubst + :splitsp + + :upper, :lower +} diff --git a/moonbuild/tableutil.lua b/moonbuild/tableutil.lua new file mode 100644 index 0000000..ea771e6 --- /dev/null +++ b/moonbuild/tableutil.lua @@ -0,0 +1,132 @@ +local insert, remove, concat, sort +do + local _obj_0 = table + insert, remove, concat, sort = _obj_0.insert, _obj_0.remove, _obj_0.concat, _obj_0.sort +end +local unpack = unpack or table.unpack +local sortedpairs +sortedpairs = function(table, cmp) + local keys + do + local _accum_0 = { } + local _len_0 = 1 + for k in pairs(table) do + _accum_0[_len_0] = k + _len_0 = _len_0 + 1 + end + keys = _accum_0 + end + sort(keys, cmp) + return coroutine.wrap(function() + for _index_0 = 1, #keys do + local key = keys[_index_0] + coroutine.yield(key, table[key]) + end + end) +end +local min +min = function(table, cmp) + if cmp == nil then + cmp = function(a, b) + return a < b + end + end + local val = table[1] + for i = 2, #table do + local elem = table[i] + if cmp(val, elem) then + val = elem + end + end + return val +end +local max +max = function(table, cmp) + if cmp == nil then + cmp = function(a, b) + return a < b + end + end + local val = table[1] + for i = 2, #table do + local elem = table[i] + if not cmp(val, elem) then + val = elem + end + end + return val +end +local foreach +foreach = function(tab, fn) + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #tab do + local e = tab[_index_0] + _accum_0[_len_0] = fn(e) + _len_0 = _len_0 + 1 + end + return _accum_0 +end +local first +first = function(tab, fn) + for _index_0 = 1, #tab do + local e = tab[_index_0] + if fn(e) then + return e + end + end +end +local exclude +exclude = function(tab, ...) + local i = 1 + while i <= #tab do + local removed = false + for j = 1, select('#', ...) do + if tab[i] == select(j, ...) then + remove(tab, i) + removed = true + break + end + end + if not (removed) then + i = i + 1 + end + end + return tab +end +local flatten +flatten = function(tab) + if (type(tab)) ~= 'table' then + return { + tab + } + end + local out = { } + for _index_0 = 1, #tab do + local e = tab[_index_0] + if (type(e)) == 'table' then + local _list_0 = flatten(e) + for _index_1 = 1, #_list_0 do + local v = _list_0[_index_1] + insert(out, v) + end + else + insert(out, e) + end + end + return out +end +return { + min = min, + max = max, + foreach = foreach, + first = first, + exclude = exclude, + flatten = flatten, + sortedpairs = sortedpairs, + insert = insert, + remove = remove, + concat = concat, + sort = sort, + unpack = unpack +} diff --git a/moonbuild/tableutil.moon b/moonbuild/tableutil.moon new file mode 100644 index 0000000..77bcd49 --- /dev/null +++ b/moonbuild/tableutil.moon @@ -0,0 +1,66 @@ +import insert, remove, concat, sort from table +unpack or= table.unpack + +sortedpairs = (table, cmp) -> + keys = [k for k in pairs table] + sort keys, cmp + coroutine.wrap -> + for key in *keys + coroutine.yield key, table[key] + +min = (table, cmp=(a, b) -> a + val = table[1] + for i=2, #table + elem = table[i] + if cmp val, elem + val = elem + val + +max = (table, cmp=(a, b) -> a + val = table[1] + for i=2, #table + elem = table[i] + if not cmp val, elem + val = elem + val + +foreach = (tab, fn) -> + [fn e for e in *tab] + +first = (tab, fn) -> + for e in *tab + return e if fn e + +exclude = (tab, ...) -> + i=1 + while i<=#tab + removed=false + for j=1, select '#', ... + if tab[i]==select j, ... + remove tab, i + removed = true + break + i += 1 unless removed + tab + +flatten = (tab) -> + return {tab} if (type tab)!='table' + out = {} + for e in *tab + if (type e)=='table' + insert out, v for v in *flatten e + else + insert out, e + out + +{ + :min, :max + :foreach + :first + :exclude + :flatten + :sortedpairs + + :insert, :remove, :concat, :sort + :unpack +} diff --git a/moonbuild/util.lua b/moonbuild/util.lua new file mode 100644 index 0000000..0470d5a --- /dev/null +++ b/moonbuild/util.lua @@ -0,0 +1,189 @@ +local wildcard, exists, isdir, mtime +do + local _obj_0 = require('moonbuild.fsutil') + wildcard, exists, isdir, mtime = _obj_0.wildcard, _obj_0.exists, _obj_0.isdir, _obj_0.mtime +end +local foreach, first, flatten, exclude, sortedpairs, min, max +do + local _obj_0 = require('moonbuild.tableutil') + foreach, first, flatten, exclude, sortedpairs, min, max = _obj_0.foreach, _obj_0.first, _obj_0.flatten, _obj_0.exclude, _obj_0.sortedpairs, _obj_0.min, _obj_0.max +end +local patsubst, splitsp +do + local _obj_0 = require('moonbuild.stringutil') + patsubst, splitsp = _obj_0.patsubst, _obj_0.splitsp +end +local insert, concat, sort, pairs +do + local _obj_0 = require('moonbuild.tableutil') + insert, concat, sort, pairs = _obj_0.insert, _obj_0.concat, _obj_0.sort, _obj_0.pairs +end +local upper, lower +do + local _obj_0 = require('moonbuild.stringutil') + upper, lower = _obj_0.upper, _obj_0.lower +end +local GLOB_PATT = '^([^%%]*)%%([^%%]*)$' +local escapecmdpart +escapecmdpart = function(p) + if (type(p)) == 'table' then + if p.raw then + return p.raw + end + return concat((function() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #p do + local part = p[_index_0] + _accum_0[_len_0] = escapecmdpart(part) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ' ') + end + if p:match('^[a-zA-Z0-9_./-]+$') then + return p + end + return '"' .. p:gsub('\\', '\\\\'):gsub('"', '\\"') .. '"' +end +local escapecmd +escapecmd = function(c, args) + if args == nil then + args = { } + end + c = escapecmdpart(c) + local _list_0 = flatten(args) + for _index_0 = 1, #_list_0 do + local a = _list_0[_index_0] + if a then + c = c .. (' ' .. escapecmdpart(a)) + end + end + return c +end +local run +run = function(c, args, params) + if params == nil then + params = { } + end + local escaped = escapecmd(c, args) + if params.print then + print(escaped) + end + local ret, _, code = os.execute(escaped) + if (type(ret)) == 'number' then + ret, code = ret == 0, ret + end + if params.error and not ret then + error(tostring(c) .. " failed with code " .. tostring(code)) + end + return ret, code +end +local popen +popen = function(c, args, mode, params) + if mode == nil then + mode = 'r' + end + if params == nil then + params = { } + end + local escaped = escapecmd(c, args) + if params.print then + print(escaped) + end + return io.popen(escaped, mode) +end +local calccdeps +calccdeps = function(infile, includesys) + if includesys == nil then + includesys = false + end + local data = (popen('cc', { + includesys and '-M' or '-MM', + infile + })):read('*a') + local rawdeps = data:gsub('\\\n', ''):match(':(.+)') + local _accum_0 = { } + local _len_0 = 1 + for dep in rawdeps:gmatch('%S+') do + if dep ~= infile then + _accum_0[_len_0] = dep + _len_0 = _len_0 + 1 + end + end + return _accum_0 +end +local findclib +findclib = function(name, mode) + if mode == nil then + mode = 'all' + end + local args = { + name + } + if mode == 'all' or mode == 'cc' then + insert(args, '--cflags') + end + if mode == 'all' or mode == 'ld' then + insert(args, '--libs') + end + local _accum_0 = { } + local _len_0 = 1 + for arg in (popen('pkg-config', args)):read('*a'):gmatch('%S+') do + _accum_0[_len_0] = arg + _len_0 = _len_0 + 1 + end + return _accum_0 +end +local match +match = function(str, glob) + local prefix, suffix = glob:match(GLOB_PATT) + if not (prefix) then + return str == glob + end + if (str:sub(1, #prefix)) == prefix and (str:sub(-#suffix)) == suffix then + return str:sub(#prefix + 1, -#suffix - 1) + end + return false +end +local isglob +isglob = function(glob) + if glob:match(GLOB_PATT) then + return true + else + return false + end +end +local env +env = function(key, def) + return (os.getenv(key)) or def +end +return { + min = min, + max = max, + foreach = foreach, + first = first, + exclude = exclude, + flatten = flatten, + sortedpairs = sortedpairs, + insert = insert, + remove = remove, + concat = concat, + sort = sort, + unpack = unpack, + wildcard = wildcard, + mtime = mtime, + exists = exists, + isdir = isdir, + run = run, + popen = popen, + calccdeps = calccdeps, + findclib = findclib, + patsubst = patsubst, + splitsp = splitsp, + upper = upper, + lower = lower, + match = match, + isglob = isglob, + env = env +} diff --git a/moonbuild/util.moon b/moonbuild/util.moon new file mode 100644 index 0000000..3b39c1b --- /dev/null +++ b/moonbuild/util.moon @@ -0,0 +1,95 @@ +import wildcard, exists, isdir, mtime from require 'moonbuild.fsutil' +import foreach, first, flatten, exclude, sortedpairs, min, max from require 'moonbuild.tableutil' +import patsubst, splitsp from require 'moonbuild.stringutil' + +import insert, concat, sort, pairs from require 'moonbuild.tableutil' +import upper, lower from require 'moonbuild.stringutil' + +GLOB_PATT='^([^%%]*)%%([^%%]*)$' + +-- command functions +escapecmdpart= (p) -> + if (type p)=='table' + return p.raw if p.raw + return concat [escapecmdpart part for part in *p], ' ' + return p if p\match '^[a-zA-Z0-9_./-]+$' + '"'..p\gsub('\\', '\\\\')\gsub('"', '\\"')..'"' +escapecmd= (c, args={}) -> + c=escapecmdpart c + for a in *flatten args + c..=' '..escapecmdpart a if a + c +run= (c, args, params={}) -> + escaped=escapecmd c, args + print escaped if params.print + ret, _, code=os.execute escaped + ret, code=ret==0, ret if (type ret)=='number' + error "#{c} failed with code #{code}" if params.error and not ret + ret, code +popen= (c, args, mode='r', params={}) -> + escaped=escapecmd c, args + print escaped if params.print + io.popen escaped, mode + +calccdeps= (infile, includesys=false) -> + data=(popen 'cc', {includesys and '-M' or '-MM', infile})\read '*a' + rawdeps=data\gsub('\\\n', '')\match ':(.+)' + [dep for dep in rawdeps\gmatch '%S+' when dep!=infile] + +findclib= (name, mode='all') -> + args={name} + insert args, '--cflags' if mode=='all' or mode=='cc' + insert args, '--libs' if mode=='all' or mode=='ld' + [arg for arg in (popen 'pkg-config', args)\read('*a')\gmatch '%S+'] + +-- glob match +match= (str, glob) -> + prefix, suffix=glob\match GLOB_PATT + return str==glob unless prefix + return str\sub #prefix+1, -#suffix-1 if (str\sub 1, #prefix)==prefix and (str\sub -#suffix)==suffix + false + +-- is a valid glob +isglob= (glob) -> + return if glob\match GLOB_PATT + true + else + false + +-- getenv +env= (key, def) -> + (os.getenv key) or def + +{ + -- table function + :min, :max + :foreach + :first + :exclude + :flatten + :sortedpairs + + :insert, :remove, :concat, :sort + :unpack + + -- file functions + :wildcard + :mtime + :exists, :isdir + + -- command functions + :run, :popen + :calccdeps, :findclib + + -- string functions + :patsubst + :splitsp + + :upper, :lower + + -- glob functions + :match, :isglob + + -- env functions + :env +}