aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/LuaSL/testLua/ilua.lua
blob: f58505a37537a53d53ce7bfde05ecc9ccfa22f3b (plain)
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
-- ilua.lua
-- A more friendly Lua interactive prompt
-- doesn't need '='
-- will try to print out tables recursively, subject to the pretty_print_limit value.
-- Steve Donovan, 2007
--
local pretty_print_limit = 20
local max_depth = 7
local table_clever = true
local prompt = '> '
local verbose = false
local strict = true
-- suppress strict warnings
_ = true

-- imported global functions
local sub = string.sub
local match = string.match
local find = string.find
local push = table.insert
local pop = table.remove
local append = table.insert
local concat = table.concat
local floor = math.floor
local write = io.write
local read = io.read

local savef
local collisions = {}
local G_LIB = {}
local declared = {}
local line_handler_fn, global_handler_fn
local print_handlers = {}

ilua = {}
local num_prec
local num_all

local jstack = {}

local function oprint(...)
    if savef then
        savef:write(concat({...},' '),'\n')
    end
    print(...)
end

local function join(tbl,delim,limit,depth)
    if not limit then limit = pretty_print_limit end
    if not depth then depth = max_depth end
    local n = #tbl
    local res = ''
    local k = 0
    -- very important to avoid disgracing ourselves with circular referencs...
    if #jstack > depth then
        return "..."
    end
    for i,t in ipairs(jstack) do
        if tbl == t then
            return "<self>"
        end
    end
    push(jstack,tbl)
    -- this is a hack to work out if a table is 'list-like' or 'map-like'
    -- you can switch it off with ilua.table_options {clever = false}
    local is_list
    if table_clever then
        local index1 = n > 0 and tbl[1]
        local index2 = n > 1 and tbl[2]
        is_list = index1 and index2
    end
    if is_list then
        for i,v in ipairs(tbl) do
            res = res..delim..val2str(v)
            k = k + 1
            if k > limit then
                res = res.." ... "
                break
            end
        end
    else
        for key,v in pairs(tbl) do
            if type(key) == 'number' then
                key = '['..tostring(key)..']'
            else
                key = tostring(key)
            end
            res = res..delim..key..'='..val2str(v)
            k = k + 1
            if k > limit then
                res = res.." ... "
                break
            end            
        end
    end
    pop(jstack)
    return sub(res,2)
end


function val2str(val)
    local tp = type(val)
    if print_handlers[tp] then
        local s = print_handlers[tp](val)
        return s or '?'
    end
    if tp == 'function' then
        return tostring(val)
    elseif tp == 'table' then
        if val.__tostring  then
            return tostring(val)
        else
            return '{'..join(val,',')..'}'
        end
    elseif tp == 'string' then
        return "'"..val.."'"
    elseif tp == 'number' then
        -- we try only to apply floating-point precision for numbers deemed to be floating-point,
        -- unless the 3rd arg to precision() is true.
        if num_prec and (num_all or floor(val) ~= val) then
            return num_prec:format(val)
        else
            return tostring(val)
        end
    else
        return tostring(val)
    end
end

function _pretty_print(...)
    for i,val in ipairs(arg) do
        oprint(val2str(val))
    end
    _G['_'] = arg[1]
end

function compile(line)
    if verbose then oprint(line) end
    local f,err = loadstring(line,'local')
    return err,f
end

function evaluate(chunk)
    local ok,res = pcall(chunk)
    if not ok then
        return res
    end
    return nil -- meaning, fine!
end

function eval_lua(line)
    if savef then
        savef:write(prompt,line,'\n')
    end
    -- is the line handler interested?
    if line_handler_fn then
        line = line_handler_fn(line)
        -- returning nil here means that the handler doesn't want
        -- Lua to see the string
        if not line then return end
    end
    -- is it an expression?
    local err,chunk = compile('_pretty_print('..line..')')
    if err then
        -- otherwise, a statement?
        err,chunk = compile(line)
    end
    -- if compiled ok, then evaluate the chunk
    if not err then
        err = evaluate(chunk)
    end
    -- if there was any error, print it out
    if err then
        oprint(err)
    end
end

local function quit(code,msg)
    io.stderr:write(msg,'\n')
    os.exit(code)
end

-- functions available in scripts
function ilua.precision(len,prec,all)
    if not len then num_prec = nil
    else
        num_prec = '%'..len..'.'..prec..'f'
    end
    num_all = all
end	

function ilua.table_options(t)
    if t.limit then pretty_print_limit = t.limit end
    if t.depth then max_depth = t.depth end
    if t.clever ~= nil then table_clever = t.clever end
