util-lua.lua /size: 7166 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['util-lua'] = {
2    version   = 1.001,
3    comment   = "companion to luat-lib.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    comment   = "the strip code is written by Peter Cawley",
6    copyright = "PRAGMA ADE / ConTeXt Development Team",
7    license   = "see context related readme files"
8}
9
10-- we will remove the 5.1 code some day soon
11
12local rep, sub, byte, dump, format = string.rep, string.sub, string.byte, string.dump, string.format
13local load, loadfile, type, collectgarbage = load, loadfile, type, collectgarbage
14
15utilities          = utilities or {}
16utilities.lua      = utilities.lua or { }
17local luautilities = utilities.lua
18
19local report_lua = logs.reporter("system","lua")
20local report_mem = logs.reporter("system","lua memory")
21
22local tracestripping           = false
23local tracememory              = false
24luautilities.stripcode         = true  -- support stripping when asked for
25luautilities.alwaysstripcode   = false -- saves 1 meg on 7 meg compressed format file (2012.08.12)
26luautilities.nofstrippedchunks = 0
27luautilities.nofstrippedbytes  = 0
28local strippedchunks           = { } -- allocate()
29luautilities.strippedchunks    = strippedchunks
30
31if not LUATEXENGINE then
32    --- probably mtxrun ...
33    LUATEXENGINE    = status.luatex_engine and string.lower(status.luatex_engine)
34    JITSUPPORTED    = LUATEXENGINE == "luajittex" or jit
35    CONTEXTLMTXMODE = CONTEXTLMTXMODE or (LUATEXENGINE == "luametatex" and 1) or 0
36end
37
38luautilities.suffixes = {
39    tma = "tma",
40    tmc = (CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and "tmd") or (jit and "tmb") or "tmc",
41    lua = "lua",
42    lmt = "lmt",
43    luc = (CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and "lud") or (jit and "lub") or "luc",
44    lui = "lui",
45    luv = "luv",
46    luj = "luj",
47    tua = "tua",
48 -- tuc = "tuc",
49    tuc = (CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and "tud") or (jit and "tub") or "tuc",
50}
51
52-- environment.loadpreprocessedfile can be set to a preprocessor
53
54local function register(name) -- makes no sense runtime
55    if tracestripping then
56        report_lua("stripped bytecode from %a",name or "unknown")
57    end
58    strippedchunks[#strippedchunks+1] = name
59    luautilities.nofstrippedchunks = luautilities.nofstrippedchunks + 1
60end
61
62local function stupidcompile(luafile,lucfile,strip)
63    local code = io.loaddata(luafile)
64    if code and code ~= "" then
65        code = load(code)
66        if code then
67            code = dump(code,strip and luautilities.stripcode or luautilities.alwaysstripcode)
68            if code and code ~= "" then
69                register(name)
70                io.savedata(lucfile,code)
71                return true, 0
72            end
73        else
74            report_lua("fatal error %a in file %a",1,luafile)
75        end
76    else
77        report_lua("fatal error %a in file %a",2,luafile)
78    end
79    return false, 0
80end
81
82-- quite subtle ... doing this wrong incidentally can give more bytes
83
84function luautilities.loadedluacode(fullname,forcestrip,name,macros)
85    -- quite subtle ... doing this wrong incidentally can give more bytes
86    name = name or fullname
87    if macros then
88        macros = lua.macros
89    end
90    local code, message
91    if macros then
92        code, message = macros.loaded(fullname,true,false)
93    else
94        code, message = loadfile(fullname)
95    end
96    if code then
97        code()
98    else
99        report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message")
100        code, message = loadfile(fullname)
101    end
102    if forcestrip and luautilities.stripcode then
103        if type(forcestrip) == "function" then
104            forcestrip = forcestrip(fullname)
105        end
106        if forcestrip or luautilities.alwaysstripcode then
107            register(name)
108            return load(dump(code,true)), 0
109        else
110            return code, 0
111        end
112    elseif luautilities.alwaysstripcode then
113        register(name)
114        return load(dump(code,true)), 0
115    else
116        return code, 0
117    end
118end
119
120function luautilities.strippedloadstring(code,name,forcestrip) -- not executed
121    local code, message = load(code)
122    if not code then
123        report_lua("loading of file %a failed:\n\t%s",name,message or "no message")
124    end
125    if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then
126        register(name)
127        return load(dump(code,true)), 0 -- not yet executed
128    else
129        return code, 0
130    end
131end
132
133function luautilities.loadstring(code,name) -- not executed
134    local code, message = load(code)
135    if not code then
136        report_lua("loading of file %a failed:\n\t%s",name,message or "no message")
137    end
138    return code, 0
139end
140
141function luautilities.compile(luafile,lucfile,cleanup,strip,fallback) -- defaults: cleanup=false strip=true
142    report_lua("compiling %a into %a",luafile,lucfile)
143    os.remove(lucfile)
144    local done = stupidcompile(luafile,lucfile,strip ~= false)
145    if done then
146        report_lua("dumping %a into %a stripped",luafile,lucfile)
147        if cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
148            report_lua("removing %a",luafile)
149            os.remove(luafile)
150        end
151    end
152    return done
153end
154
155function luautilities.loadstripped(...)
156    local l = load(...)
157    if l then
158        return load(dump(l,true))
159    end
160end
161
162-- local getmetatable, type = getmetatable, type
163--
164-- local types = { }
165--
166-- function luautilities.registerdatatype(d,name)
167--     types[getmetatable(d)] = name
168-- end
169--
170-- function luautilities.datatype(d)
171--     local t = type(d)
172--     if t == "userdata" then
173--         local m = getmetatable(d)
174--         return m and types[m] or "userdata"
175--     else
176--         return t
177--     end
178-- end
179--
180-- luautilities.registerdatatype(lpeg.P("!"),"lpeg")
181--
182-- print(luautilities.datatype(lpeg.P("oeps")))
183
184-- These finalizers will only be invoked when we have a proper lua_close
185-- call (which is not happening in luatex tex node yes) or finish with an
186-- os.exit(n,true).
187
188local finalizers = { }
189
190setmetatable(finalizers, {
191    __gc = function(t)
192        for i=1,#t do
193            pcall(t[i]) -- let's not crash
194        end
195    end
196} )
197
198function luautilities.registerfinalizer(f)
199    finalizers[#finalizers+1] = f
200end
201
202function luautilities.checkmemory(previous,threshold,trace) -- threshold in MB
203    local current = collectgarbage("count")
204    if previous then
205        local checked = (threshold or 64)*1024
206        local delta   = current - previous
207        if current - previous > checked then
208            collectgarbage("collect")
209            local afterwards = collectgarbage("count")
210            if trace or tracememory then
211                report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB",
212                    previous/1024,current/1024,delta/1024,threshold,afterwards)
213            end
214            return afterwards
215        elseif trace or tracememory then
216            report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB",
217                previous/1024,current/1024,delta/1024,threshold)
218        end
219    end
220    return current
221end
222