...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

How to import without specific symbols


ちょwwwwwwwwwwwwwwwwwwwww

import std.typetuple;


//////////////////////////////////////////////////////////////////////////////

/*
 * 配列 array のすべての要素を,順序を保ってタプルに展開する.
 */
template staticArrayToTuple(alias array)
{
	static if (array.length)
		alias TypeTuple!(array[0], staticArrayToTuple!(array[1 .. $]))
			staticArrayToTuple;
	else
		alias TypeTuple!() staticArrayToTuple;
}

unittest
{
	alias staticArrayToTuple!([ 1, 2, 3 ]) a;
	static assert(is(typeof(a) == TypeTuple!(int, int, int)));
	static assert(a[0] == 1);
	static assert(a[1] == 2);
	static assert(a[2] == 3);
}


//////////////////////////////////////////////////////////////////////////////

/*
 * モジュール mod から xids で指定された識別子以外の識別子を
 * import する選択的 import 文を生成する.
 */
template importExcept(string mod, xids...)
{
	mixin (importExceptGen!(mod, xids).result);
}

// internal
template importExceptGen(string mod, xids...)
{
	// モジュールを仮に import して,識別子を読み込んでおく.
	mixin ("static import " ~ mod ~ ";");

	/*
	 * モジュール内のすべての識別子をタプルとして得る.
	 *
	 * このタプルにはコンパイラ内部だけで使われる識別子が
	 * 含まれている.以下の処理ではまずそれを取り除き.
	 * その後で,xid で指定された識別子を取り除く.
	 */
	mixin ("alias staticArrayToTuple!("
		"__traits(allMembers, " ~ mod ~ ")) ids;");

	/*
	 * 渡された識別子文字列のタプルから,コンパイラ内部だけで
	 * 使われる識別子を取り除き,result に結果のタプルをセットする.
	 */
	template sanitize(ids...)
	{
		template check1(string id)
		{
			/* .stringof を持たないならばコンパイラ内部の識別子なので,
			 * import の対象から除外する.注意: コンパイラ内部の識別子
			 * でも .stringof を持つものがあるので,さらに check2
			 * を使って調べている.*/
			static if (__traits(compiles, mixin(id ~ ".stringof")))
				enum check1 = check2!(mixin(id ~ ".stringof"));
			else
				enum check1 = false;
		}

		template check2(string strof)
		{
			/* allMembers の戻り値には module, package が含まれる.
			 * それらは .stringof を持ったコンパイラ内部の識別子なので,
			 * import の対象から除外する.*/
			enum check2 =
				(strof.length <= 7 || strof[0 .. 7] != "module ") &&
				(strof.length <= 8 || strof[0 .. 8] != "package ") ;
		}

		static if (ids.length)
		{
			enum head = ids[0];
			alias sanitize!(ids[1 .. $]).result tail;

			static if (check1!(mod ~ "." ~ head))
				alias TypeTuple!(head, tail) result;
			else
				alias tail result;
		}
		else
			alias TypeTuple!() result;
	}


	/*
	 * [CTFE] 所望の選択的 import 文を生成する.
	 */
	string generate(ids...)()
	{
		string stmt = "import " ~ mod ~ ": ";

		foreach (id; ids)
		{
			// xid で指定された識別子は除外する.
			foreach (xid; xids)
			{
				if (id != xid)
				{
					stmt ~= id ~ ", ";
					break;
				}
			}
		}
		return stmt[0 .. $ - 2] ~ ";";
	}

	enum result = generate!(sanitize!(ids).result);
}


//////////////////////////////////////////////////////////////////////////////

// テスト
mixin importExcept!("std.stdio", "writeln");
import std.stdio: p = writeln;

static assert(__traits(compiles, writefln));
static assert(!__traits(compiles, writeln));

void main()
{
	p("abc");
}

確かにこういうのは考えたけども.

import std.stdio : !writefln;

is expression, template mixin, stringof, __traitsあたりを使った黒魔術が炸裂.
D言語やべーな.