lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Matthew Wilson wrote:
I am learning lua after using python for the last few years.

In the lua toplevel, why do I either have to either put a "=" in front
of a variable
You might be interested in this. It is a little side project of mine that makes lua work nicer in "calculator mode". It does away with the need to type "=" in front of expressions, provides nicer output for tables, enables you to "save" and "load" calculator sessions, and some other stuff.

Just save the code in a lua file (e.g., calc.lua) and start it with "lua calc.lua"...

---

function string:rep(n)
   local out = ""
   for i=1,n do out = out .. self end
   return out
end

function string:left(n)
   return self .. (" "):rep(n - self:len())
end

local function sort(t)
   local sorted = {}
   for k,v in pairs(t) do sorted[#sorted+1] = k end
   table.sort(sorted)
   local index = 0
   return function ()
       index = index + 1
       local k = sorted[index]
       return k, t[k]
   end
end

local function line_representation(x,seen)
   if type(x) == "table" then
       if not seen then seen = {} end
       if seen[x] then return "..." end
       seen[x] = true
       local r = "{"
       for k,v in sort(x) do
r = r .. line_representation(k,seen) .. '=' .. line_representation(v,seen) .. ', '
           if r:len() > 40 then
               r = r:sub(1,40)
               r = r .. '...'
               break
           end
       end
       r = r .. '}'
       return r
   elseif type(x) == "string" then
       x = string.gsub(x, '\n', '\\n')
       x = string.gsub(x, '\r', '\\r')
       x = string.gsub(x, '\t', '\\t')
       if x:len() > 40 then
           x = x:sub(1,40) .. '...'
       end
       return x
   elseif type(x) == "function" then
       local info = debug.getinfo(x)
       if info.source:sub(1,1) == '@' then
           local file = info.source:sub(2)
           local f = io.open(file)
           for i=1,info.linedefined-1 do f:read() end
           local x = f:read() .. f:read() .. f:read()
           return line_representation(x)
       else
           return line_representation(info.source)
       end
   else
       return tostring(x)
   end
end

local function ascii_table(t)
   local out = ''
   local klen = 20
   local vlen = 20
   for k,v in pairs(t) do
       local kl = line_representation(k):len() + 2
       local vl = line_representation(v):len() + 2
       if kl > klen then klen = kl end
       if vl > vlen then vlen = vl end
   end
   out = out .. ("-"):rep(klen+vlen+5) .. "\n"
   for k,v in pairs(t) do
       out = out .. "| " .. line_representation(k):left(klen) .. "| " ..
           line_representation(v):left(vlen) .."|\n"
   end
   out = out .. ("-"):rep(klen+vlen+5) .. "\n"
   return out
end

local function full_representation(x, seen)
   if type(x) == "function" then
       local info = debug.getinfo(x)
       if info.source:sub(1,1) == '@' then
           local file = info.source:sub(2)
           local f = io.open(file)
           for i=1,info.linedefined-1 do f:read() end
           local nest = 0
           local out = ""
           while true do
               local r = f:read()
               if not r then return out end
               out = out .. r .. "\n"
               for w in r:gmatch("%a*") do
if w == "do" or w == "if" or w == "repeat" or w == "function" then
                       nest = nest + 1
                   elseif w == "end" then
                       nest = nest - 1
                   end
               end
               if nest == 0 then break end
           end
           return out
       else
           return info.source
       end
   elseif type(x) == "table" then
       return ascii_table(x)
   else
       return tostring(x)
   end
end

SESSION = {}

function save(file)
   local f = io.open(file, 'w')
   for _,line in ipairs(SESSION) do
       f:write(line)
       f:write("\n")
   end
   f:close()
   error "Saved."
end

function load(file)
   local f = io.open(file, 'r')
   while true do
       local line = f:read()
       if not line then break end
       loadstring(line)()
       SESSION[#SESSION + 1] = line
   end
   f:close()
   error "Loaded."
end

function world()
   local prepend
   while true do
       local line
       if prepend then
           io.write ">> "
           line = prepend .. '\n' .. io.read()
           prepend = nil
       else
           io.write "$ "
           line = io.read()
       end
       local src = "_ = " .. line
       local assign = "_"
       local f,e = loadstring(src)
       if not f then
           src = line
           assign = nil
           f,e = loadstring(src)
       end
       if f then
           local ok,res = pcall(f)
           if ok then
               SESSION[#SESSION + 1] = src
           end
if not ok then
               print(res)
           elseif assign then
               print( full_representation(_G[assign]) )
           end
       elseif e:match("near '<eof>'") then
           prepend = line
       else
           print(e)
       end
   end
end

world()