diff options
Diffstat (limited to '')
-rw-r--r-- | LuaSL/testLua/lua.lua | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/LuaSL/testLua/lua.lua b/LuaSL/testLua/lua.lua new file mode 100644 index 0000000..40d0eb8 --- /dev/null +++ b/LuaSL/testLua/lua.lua | |||
@@ -0,0 +1,357 @@ | |||
1 | -- lua.lua - Lua 5.1 interpreter (lua.c) reimplemented in Lua. | ||
2 | -- | ||
3 | -- WARNING: This is not completed but was quickly done just an experiment. | ||
4 | -- Fix omissions/bugs and test if you want to use this in production. | ||
5 | -- Particularly pay attention to error handling. | ||
6 | -- | ||
7 | -- (c) David Manura, 2008-08 | ||
8 | -- Licensed under the same terms as Lua itself. | ||
9 | -- Based on lua.c from Lua 5.1.3. | ||
10 | -- Improvements by Shmuel Zeigerman. | ||
11 | |||
12 | -- Variables analogous to those in luaconf.h | ||
13 | local LUA_INIT = "LUA_INIT" | ||
14 | local LUA_PROGNAME = "lua" | ||
15 | local LUA_PROMPT = "> " | ||
16 | local LUA_PROMPT2 = ">> " | ||
17 | local function LUA_QL(x) return "'" .. x .. "'" end | ||
18 | |||
19 | -- Variables analogous to those in lua.h | ||
20 | local LUA_RELEASE = "Lua 5.1.3" | ||
21 | local LUA_COPYRIGHT = "Copyright (C) 1994-2008 Lua.org, PUC-Rio" | ||
22 | |||
23 | |||
24 | -- Note: don't allow user scripts to change implementation. | ||
25 | -- Check for globals with "cat lua.lua | luac -p -l - | grep ETGLOBAL" | ||
26 | local _G = _G | ||
27 | local assert = assert | ||
28 | local collectgarbage = collectgarbage | ||
29 | local loadfile = loadfile | ||
30 | local loadstring = loadstring | ||
31 | local pcall = pcall | ||
32 | local rawget = rawget | ||
33 | local select = select | ||
34 | local tostring = tostring | ||
35 | local type = type | ||
36 | local unpack = unpack | ||
37 | local xpcall = xpcall | ||
38 | local io_stderr = io.stderr | ||
39 | local io_stdout = io.stdout | ||
40 | local io_stdin = io.stdin | ||
41 | local string_format = string.format | ||
42 | local string_sub = string.sub | ||
43 | local os_getenv = os.getenv | ||
44 | local os_exit = os.exit | ||
45 | |||
46 | |||
47 | local progname = LUA_PROGNAME | ||
48 | |||
49 | -- Use external functions, if available | ||
50 | local lua_stdin_is_tty = function() return true end | ||
51 | local setsignal = function() end | ||
52 | |||
53 | local function print_usage() | ||
54 | io_stderr:write(string_format( | ||
55 | "usage: %s [options] [script [args]].\n" .. | ||
56 | "Available options are:\n" .. | ||
57 | " -e stat execute string " .. LUA_QL("stat") .. "\n" .. | ||
58 | " -l name require library " .. LUA_QL("name") .. "\n" .. | ||
59 | " -i enter interactive mode after executing " .. | ||
60 | LUA_QL("script") .. "\n" .. | ||
61 | " -v show version information\n" .. | ||
62 | " -- stop handling options\n" .. | ||
63 | " - execute stdin and stop handling options\n" | ||
64 | , | ||
65 | progname)) | ||
66 | io_stderr:flush() | ||
67 | end | ||
68 | |||
69 | local function l_message (pname, msg) | ||
70 | if pname then io_stderr:write(string_format("%s: ", pname)) end | ||
71 | io_stderr:write(string_format("%s\n", msg)) | ||
72 | io_stderr:flush() | ||
73 | end | ||
74 | |||
75 | local function report(status, msg) | ||
76 | if not status and msg ~= nil then | ||
77 | msg = (type(msg) == 'string' or type(msg) == 'number') and tostring(msg) | ||
78 | or "(error object is not a string)" | ||
79 | l_message(progname, msg); | ||
80 | end | ||
81 | return status | ||
82 | end | ||
83 | |||
84 | local function tuple(...) | ||
85 | return {n=select('#', ...), ...} | ||
86 | end | ||
87 | |||
88 | local function traceback (message) | ||
89 | local tp = type(message) | ||
90 | if tp ~= "string" and tp ~= "number" then return message end | ||
91 | local debug = _G.debug | ||
92 | if type(debug) ~= "table" then return message end | ||
93 | local tb = debug.traceback | ||
94 | if type(tb) ~= "function" then return message end | ||
95 | return tb(message, 2) | ||
96 | end | ||
97 | |||
98 | local function docall(f, ...) | ||
99 | local tp = {...} -- no need in tuple (string arguments only) | ||
100 | local F = function() return f(unpack(tp)) end | ||
101 | setsignal(true) | ||
102 | local result = tuple(xpcall(F, traceback)) | ||
103 | setsignal(false) | ||
104 | -- force a complete garbage collection in case of errors | ||
105 | if not result[1] then collectgarbage("collect") end | ||
106 | return unpack(result, 1, result.n) | ||
107 | end | ||
108 | |||
109 | local function dofile(name) | ||
110 | local f, msg = loadfile(name) | ||
111 | if f then f, msg = docall(f) end | ||
112 | return report(f, msg) | ||
113 | end | ||
114 | |||
115 | local function dostring(s, name) | ||
116 | local f, msg = loadstring(s, name) | ||
117 | if f then f, msg = docall(f) end | ||
118 | return report(f, msg) | ||
119 | end | ||
120 | |||
121 | local function dolibrary (name) | ||
122 | return report(docall(_G.require, name)) | ||
123 | end | ||
124 | |||
125 | local function print_version() | ||
126 | l_message(nil, LUA_RELEASE .. " " .. LUA_COPYRIGHT) | ||
127 | end | ||
128 | |||
129 | local function getargs (argv, n) | ||
130 | local arg = {} | ||
131 | for i=1,#argv do arg[i - n] = argv[i] end | ||
132 | if _G.arg then | ||
133 | local i = 0 | ||
134 | while _G.arg[i] do | ||
135 | arg[i - n] = _G.arg[i] | ||
136 | i = i - 1 | ||
137 | end | ||
138 | end | ||
139 | return arg | ||
140 | end | ||
141 | |||
142 | --FIX? readline support | ||
143 | local history = {} | ||
144 | local function saveline(s) | ||
145 | -- if #s > 0 then | ||
146 | -- history[#history+1] = s | ||
147 | -- end | ||
148 | end | ||
149 | |||
150 | |||
151 | local function get_prompt (firstline) | ||
152 | -- use rawget to play fine with require 'strict' | ||
153 | local pmt = rawget(_G, firstline and "_PROMPT" or "_PROMPT2") | ||
154 | local tp = type(pmt) | ||
155 | if tp == "string" or tp == "number" then | ||
156 | return tostring(pmt) | ||
157 | end | ||
158 | return firstline and LUA_PROMPT or LUA_PROMPT2 | ||
159 | end | ||
160 | |||
161 | |||
162 | local function incomplete (msg) | ||
163 | if msg then | ||
164 | local ender = LUA_QL("<eof>") | ||
165 | if string_sub(msg, -#ender) == ender then | ||
166 | return true | ||
167 | end | ||
168 | end | ||
169 | return false | ||
170 | end | ||
171 | |||
172 | |||
173 | local function pushline (firstline) | ||
174 | local prmt = get_prompt(firstline) | ||
175 | io_stdout:write(prmt) | ||
176 | io_stdout:flush() | ||
177 | local b = io_stdin:read'*l' | ||
178 | if not b then return end -- no input | ||
179 | if firstline and string_sub(b, 1, 1) == '=' then | ||
180 | return "return " .. string_sub(b, 2) -- change '=' to `return' | ||
181 | else | ||
182 | return b | ||
183 | end | ||
184 | end | ||
185 | |||
186 | |||
187 | local function loadline () | ||
188 | local b = pushline(true) | ||
189 | if not b then return -1 end -- no input | ||
190 | local f, msg | ||
191 | while true do -- repeat until gets a complete line | ||
192 | f, msg = loadstring(b, "=stdin") | ||
193 | if not incomplete(msg) then break end -- cannot try to add lines? | ||
194 | local b2 = pushline(false) | ||
195 | if not b2 then -- no more input? | ||
196 | return -1 | ||
197 | end | ||
198 | b = b .. "\n" .. b2 -- join them | ||
199 | end | ||
200 | |||
201 | saveline(b) | ||
202 | |||
203 | return f, msg | ||
204 | end | ||
205 | |||
206 | |||
207 | local function dotty () | ||
208 | local oldprogname = progname | ||
209 | progname = nil | ||
210 | while true do | ||
211 | local result | ||
212 | local status, msg = loadline() | ||
213 | if status == -1 then break end | ||
214 | if status then | ||
215 | result = tuple(docall(status)) | ||
216 | status, msg = result[1], result[2] | ||
217 | end | ||
218 | report(status, msg) | ||
219 | if status and result.n > 1 then -- any result to print? | ||
220 | status, msg = pcall(_G.print, unpack(result, 2, result.n)) | ||
221 | if not status then | ||
222 | l_message(progname, string_format( | ||
223 | "error calling %s (%s)", | ||
224 | LUA_QL("print"), msg)) | ||
225 | end | ||
226 | end | ||
227 | end | ||
228 | io_stdout:write"\n" | ||
229 | io_stdout:flush() | ||
230 | progname = oldprogname | ||
231 | end | ||
232 | |||
233 | |||
234 | local function handle_script(argv, n) | ||
235 | _G.arg = getargs(argv, n) -- collect arguments | ||
236 | local fname = argv[n] | ||
237 | if fname == "-" and argv[n-1] ~= "--" then | ||
238 | fname = nil -- stdin | ||
239 | end | ||
240 | local status, msg = loadfile(fname) | ||
241 | if status then | ||
242 | status, msg = docall(status, unpack(_G.arg)) | ||
243 | end | ||
244 | return report(status, msg) | ||
245 | end | ||
246 | |||
247 | |||
248 | local function collectargs (argv, p) | ||
249 | local i = 1 | ||
250 | while i <= #argv do | ||
251 | if string_sub(argv[i], 1, 1) ~= '-' then -- not an option? | ||
252 | return i | ||
253 | end | ||
254 | local prefix = string_sub(argv[i], 1, 2) | ||
255 | if prefix == '--' then | ||
256 | if #argv[i] > 2 then return -1 end | ||
257 | return argv[i+1] and i+1 or 0 | ||
258 | elseif prefix == '-' then | ||
259 | return i | ||
260 | elseif prefix == '-i' then | ||
261 | if #argv[i] > 2 then return -1 end | ||
262 | p.i = true | ||
263 | p.v = true | ||
264 | elseif prefix == '-v' then | ||
265 | if #argv[i] > 2 then return -1 end | ||
266 | p.v = true | ||
267 | elseif prefix == '-e' then | ||
268 | p.e = true | ||
269 | if #argv[i] == 2 then | ||
270 | i = i + 1 | ||
271 | if argv[i] == nil then return -1 end | ||
272 | end | ||
273 | elseif prefix == '-l' then | ||
274 | if #argv[i] == 2 then | ||
275 | i = i + 1 | ||
276 | if argv[i] == nil then return -1 end | ||
277 | end | ||
278 | else | ||
279 | return -1 -- invalid option | ||
280 | end | ||
281 | i = i + 1 | ||
282 | end | ||
283 | return 0 | ||
284 | end | ||
285 | |||
286 | |||
287 | local function runargs(argv, n) | ||
288 | local i = 1 | ||
289 | while i <= n do if argv[i] then | ||
290 | assert(string_sub(argv[i], 1, 1) == '-') | ||
291 | local c = string_sub(argv[i], 2, 2) -- option | ||
292 | if c == 'e' then | ||
293 | local chunk = string_sub(argv[i], 3) | ||
294 | if chunk == '' then i = i + 1; chunk = argv[i] end | ||
295 | assert(chunk) | ||
296 | if not dostring(chunk, "=(command line)") then return false end | ||
297 | elseif c == 'l' then | ||
298 | local filename = string_sub(argv[i], 3) | ||
299 | if filename == '' then i = i + 1; filename = argv[i] end | ||
300 | assert(filename) | ||
301 | if not dolibrary(filename) then return false end | ||
302 | end | ||
303 | i = i + 1 | ||
304 | end end | ||
305 | return true | ||
306 | end | ||
307 | |||
308 | |||
309 | local function handle_luainit() | ||
310 | local init = os_getenv(LUA_INIT) | ||
311 | if init == nil then | ||
312 | return -- status OK | ||
313 | elseif string_sub(init, 1, 1) == '@' then | ||
314 | dofile(string_sub(init, 2)) | ||
315 | else | ||
316 | dostring(init, "=" .. LUA_INIT) | ||
317 | end | ||
318 | end | ||
319 | |||
320 | |||
321 | local import = _G.import | ||
322 | if import then | ||
323 | lua_stdin_is_tty = import.lua_stdin_is_tty or lua_stdin_is_tty | ||
324 | setsignal = import.setsignal or setsignal | ||
325 | LUA_RELEASE = import.LUA_RELEASE or LUA_RELEASE | ||
326 | LUA_COPYRIGHT = import.LUA_COPYRIGHT or LUA_COPYRIGHT | ||
327 | _G.import = nil | ||
328 | end | ||
329 | |||
330 | if _G.arg and _G.arg[0] and #_G.arg[0] > 0 then progname = _G.arg[0] end | ||
331 | local argv = {...} | ||
332 | handle_luainit() | ||
333 | local has = {i=false, v=false, e=false} | ||
334 | local script = collectargs(argv, has) | ||
335 | if script < 0 then -- invalid args? | ||
336 | print_usage() | ||
337 | os_exit(1) | ||
338 | end | ||
339 | if has.v then print_version() end | ||
340 | local status = runargs(argv, (script > 0) and script-1 or #argv) | ||
341 | if not status then os_exit(1) end | ||
342 | if script ~= 0 then | ||
343 | status = handle_script(argv, script) | ||
344 | if not status then os_exit(1) end | ||
345 | else | ||
346 | _G.arg = nil | ||
347 | end | ||
348 | if has.i then | ||
349 | dotty() | ||
350 | elseif script == 0 and not has.e and not has.v then | ||
351 | if lua_stdin_is_tty() then | ||
352 | print_version() | ||
353 | dotty() | ||
354 | else dofile(nil) -- executes stdin as a file | ||
355 | end | ||
356 | end | ||
357 | |||