- Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathload.lua
More file actions
Latest commit
164 lines (146 loc) · 6.23 KB
/
Copy pathload.lua
File metadata and controls
164 lines (146 loc) · 6.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
--[[
shim load() and loadstring() and loadfile() layer
comes with callback handler for various AST or string modifications
How to make this more modular so that it could be applied to specific environments and not just _G ?
require 'ext.load'(_G) -- modify _G so load, loadstring, loadfile, require all use new load() function with xform shim layer
but if it's returning a function instead of caching result in package.laded after a one-time global modification, then how to store it and associate it per-env, so we don't re-add the layer every time we require it?
How about caching the results per-input-env table?
Of course if anyone else replaces _G, or passes in multiple _ENV's, then we're gonna re-apply this a few times possibly ...
local state = require 'ext.load'(env)
state has the following:
xforms = table of transforms for the load() function
oldload = old load function
load = new load function that is now also assigned to env.load
oldloadfile = old loadfile function
loadfile = new loadfile function that is now also assigned to env.loadfile
olddofile = old dofile function
dofile = new dofile function that is now also assigned to env.dofile
oldloadstring = (if env.loadstring exists) old loadstring function
loadstring = (if env.loadstring exists) new loadstring function that is now also assigned to env.loadstring
oldsearchfile = old package.searchers[2] or package.loaders[2]
searchfile = new package.searchers[2] or package.loaders[2]
--]]
localstateForEnv= {}
returnfunction(env)
env=envor_G
localstate=stateForEnv[env]
ifstatethenreturnstateend
state= {}
require'ext.xpcall'(env)
require'ext.require'(env)
localpackage=env.packageor_G.package
-- package.searchpath is missing in 5.1 (but not luajit) ... I need a package.searchpath
-- Put in its own file? does anyone else need this? or not since it pairs with my require-override, which is in this file too.
localsearchpath=package.searchpath
ifnotsearchpaththen
functionsearchpath(name, path, sep, rep)
sep=sepor';'
rep=repor'/' -- or \ for windows ... TODO meh?
localnamerep=name:gsub('%.', rep)
localattempted= {}
forwinpath:gmatch('[^'..sep..']*') do-- TODO escape sep? meh?
localfn=w
iffn=='' then-- search default locations ... which are ... builtin ... or not?
else
fn=fn:gsub('%?', namerep)
-- path(fn):exists() implementation:
localexists=io.open(fn,'rb')
ifexiststhen
exists:close()
returnfn
end
table.insert(attempted, "\n\tno file '"..fn.."'")
end
end
returnnil, table.concat(attempted)
end
end
state.xforms=setmetatable({}, {__index=table})
-- TODO proper test? like if load'string' fails?
localloadUsesFunctions= (_VERSION=='Lua 5.1' andnotenv.jit)
state.oldload=loadUsesFunctionsand (env.loadstringor_G.loadstring) or (env.loador_G.load)
-- ok here's my modified load behavior
-- it's going to parse the lua 5.4 code and spit out the luajit code
state.load=function(data, ...)
iftype(data) =='function' then
locals= {}
repeat
-- "A return of an empty string, nil, or no value signals the end of the chunk."
localchunk=data()
ifchunk=='' orchunk==nilthenbreakend
table.insert(s, chunk)
untilfalse
data=table.concat(s)
end
-- 5.1 behavior: load(func, name) versus loadstring(data, name)
-- 5.2..5.4 behavior: load(chunk, name, mode, env)
-- TODO mind you the formatting on re-converting it will be off ...
-- errors won't match up ...
-- so I'll re-insert the generated code
-- TODO would be nice to save whitespace and re-insert that ... hmm maybe long into the future ...
-- TODO xpcall behavior testing for when we are allowed to forward the args ... maybe that compat behavior belongs in ext ?
localsource=...or ('['..data:sub(1,10)..'...]')
fori,xforminipairs(state.xforms) do
localreason
data, reason=xform(data, source)
ifnotdatathen
returnfalse, "ext.load.xform["..i.."]: "..(reasonandtostring(reason) or'')
end
end
returnstate.oldload(data, ...)
end
-- override global load() function, and maybe loadfile() if it's present too
-- (maybe loadstring() too ?)
ifenv.loadstring~=nilor_G.loadstring~=nilthen
state.oldloadstring=env.loadstringor_G.loadstring
state.loadstring=state.load
env.loadstring=state.loadstring
end
-- TODO if we're in luajit (_VERSION=Lua 5.1) then load() will handle strings, but if we're in lua 5.1 then it will only handle functions (according to docs?) right?
env.load=state.load
state.oldloadfile=env.loadfileor_G.loadfile
-- NOTICE when specifying args (filename, mode, env) explicitly, and forwarding them explicitly, the CLI had some trouble with _ENV var in lua 5.4 ...
-- so for vanilla lua cli the number of args matters for some reason
state.loadfile=function(...)
localfilename=...
localdata, err
iffilenamethen
localf
f, err=io.open(filename, 'rb')
ifnotfthenreturnnil, errend
data, err=f:read'*a'
f:close()
else
data, err=io.read'*a'
end
iferrthenreturnnil, errend
-- luajit loadfile/dofile will skip the first # just fine
-- but lua 5.4 will not ... lua 5.4 seems to only skip the leading # if you run it directly
-- so here's some luajit compat ...
ifdatathen
data=data:match'^#[^\n]*\n(.*)$' ordata
end
returnstate.load(data, ...)
end
env.loadfile=state.loadfile
state.olddofile=env.dofileor_G.dofile
state.dofile=function(filename)
returnassert(state.loadfile(filename))()
end
env.dofile=state.dofile
-- next TODO here , same as ext.debug (consider making modular)
-- ... wedge in new package.seachers[2]/package.loaders[2] behavior to use my modified load()
-- replace the package.loaders[2] / package.searchers[2] table entry
-- make it to replace file contents before loading
localsearchers=assert(package.searchersorpackage.loaders, "couldn't find searchers")
state.oldsearchfile=searchers[2]
state.searchfile=function(req, ...)
localfilename, err=searchpath(req, package.path)
ifnotfilenamethenreturnerrend
localf, err=state.loadfile(filename)
returnforerr
end
searchers[2] =state.searchfile
stateForEnv[env] =state
returnstate
end