Lua Notes

Compile-time Counters
Login

Compile-time Counters

From the d forums:

import std;
template counter(){
	template access(int i){
		//pragma(msg,i,"acess");
		enum access=mixin("__LINE__");
	}
	template get_(int i,int sentinel){
		//pragma(msg,i," ",sentinel);
		static if(access!(i)>sentinel){
			enum get_=i;
		} else {
			enum get_=get_!(i+1,sentinel);
	}}
	template get(int i=__LINE__){
		enum setty=mixin("__LINE__");
		alias get=get_!(0,setty);
	}
}
enum x = counter!().get!();
void main(){
	counter!().get!().writeln;
	counter!().get!().writeln;
	counter!().get!().writeln;
	writeln(x);
}

Output:

$ dmd -mixin=mix -run count.d
1
2
3
0

NB. I don't know how this works, except that it's clearly abusing __LINE__ somehow, and it can't compile without that -mixin=mix argument, despite the code not using the file and the file seeming to be only for logging mixin results.

What's black magic in d is straightforward in Nelua:

## local function count()
  ## if not comptime_counter then comptime_counter = 0 end
  in #[comptime_counter]#
  ## comptime_counter = comptime_counter + 1
## end

local x <comptime> = count!()
print(count!())
print(count!())
print(count!())
print(x)

Which is easily confirmed to compile to

int nelua_main(int argc, char** argv) {
  nelua_print_1(1);
  nelua_print_1(2);
  nelua_print_1(3);
  nelua_print_1(0);
  return 0;
}

How does this work as a module?

For d - it doesn't.

/usr/bin/ld: count.o:(.data.rel.ro+0x18): undefined reference to `_D7counter12__ModuleInfoZ'

For Nelua there's only one complication: because this is using a mixed-language macro, with a single line of Nelua code in a Lua function, to use it in multiple libraries you'd need to do one of

  1. make it a global function (risk: name conflicts)
  2. make a Nelua instead of a Lua function to have something to require() (risk: binary bloat)
  3. rewrite it to pure Lua and
    • (for something this simple) call it directly
    • (for more complex code) inject the expression manually
    and do the require() in Lua instead of Nelua

Here's #3, and the simpler case:

-- counter.lua
if not comptime_counter then comptime_counter = -1 end
local function count()
  comptime_counter = comptime_counter + 1
  return comptime_counter
end
return { count = count }

-- count.nelua
## local count = require('counter').count

local x <comptime> = count!()
print(count!())
print(count!())
print(count!())
print(x)