A failed programming experiment

I have a Lua [1] module that embeds a C compiler [2] (and there's an extension module that allows you to load a Lua module straight from C code [3]) which allows you to embed C code inside Lua code and compile it directly into memory:

>
```
cc = require "org.conman.cc"
load = cc.compile('load',[[
#include <lua.h>
int load(lua_State *L)
{
double load[3];
getloadavg(laod,3);
lua_pushnumber(L,load[0]);
lua_pushnumber(L,load[1]);
lua_pushnumber(L,load[2]);
return 3;
}
]])
print(load())
```

I use it as a means to quickly test Lua functions in C without having to muck about with external files, C compilers and linkers. For that, it's wonderful except …

Errors. If there's an error in the C portion, I get:

>
```
[spc]lucy:/tmp>lua load.lua
tcc: <string>:7: error: 'laod' undeclared
```

Yeah, the line number is correct as far as it goes—it's in line 7 of the code, but the actual line number is 10 of the file. Okay, in this case, I can do a simple search on “laod” but for instance, this error:

>
```
[spc]lucy:/tmp>lua load.lua
tcc: <string>:10: error: ';' expected (got "lua_pushnumber")
```

It's actually line 12 of the file.

A recent message [4] to the Lua mailing list [5] reminded me that it is, indeed, possible, to get what I want from the output:

>
```
[spc]lucy:/tmp>lua load.lua
tcc: load.lua:12: error: ';' expected (got "lua_pushnumber")
```

and that's by using the #line C preprocessor directive. It's a relatively straightforward matter to add such a line in Lua—just generate a proper #line directive and concatenate the code to it before feeding it to the compiler. Getting the line information from Lua is, again, straightforward:

>
```
static const char *itcc_add_line_info(lua_State *L,int idx)
{
lua_Debug info;
/*------------------------------------------------------
; get caller info and return linenumber and source file
;-------------------------------------------------------*/
lua_getstack(L,3,&info);
lua_getinfo(L,"lS",&info);
/*-----------------------------------------------------------------------
; line number will be negative if it's a Lua function written in C or if
; the source can't be located. If that's the case just return the
; original string, otherwise, prepend a #line directive and return the
; modified string.
;------------------------------------------------------------------------*/
if (info.currentline > 0)
{
char lineinfo[FILENAME_MAX + 32];
size_t len = snprintf(
lineinfo,
sizeof(lineinfo),
"#line %d \"%s\"\n",
info.currentline,
info.short_src
);
lua_pushlstring(L,lineinfo,len);
lua_pushvalue(L,idx);
lua_concat(L,2);
return lua_tostring(L,-1);
}
else
return lua_tostring(L,idx);
}
```

Add the call to that function in the right spot, and voilà, you now have an uncle named Robert [6].

As I was coding this up and testing it, I realized something else—I don't always include the code as a literal to the function. Sometimes, I declare the code as a variable:

>
```
cc = require "org.conman.cc"
LOAD = [[
#include <lua.h>
int load(lua_State *L)
{
double load[3];
getloadavg(load,3);
lua_pushnumber(L,load[0]);
lua_pushnumber(L,load[1])
lua_pushnumber(L,load[2]);
return 3;
}
]]
load = cc.compile('load',LOAD)
print(load())
```

I do this when the C code is longer, or I have additional parameters to pass to cc.compile(). And in this case, the line number reported will be the call site (for the above example, line 18) instead of the actual error (line 12).

Well … darn.

It wasn't as easy as I thought it would be.

[1] http://www.lua.org/

[2] https://github.com/spc476/lua-conmanorg/blob/master/src/tcc.c

[3] https://github.com/spc476/lua-conmanorg/blob/master/lua/cc.lua

[4] http://lua-users.org/lists/lua-l/2014-05/msg00403.html

[5] http://www.lua.org/lua-l.html

[6] http://en.wikipedia.org/wiki/Bob's_your_uncle

Gemini Mention this post

Contact the author