use core:io;
use core:lang;
use lang:bs:macro;
use core:asm;

lang:PkgReader reader(Url[] files, Package pkg) on Compiler {
	lang:FilePkgReader(files, pkg, (x) => DemoFileReader(x));
}

class DemoFileReader extends lang:FileReader {
	init(lang:FileInfo info) {
		init(info) {}
	}

	void readFunctions() : override {
		Parser<SRoot> parser;
		parser.parse(info.contents, info.url, info.start);
		if (parser.hasError)
			throw parser.error();

		DemoFunction[] functions = parser.tree().transform();
		for (f in functions)
			info.pkg.add(f);
	}

	lang:bnf:Rule rootRule() : override {
		named{SRoot};
	}
}

class DemoFunction extends Function {
	Str[] paramNames;
	SExpr body;

	init(SrcPos pos, Str name, Str[] paramNames, SExpr body) {
		Value[] valParams;
		for (x in paramNames)
			valParams << named{Int};

		init(pos, named{Int}, name, valParams) {
			paramNames = paramNames;
			body = body;
		}

		setCode(LazyCode(&this.createCode));
	}

	private CodeGen createCode() {
		CodeGen gen(runOn, isMember, result);

		gen.l << prolog();

		DemoLookup lookup(this);
		for (name in paramNames) {
			Var param = gen.l.createParam(named{Int}.desc());
			lookup.addVar(pos, name, param);
		}

		Expr e = body.transform(Scope(lookup));
		e.code(gen);

		gen.l << fnRet(eax);

		return gen;
	}
}

class DemoLookup extends NameLookup {
	private Str->DemoVar variables;

	init(NameLookup parent) {
		init(parent) {}
	}

	void addVar(SrcPos pos, Str name, Var v) {
		DemoVar var(pos, name, v);
		var.parentLookup = this;
		variables.put(name, var);
	}

	Named? find(SimplePart part, Scope scope) : override {
		if (part.params.empty) {
			if (found = variables.at(part.name)) {
				return found;
			}
		}
		null;
	}
}

class DemoVar extends Variable {
	Var codeVar;

	init(SrcPos pos, Str name, Var codeVar) {
		init(pos, name, named{Int}) {
			codeVar = codeVar;
		}
	}
}
