Can Metaprogramming Help Here?

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Feb 26 20:42:50 UTC 2021


On Fri, Feb 26, 2021 at 11:37:18AM -0800, H. S. Teoh via Digitalmars-d-learn wrote:
> On Wed, Feb 24, 2021 at 08:10:30PM +0000, Mike Brown via Digitalmars-d-learn wrote:
> [...]
> > Thank you for the reply. Im struggling extending this to get the
> > nesting working.
[...]

Alright, here's an actual working example. Instead of using classes, I
decided to use templates instead, but the underlying concept is the
same:

-------------------------------------snip--------------------------------------
template branch(string _ident, _values...) {
	enum ident = _ident;
	alias values = _values;
}

// I used strings for easier concatenation to code, otherwise we have to use
// std.conv to convert it which is slow in CTFE.
static immutable string[] primes = [
	"2", "3", "5", "7", "11", "13", "17", "19", "23", "29", "31", "37",
	"41", // fill in more if you need to
];

string genPrimeId(size_t[] indices)
	in (indices.length > 0)
{
	string result = primes[indices[0]];
	foreach (i; indices[1 .. $]) {
		result ~= "*" ~ primes[i];
	}
	return result;
}

template primeIdsImpl(size_t[] indices, Args...)
	if (indices.length > 0 && Args.length > 0)
{
	static if (Args.length == 1) {
		static if (is(typeof(Args[0]) == string)) {
			enum primeIdsImpl = Args[0] ~ "=" ~ genPrimeId(indices) ~ ",\n";
		} else {
			enum primeIdsImpl = Args[0].ident ~ "=" ~ genPrimeId(indices) ~ ",\n" ~
				primeIdsImpl!(indices ~ [ indices[$-1] + 1 ],
					Args[0].values);
		}
	} else {
		enum primeIdsImpl = primeIdsImpl!(indices, Args[0]) ~
			primeIdsImpl!(indices[0 .. $-1] ~ [ indices[$-1] + 1 ],
					Args[1 .. $]);
	}
}

template primeIds(string enumName, Args...) if (Args.length > 0) {
	enum primeIds = "enum " ~ enumName ~ " {\n" ~
		primeIdsImpl!([0], Args) ~
		"}";
}

mixin(primeIds!("token_type",
	"endOfFile",
	"unknown",
	"newline",
	branch!("identifier",
		"userDefined",
		"var",
		"uses",
		"constructor",
		"do_",
		"end_",
	),
	branch!("operator",
		"copyAssignment",
	),
));

void main() {
	import std;
	writefln("%s", token_type.identifier);
	writefln("%d", token_type.identifier);
}
-------------------------------------snip--------------------------------------


You can change the mixin line to `pragma(msg, ...)` instead to see the
generated code string.

I noticed that the definitions of the first nested identifiers are
different from your original post; I don't know if this is a
misunderstanding on my side or an oversight on your part?  After
identifier=7, the next prime should be 11, not 13, so userDefined should
start with 11*identifier rather than 13*identifier.


T

-- 
Shin: (n.) A device for finding furniture in the dark.


More information about the Digitalmars-d-learn mailing list