lua-users home
lua-l archive

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

(Sending this message again with the correct subject header :)

> > I examined the code of lbci and used it to make my own static
> > routine. The requirements for getting all of the line numbers and 
> > matching them to names of functions are non-trivial, but it works!
> Could you share your code if it only uses the lbci api?
> > The only thing I don't like about this is that it's tied to the
> > interface of Lua, ie. it is version-dependent and needs access to
> > complete Lua source in order to build. But things could be worse.
> Well, I can promise to keep lbci updated if there's enough interest.

I can share the code, but it's very task-specific and it needs some
extraction from its environment. It doesn't actually use the lbci API;
it just uses the techniques demonstrated in it.

My goal is to create a mapping of valid lines in a source file to a
structure of meta-information (currently only containing a pointer to a
function name). I can then query this map for the nearest valid line of
source to any arbitrary line supplied by the user by calling

// Header-materials
#include <map>

struct LineMeta
	const char	*functionName;

struct SourceMeta
	typedef std::map<int, LineMeta> LineMap;

	LineMap	lineMapping;

extern SourceMeta GetSourceMeta(lua_State *L, int stack);

// Implementation details

extern "C"
	#include "lua.h"

	#include "ldebug.h"
	#include "lobject.h"
	#include "lopcodes.h"

typedef std::map<int, const char *> FunctionNameMap;

static void RecurseOnPrototype(Proto *p, SourceMeta::LineMap *m,
FunctionNameMap *fnm)
	int		lastLine = 0;

	// Iterate over the opcodes/set of valid lines
	for (int i = 0; i < p->sizelineinfo; i++)
		OpCode	o = GET_OPCODE(p->code[i]);
		int		thisLine = p->lineinfo[i];

		if (o == OP_SETGLOBAL)
			// Store that this line possibly indicates the
start of a function definition
			(*fnm)[thisLine] =

		if (lastLine == thisLine)
			// We've visited this line already in a previous

		// This is a new, valid line of source so create an
entry for it.
		// Check to see if the linedefined field matches up to a
global name we've stored off.
		LineMeta				lm;
		FunctionNameMap::iterator	itr =

		lm.functionName = (itr == fnm->end()) ? NULL :
		m->insert(make_pair(thisLine, lm));
		lastLine = thisLine;	// This is the new most-recently
visited line

	// Process any sub-functions in this definition
	for (int i = 0; i < p->sizep; i++)
		RecurseOnPrototype(p->p[i], m, fnm);

SourceMeta GetSourceMeta(lua_State *L, int stack)
	Proto			*p = ((Closure *)lua_topointer(L,
	FunctionNameMap	fnm;
	SourceMeta		result;

	RecurseOnPrototype(p, &result.lineMapping, &fnm);

	return result;

If you call GetSourceMeta() with your Lua code loaded onto the stack
(eg. by calling luaL_loadbuffer) then it returns the complete mapping of
valid lines to function names.