天天看點

d串插件示例

原文在此

還有一篇

還有這裡

還有這裡都可以看看.元程式設計相關的.

我們想要:

enum sql = `
	CREATE TABLE Person (
		id INTEGER NOT NULL,
		name TEXT,
		birthday DATE
	);
`;

/+
	通過上面生成下面:

	class Person {
		int id;
		string text;
		Date birthday;

		void save() {
			/* 忽略實作 */
		}
	}
+/
           
class ObjectImpl(some_arguments) {
		// 實作
	}

	mixin("alias " ~ some_name ~ " ObjectImpl!(whatever, args);");
           
struct 結查列 {
	string name;
	string type;
}

struct 結查表 {
	string name;
	結查列[] 列;
}

結查表 解析結查語句(string sql) {
	結查表 table;//sql解析

	// 省略實作
	table.name = "Person";//名字
	table.列 = [
		結查列("id", "INTEGER"),
		結查列("name", "TEXT"),
		結查列("birthday", "DATE"),
	];

	return table;
}//這是解析sql剩下的


//先分解,插件模闆聲明+取串

mixin template 結查表對象(string sql) {//@2
	// sql轉D,編譯時轉換
	template 結查變量類型(string 結查類型) {
		static if(結查類型 == "INTEGER")
			alias 結查變量類型 = int;
		else static if(結查類型 == "DATE") {
			import std.datetime;
			alias 結查變量類型 = Date;
		} else static if(結查類型 == "TEXT")
			alias 結查變量類型 = string;
		else static assert(0, "未知類型" ~ 結查類型);
	}//變量類型轉換

	// 使用者定義反射
	struct 結查列 {
		string name;
	}//重要的是結查表.

	// 生成變量,一次一個,用小串插件
	mixin template 結查變量(結查列[]列){//重點在此
		mixin("
			//自定義屬性,用于反射
			@結查列(列[0].name)
			//串中有類型轉換,用遞歸
			結查變量類型!(列[0].type) " ~ 列[0].name ~ ";");//第一個在這裡.
		static if(列.length > 1)
			mixin 結查變量!(列[1 .. $]);
	}//一堆變量,這裡沒有定義結果列第一個變量.

	// 普通聲明加變量插件
	class 我們結查表對象 {
		//待加變量
		mixin 結查變量!(解析結查語句(sql).列);
        //這裡插入變量
		void save() {//儲存函數
			import std.stdio;
			import std.traits;

			//用反射檢視生成的東西
			foreach(idx, variable; getSymbolsByUDA!(我們結查表對象, 結查列)) {
				auto name = getSymbolsByUDA!(我們結查表對象, 結查列)[idx].stringof;
				writeln(name, " = ", variable);
			}//檢視

		}
	}

	// 串插件中再用别名來取名字
	mixin("alias " ~ 解析結查語句(sql).name ~ " = 我們結查表對象;");//用别名來定義我們的類.
}

//混合所有,搞定
mixin 結查表對象!(sql);//@1

void main() {
	auto person = new Person;
	person.id = 10;
	person.save();
}