end

-- inject @tbl into the global namespace
function ilua.import(tbl,dont_complain,lib)
    lib = lib or '<unknown>'
    if type(tbl) == 'table' then
        for k,v in pairs(tbl) do
            local key = rawget(_G,k)
            -- NB to keep track of collisions!
            if key and k ~= '_M' and k ~= '_NAME' and k ~= '_PACKAGE' and k ~= '_VERSION' then
                append(collisions,{k,lib,G_LIB[k]})
            end
            _G[k] = v
            G_LIB[k] = lib
        end
    end
    if not dont_complain and  #collisions > 0  then
        for i, coll in ipairs(collisions) do
            local name,lib,oldlib = coll[1],coll[2],coll[3]
            write('warning: ',lib,'.',name,' overwrites ')
            if oldlib then
                write(oldlib,'.',name,'\n')
            else
                write('global ',name,'\n')
            end
        end
    end
end

function ilua.print_handler(name,handler)
    print_handlers[name] = handler
end

function ilua.line_handler(handler)
    line_handler_fn = handler
end

function ilua.global_handler(handler)
    global_handler_fn = handler
end

function ilua.print_variables()
    for name,v in pairs(declared) do
        print(name,type(_G[name]))
    end
end
--
-- strict.lua
-- checks uses of undeclared global variables
-- All global variables must be 'declared' through a regular assignment
-- (even assigning nil will do) in a main chunk before being used
-- anywhere.
--
local function set_strict()
    local mt = getmetatable(_G)
    if mt == nil then
        mt = {}
        setmetatable(_G, mt)
    end

    local function what ()
        local d = debug.getinfo(3, "S")
        return d and d.what or "C"
    end

    mt.__newindex = function (t, n, v)
        declared[n] = true
        rawset(t, n, v)
    end
      
    mt.__index = function (t, n)
        if not declared[n] and what() ~= "C" then
            local lookup = global_handler_fn and global_handler_fn(n)
            if not lookup then
                error("variable '"..n.."' is not declared", 2)
            else
                return lookup
            end
        end
        return rawget(t, n)
    end

end

--- Initial operations which may not succeed!
-- try to bring in any ilua configuration file; don't complain if this is unsuccessful
pcall(function()    
    require 'ilua-defs'
end)

-- Unix readline support, if readline.so is available...
local rl,readline,saveline
err = pcall(function()
    rl = require 'readline'  
    readline = rl.readline
    saveline = rl.add_history
end)
if not rl then
    readline = function(prompt)
        write(prompt)
        return read()
    end
    saveline = function(s) end
end

-- process command-line parameters
if arg then
    local i = 1
    
    local function parm_value(opt,parm,def)
        local val = parm:sub(3)
        if #val == 0 then
            i = i + 1
            if i > #arg then 
                if not def then
                    quit(-1,"expecting parameter for option '-"..opt.."'")
                else
                    return def
                end
            end
            val = arg[i]
        end
        return val
    end
    
    while i <= #arg do
        local v = arg[i]
        local opt = v:sub(1,1)
        if opt == '-' then
            opt = v:sub(2,2)			
            if opt == 'h' then
                quit(0,"ilua (-l lib) (-L lib) (lua files)")            
            elseif opt == 'l' then
                require (parm_value(opt,v))
            elseif opt == 'L' then
                local lib = parm_value(opt,v)
                local tbl = require (lib)
                -- we cannot always trust require to return the table!
                if type(tbl) ~= 'table' then
                    tbl = _G[lib]
                end
                ilua.import(tbl,true,lib)
            elseif opt == 't' or opt == 'T' then
                local file
                if opt == 'T' then
                    file = 'ilua_'..os.date ('%y_%m_%d_%H_%M')..'.log'
                else
                    file = parm_value(opt,v,"ilua.log")
                end
                print('saving transcript "'..file..'"')
                savef = io.open(file,'w')
                savef:write('! ilua ',concat(arg,' '),'\n')
            elseif opt == 's' then
                strict = false
            elseif opt == 'v' then
                verbose = true
            end
        else -- a plain file to be executed immediately
            dofile(v)
        end
        i = i + 1
    end
end
    
print 'ILUA: Lua 5.1.2  Copyright (C) 1994-2007 Lua.org, PUC-Rio\n"quit" to end'

-- any import complaints?
ilua.import()

-- enable 'not declared' error
if strict then 
    set_strict()
end

local line = readline(prompt)
while line do    
    if line == 'quit' then break end
    eval_lua(line)
    saveline(line)
    line = readline(prompt)
end

if savef then
    savef:close()
end