local preproc = {} preproc.directives = {} function preproc.parsewords(line) -- string -- table -- Returns a table of words from the string *line*, parsing quotes and escapes. local rt = {""} local escaped, quoted = false, false for c in line:gmatch(".") do if escaped then rt[#rt] = rt[#rt]..c elseif c == '"' or c == "'" then quoted = not quoted elseif c == "\\" then escaped = true elseif c:match("%s") and not quoted and rt[#rt]:len() > 0 then rt[#rt+1] = "" else rt[#rt] = rt[#rt]..c end end return rt end function preproc.line(line) -- string -- -- Returns either a function - which can be called to get lines until it returns nil - or a string from processing *line* using preprocessor directives. if line:match("^%-%-#") then local directive, args = line:match("^%-%-#(%S+)%s(.+)") print(directive,args) local args = preproc.parsewords(args) if preproc.directives[directive] then return preproc.directives[directive](table.unpack(args)) else error("unknown preprocessor directive: "..directive) end else return line end end function preproc.preproc(...) -- string -- string -- Returns the output from preprocessing the files listed in *...*. local tA = {...} local output = "" for _,fname in ipairs(tA) do local f,e = io.open(fname) if not f then error("unable to open file "..fname..": "..e) end for line in f:lines() do local r = preproc.line(line) if type(r) == "function" then while true do local rs = r() if not rs then break end output = output .. rs .. "\n" end else output = output .. r .. "\n" end end end return output end preproc.directives.include = preproc.preproc function preproc.directives.includelib(file, name) -- string string -- string -- Returns a preprocessed inlined library return string.format("package.loaded['%s'] = (function()\n%s\nend)()", name, preproc.preproc(file)) end function preproc.directives.includepkgfile(package, file) if (_OSVERSION or ""):sub(1,7) == "PsychOS" then return preproc.preproc(string.format("/pkg/%s", file)) else for path in (os.getenv("PSYCHOSPACKAGES") or "../PsychOSPackages"):gmatch("[^:]+") do local f = io.open(string.format("%s/%s/%s", path, package, file), "r") if f then f:close() return preproc.preproc(string.format("%s/%s/%s", path, package, file)) end end end error(string.format("unable to locate file %s from package %s", file, package)) end function preproc.directives.includepkglib(package, file, name) -- string string -- string -- Returns a preprocessed inlined library return string.format("package.loaded['%s'] = (function()\n%s\nend)()", name, preproc.directives.includepkgfile(package, file)) end local minify = true local minifyFilters = { {"%-%-%[%[.-%]%]",""}, {"%-%-.-\n","\n"}, {"\n[ \t]+","\n"}, {"%s?%.%.%s?",".."}, {"%s?==%s?","=="}, {"%s?~=%s?","~="}, {"%s?>=%s?",">="}, {"%s?<=%s?","<="}, {"%s?>%s?",">"}, {"%s?<%s?","<"}, {"%s?=%s?","="}, {"%s?,%s?",","}, {",\n",","}, {"\n\n+","\n"}, {"[ \t]\n","\n"}, {"%{%s+","{"}, {"%s+%}","}"} } return setmetatable(preproc,{__call=function(_,...) local tA = {...} local out = table.remove(tA,#tA) local f,e = io.open(out,"wb") if not f then error("unable to open file "..out..": "..e) end local out = preproc.preproc(table.unpack(tA)) if preproc.minify then local olen = #out for k,v in ipairs(minifyFilters) do out = out:gsub(v[1],v[2]) end print(olen, #out) end f:write(out) f:close() end})