/*
// GOTOTINE BEGIN labelPosition
から
// GOTOTINE END
まで、以下の処理を行う
(labelPositionは任意の名前)

yield 返り値;
を
{labelPosition=数値;return 返り値;_数値:;}
に置き換える
(返り値は省略可)

最初に
static assert(is(int == typeof(labelPosition)));
if (labelPosition == 1) goto _1;
...
if (labelPosition == yield.length) goto _yield.length;
を追加する
*/

import std.cstream, std.string, std.stream;
import std.regexp : RegExp;

void main()
{
	//return; // for unittest
	dout.writefln("// このファイルはgototineで自動生成しました");
	while (!din.eof)
	{
		auto line = cast(string)din.readLine();
		if (isBegin(line))
		{
			auto counterName = getCounterName(line);
			dout.writefln(
				"%sstatic assert(is(int == typeof(%s)));",
				repeat("\t", line.count("\t")),
				counterName
			);
			
			auto ms = new MemoryStream();
			int yieldLength = 0;
			while (true)
			{
				if (din.eof) throw new Error("error");
				auto line2 = cast(string)din.readLine();
				if (isEnd(line2)) break;
				else if (isYield(line2))
				{
					yieldLength++;
					ms.writeLine(line2.replaceYield(counterName, yieldLength));
				}
				else ms.writeLine(line2);
			}
			
			for (int i = 1; i <= yieldLength; i++)
			{
				dout.writefln(
					"%sif (%s == %d) goto _%d;",
					repeat("\t", line.count("\t")),
					counterName,
					i,
					i
				);
			}
			ms.seekSet(0);
			while (!ms.eof) dout.writeLine(ms.readLine());
		}
		else dout.writeLine(line);
	}
}

unittest
{
	assert(!isBegin("aa"));
	assert(isBegin("\t\t// GOTOTINE BEGIN labelPosition"));
}

bool isBegin(string a)
{
	auto b = a.split();
	return b.length == 4 && b[0] == "//" && b[1] == "GOTOTINE" && b[2] == "BEGIN";
}

unittest
{
	assert(!isEnd("bb"));
	assert(isEnd("\t\t// GOTOTINE END"));
}

bool isEnd(string a)
{
	auto b = a.split();
	return b.length == 3 && b[0] == "//" && b[1] == "GOTOTINE" && b[2] == "END";
}

unittest
{
	assert(!isYield("cc"));
	assert(isYield("\t\tyield;"));
	assert(isYield("\t\tyield 1;"));
	assert(isYield("\t\tyield \"hoge\";"));
	assert(isYield("for (i = 0; i < 10; i++) yield;"));
	assert(isYield("\t\tif (false) yield \"foo\";"));
}

bool isYield(string a)
{
	return std.regexp.find(a, `yield.*;`) != -1;
}

unittest
{
	assert("labelPosition" == getCounterName("\t\t// GOTOTINE BEGIN labelPosition"));
}

string getCounterName(string a)
in
{
	assert(isBegin(a));
}
body
{
	return a.split()[3];
}

unittest
{
	assert("\t\t{lp=1;return;_1:;}" == replaceYield("\t\tyield;", "lp", 1));
	assert("\t\t{lp=2;return 1;_2:;}" == replaceYield("\t\tyield 1;", "lp", 2));
	assert(`{lp=3;return "hoge";_3:;}` == replaceYield(`yield "hoge";`, "lp", 3));
	assert(
		"for (i = 0; i < 10; i++) {lp=4;return;_4:;}"
		== replaceYield("for (i = 0; i < 10; i++) yield;", "lp", 4)
	);
	assert(`if (true) {lp=5;return "foo";_5:;}` == replaceYield(`if (true) yield "foo";`, "lp", 5));
}

string replaceYield(string a, string counterName, int yieldLength)
in
{
	assert(isYield(a));
}
body
{
	return std.regexp.sub(
		a,
		`yield.*;`,
		delegate string(RegExp m)
		{
			auto ret = m.match(0).replace("yield", "return");
			return format("{%s=%d;%s_%d:;}", counterName, yieldLength, ret, yieldLength);
		}
	);
}
