lua-users home
lua-l archive

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


There would be advantages if lua_Debug included the starting character
position of a function rather than (or in addition to) line numbers.

The problem I have is a source code browser that given a function
value `f` needs to obtain its signature string `sig`.  `f` is
typically obtained by something like `f = require 'foo'.bar`.  I can
obtain its line number and source code via the 'linedefined',
'source', and 'what' fields of `debug.getinfo(f)`.  This allows a
signature to be parsed, but it can do so uniquely only if a single
function exists on the line, which is typical but not certain.  An
exact character position is more than sufficient actually: simply a
token number or a number `n` indicating that the function is the n-th
function on the line or file would be sufficient given an external
lexer/parser.  Now, I might perhaps infer n by bytecode analysis
(looking up a function's Proto and finding all functions on that line
and sorting them), but that is getting much more complicated than
necessary and breaks under alternative bytecodes like LuaJIT2.

So, it would be ideal to have the starting character position
(positiondefined) in which a function is defined.  linedefined, as
well as a column number, may be derived from positiondefined.
lastlinedefined and lastpositiondefined may also be derived by
reparsing the source.  The full text of a function, as some have
requested [1], may then be derived from positiondefined and
lastpositiondefined.  Comments surrounding the function and other
details may also be derived.  This might not take up that much extra
space [3], and it might only be needed for function definitions.

I realize that in 5.2-work4, debug.getlocal and the 'nparams' and
'isvararg' fields of debug.getinfo results can be used to obtain
parameter names [2], and this can be used to build much of a
function's signature.  However, it doesn't contain return values,
which I would be able to obtain via a custom code analysis given an
exact position (e.g. `function f(a, ...) local x = a .. a; return x
end` has signature 'x = f(a, ...)', and a lot of times signatures are
more complicated like 'info = debug.getinfo ([thread,] function [,
what])'.  It also doesn't allow some of the other possibilities
mentioned above like obtaining function source and comments.  In
short, a character position seems the simplest to implement and most
general in flexibility.

I was also thinking that perhaps debug.getinfo should also be able to
obtain source position info for tables rather than just functions, so
that given a module table `t`, you can obtain the location where it is
defined.  OTOH, if you use some helper function like `function
createmodule() return {} end` to create all your module tables, then
this information won' t be distinctive.  The same problem would also
affect functions created with the decorator pattern [4], though
decorator functions seem less common than utility function that create
tables.  If you want to determine where t is defined, you can just
debug.getinfo a function inside t or trace t back to its require
(which is easy when using the `local t = require "foo"` style import).

On a tangential point, there's this curious "activelines" field in the
debug info.  There's only two threads in the archives on this related
to partial success using it for code coverage analysis.  As a test,

  function
  f()
  print(1)
  --
  print(2,
  3,

  4
  )
  end
  local info = debug.getinfo(f, 'L')
  table.foreach(info.activelines, print)

outputs

  6       true
  3       true
  10      true
  9       true
  5       true

which is a little odd looking but apparently corresponds with
byte-codes.  So, it would be byte-code dependent (which possibly
should be noted in the manual).  There was a suggestion it is useful
for setting breakpoints via the hook mechanism.

Finally, there probably are uses for allowing C functions to inject
debugging information.  Currently,

  debug.getinfo(math.sqrt).nparams  --> returns 0 not 1
  debug.getinfo(math.sqrt).linedefined --> returns -1
  debug.getinfo(math.sqrt).source --> returns "=[C]" but could include
the C __FILE__ macro

though a module can always store more general metadata on function in
weak table like in the decorator pattern [4], although there would be
a lack of consistency in that between modules and through Lua.

[1] http://lua-users.org/lists/lua-l/2008-09/msg00358.html
[2] http://www.lua.org/work/doc/manual.html#pdf-debug.getlocal
[3] http://lua-users.org/lists/lua-l/2009-11/msg00368.html
[4] http://lua-users.org/wiki/DecoratorsAndDocstrings