The check to see if an item was already on the heap was randomly hitting.
[jitcs.git] / tools / emblua.lua
blobf3dd25fa3999642f005c95c99897f6edccfdc89f
1 ----------------------------------------------------
2 local _setfenv, _ipairs, _pairs, _select, _tostr = setfenv, ipairs, pairs, select, tostring
3 local _loadstr, _pcall, _type = loadstring, pcall, type
4 local _open, _write, _err, _rerouteoutput = io.open, io.write, io.stderr, io.output
5 local _flush, _filelines = io.flush, io.lines
6 local _match, _gmatch, _fmt, _upper = string.match, string.gmatch, string.format, string.upper
7 local _gsub, _sub, _byte = string.gsub, string.sub, string.byte
8 local _exec, _getenv = os.execute, os.getenv
9 local _cat = table.concat
11 local _filesep = _match(_getenv("OS"),"Windows") and "\\" or "/"
13 local function _existfile(n)
14 local f = _open(n)
15 if not f then return false end
16 f:close()
17 return true
18 end
20 local function _readfile(n)
21 local f = _open(n)
22 local ctnt = f:read("*a")
23 f:close()
24 return ctnt
25 end
26 local function _writefile(n, c)
27 local f = _open(n, "w")
28 f:write(c)
29 f:close()
30 end
32 local function _strlines(self)
33 local me, ix = self[1], self[2]
34 local n = #me
35 if ix > n then return nil end
36 local ix2 = ix
37 local c = _byte(me, ix2)
38 while c ~= 13 and c ~= 10 and ix2 <= n do
39 ix2 = ix2 + 1
40 c = _byte(me, ix2)
41 end
42 local ix3 = ix2
43 while ix3 <= n and _byte(me, ix3) == 13 do ix3 = ix3 + 1 end
44 if ix3 <= n and _byte(me, ix3) == 10 then ix3 = ix3 + 1 end
45 self[2] = ix3
46 return _sub(me, ix, ix2 - 1)
47 end
48 local function strlines(str) return _strlines,{str,1} end
50 local function stream_valid_input(s)
51 if type(s) == "string" then return _existfile(s) end
52 if type(s) == "table" and s.type == "file" then return _existfile(s.value) end
53 if type(s) == "table" and s.type == "string" then return true end
54 return false
55 end
56 local function _stream_filename(s)
57 if type(s) == "string" then return s or "" end
58 if type(s) == "table" and s.type == "file" then return s.value or "" end
59 if type(s) == "table" and s.type == "string" then return s.file or "" end
60 return ""
61 end
63 local function stream_lines(s)
64 if type(s) == "string" then return _filelines(s) end
65 if type(s) == "table" and s.type == "file" then return _filelines(s.value) end
66 if type(s) == "table" and s.type == "string" then return strlines(s.value) end
67 return nil, nil
68 end
69 local function _nil_output_stream()
70 return {
71 close = function(self) end,
72 write = function(self, c) end,
74 end
75 local function _file_output_stream(s)
76 return {
77 _f = _open(s, "w"),
78 close = function(self) self._f:close() end,
79 write = function(self, c) self._f:write(c) end,
81 end
82 local function _string_output_stream(t)
83 return {
84 _ref = t,
85 _t = {},
86 _tt = {},
87 _flush = function(self)
88 if #self._tt == 0 then return end
89 local t = self._t;
90 t[#t + 1] = _cat(self._tt, "")
91 self._tt = {}
92 end,
93 close = function(self) self:_flush(); self._ref.value = _cat(self._t, "") end,
94 write = function(self, c)
95 local tt = self._tt;
96 tt[#tt + 1] = c;
97 if #self._tt >= 32 then self:_flush() end
98 end,
101 local function stream_output(s)
102 if type(s) == "string" then return _file_output_stream(s) end
103 if type(s) == "table" and s.type == "file" then return _file_output_stream(s.value) end
104 if type(s) == "table" and s.type == "string" then return _string_output_stream(s) end
107 local myprint,myprintf= print,printf
108 local print_outstream = nil
109 function _printwrite(s)
110 if print_outstream then
111 print_outstream:write(s)
112 return
114 _write(s)
116 function print( ... )
117 local n= _select( "#",... )
118 for i=1,n do
119 _printwrite( _tostr(_select(i,...)) )
120 if i<n then _printwrite( "\t" ) end
122 _printwrite( "\n" )
124 function printf( ... )
125 --print( ... )
126 _printwrite( _fmt( ... ) )
127 _printwrite( "\n" )
130 function readfile( s )
131 return _readfile(FILEDIR.._gsub(s, "[\\/]", _filesep))
133 function runfile( s,... )
134 local d= readfile( s )
135 local code= _loadstr( d,s )
136 return code(...)
139 local function run(script, srcfile, params)
140 local fun,msg= _loadstr(script)
141 local doneok
142 if not fun then
143 _err:write( msg,"\n" )
144 else
145 doneok,msg= _pcall( fun, srcfile, params )
146 if not doneok then
147 _err:write( msg,"\n" )
148 else
149 return true
152 return false
155 local function varprefix(vardelim)
156 return _gsub(vardelim,".","%%%0")
158 local function varpattern(vardelim)
159 return varprefix(vardelim).."(%b())"
161 local function preidpattern()
162 return "([%w_]+)"
164 local function idpattern()
165 return "([%a_][%w_]*)"
167 local function varpattern2(vardelim)
168 return varprefix(vardelim)..idpattern()
171 local function getidents(s,vardelim)
172 local result={}
173 local nonempty= false
174 local ignore = {["not"]=true,["or"]=true,["and"]=true,["false"]=true,["true"]=true,["nil"]=true}
175 for id in _gmatch(s, varpattern2(vardelim)) do
176 if not ignore[id] then
177 result[id]= true
178 nonempty = true
181 for b in _gmatch(s, varpattern(vardelim)) do
182 local bb= _sub(b, 2,-2)
183 for id in _gmatch(bb, preidpattern()) do
184 if _match(id, "^"..idpattern().."$") and not ignore[id] then
185 result[id]= true
186 nonempty = true
190 return nonempty and result
192 local function identsparam(idents)
193 local result= ""
194 for k,v in _pairs(idents) do
195 result= result..k.."="..k..","
197 return "{"..result.."}"
199 local function generateXYZPrint(vardelim)
200 return _fmt( [[
201 local _gsub, _sub, _loadstr, _setfenv, _tostr, _err = string.gsub, string.sub
202 local _loadstr, _setfenv, _tostr, _err = loadstring, setfenv, tostring, io.stderr
203 function _xyz_print( line,vars )
204 line= _gsub(line,"%s",vars)
205 line= _gsub(line,"(%s)",
206 function(pattern,x)
207 local fx,gx= _loadstr("return ".._sub(x,2,-2))
208 if not fx then
209 _err:write( "error in pattern "..pattern.." : "..gx.."\n" )
211 _setfenv(fx,vars)
212 local xnew= fx()
213 return _tostr(xnew)
214 end)
215 print( line )
217 ]],varpattern2(vardelim),varpattern(vardelim))
220 local function main(SELF, IN, OUT, SEP, PARAMS)
221 if _type(IN) == "string" then IN = {type = "file", value = IN} end
222 if _type(OUT) == "string" then OUT = {type = "file", value = OUT} end
223 if not stream_valid_input(IN) then
224 printf( [[
225 usage: %s IN [OUT=IN.out] [SEP=|] [PARAMS=]
226 convert lua interface file IN into C source code file OUT
227 lua script lines start with separator SEP, defaults to |
228 PARAMS may denote a file containing further data
229 ]],SELF )
230 return
232 FILEPOS= _stream_filename(IN)
233 if not (_type(OUT) == "table" and OUT.type == "string") then
234 local OUTN = _stream_filename(OUT)
235 if OUTN == "" or _sub(OUTN, 1, 1) == "." then
236 if FILEPOS == "" then
237 OUT = {type = "string"}
238 else
239 if OUTN == "" then OUTN = ".out" end
240 OUT = {type = "file", value = _match(FILEPOS, "^(.-)%.[^.\\/]*$") .. OUTN}
244 assert(FILEPOS == "" or FILEPOS ~= _stream_filename(OUT))
245 local prefix= SEP or "|"
246 FILEDIR= ""
247 if _match(FILEPOS, "[/\\]" ) then
248 FILEDIR= _match(FILEPOS, [[^(.-[/\])[^/\]*$]] )
251 local prefixlist = {}
252 for line in stream_lines(IN) do
253 local handled= false
254 local x= _match(line, "^#/.-/emblua(.-)$")
255 if (x) then
256 --title line with settings
257 for var,val in _gmatch(x, idpattern().."=(%S+)") do
258 if _upper(var) == "LUAPREFIX" then
259 prefixlist[#prefixlist + 1] = val
260 else
261 _err:write( "unknown setup variable "..var.." in line 1" )
264 handled= true
266 break
268 if #prefixlist == 0 then prefixlist = {prefix} end
270 local inputfile = IN
272 for k,prefix in _ipairs(prefixlist) do
273 printf("running pass %d of %d, prefix %s",k,#prefixlist,prefix)
274 local paramsfile = PARAMS
275 outputfile = #prefixlist == k and OUT or {type="string"}
276 local first= true
277 local vardelim= "$"
278 local comment= "//"
279 local currentscript= ""
280 local needvarreplfun= false
281 local printing = false
283 for line in stream_lines(inputfile) do
284 local handled= false
285 if first then
286 local x= _match(line, "^#/.-/emblua(.-)$")
287 if (x) then
288 handled= true
290 first= false
292 if not handled and not printing then
293 local pfx, var, val= _match(line, "^%s*(%S+)%s*%-%-%s*"..idpattern().."%s*=%s*(%S+)%s*$" )
294 if pfx and pfx == prefix then
295 if _upper(var) == "VARDELIM" then
296 vardelim= val
297 elseif _upper(var)=="CMTDELIM" then
298 comment= val
299 elseif _upper(var)=="DUMPSCRIPT" then
300 dumpscript=true
302 handled = true
306 local firstword, remainder= _match(line, "^%s*(%S+)(.*)$")
307 if not handled and firstword==prefix then
308 -- scriptline
309 currentscript= currentscript..remainder.."\n"
310 handled= true
311 printing = true
313 if not handled then
314 local idents= getidents(line,vardelim)
315 local quoteline = _fmt("%q",line)
316 local newline
317 if idents then
318 needvarreplfun= true
319 local parms= identsparam(idents)
320 newline= "_xyz_print("..quoteline..","..parms..")"
321 else
322 newline= "print("..quoteline..")"
324 currentscript= currentscript..newline.."\n"
325 printing = true
328 if needvarreplfun then
329 currentscript= generateXYZPrint(vardelim).."local SRCFILE,PARAMS=...;\n"..currentscript
331 --print( "RUN" )
333 local params = {}
334 if paramsfile and paramsfile ~= "" then
335 local paramsfile = readfile(paramsfile)
336 if paramsfile then
337 local paramsdatafnc = _loadstr("return "..paramsfile)
338 if paramsdatafnc then
339 local paramsdata = paramsdatafnc()
340 if _type(paramsdata) == "table" then
341 params = paramsdata
347 if dumpscript and _stream_filename(outputfile) ~= "" then
348 _writefile(_stream_filename(outputfile)..".script",currentscript )
351 print_outstream = stream_output(outputfile)
352 if k == #prefixlist then
353 if _stream_filename(IN) ~= "" then
354 printf(comment.." DO NOT EDIT. this file was autogenerated from %s",_stream_filename(IN))
355 else
356 print(comment.." DO NOT EDIT. this file was autogenerated")
359 --print( currentscript )
360 run(currentscript, paramsfile, params)
361 --print( "DONE" )
362 print_outstream:close()
363 print_outstream = nil
364 inputfile = outputfile
366 return OUT.value
369 return main(arg[0], ...)