/* Dialect - Code Output Formatter
 * Copyright (C) 2001-2002  Jay Freeman (saurik)
*/

/*
 *        Redistribution and use in source and binary
 * forms, with or without modification, are permitted
 * provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer in the documentation
 *    and/or other materials provided with the
 *    distribution.
 * 3. The name of the author may not be used to endorse
 *    or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "stdafx.h"
#include "CSharpDialect.h"

#include "ilengineer/Ops/MSIL.h"
#include "ilengineer/Ops/ILE.h"

void Dialect::CSharpDialect::Formulate(ILEngineer::Operation *op) {
	const type_info &type = typeid(*op);
	const Metallurgy::Module &import = *op->getMethod()->getImport();
	const Metallurgy::Method &method = op->getMethod()->getMethodDef();

	if (op->isScope())
		*wout << L"(";

	if (op->isSkip()) {
		Formulate(op->getOperations()[0]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Add)) {
		Formulate(op->getOperations()[0]);
		*wout << L" + ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::And)) {
		ILEngineer::Ops::MSIL::And *logic = dynamic_cast<ILEngineer::Ops::MSIL::And *>(op);
		Formulate(logic->getOperations()[0]);
		*wout << L" & ";
		Formulate(logic->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Box)) {
		ILEngineer::Ops::MSIL::Box *box = dynamic_cast<ILEngineer::Ops::MSIL::Box *>(op);
		Formulate(box->getValue());

	} else if (type == typeid(ILEngineer::Ops::MSIL::Branch)) {
		*wout << L"-> 0x" << (void *) dynamic_cast<ILEngineer::Ops::MSIL::Branch *>(op)->getTarget();

	} else if (type == typeid(ILEngineer::Ops::MSIL::BranchTrue)) {
		*wout << L"if (";
		Formulate(dynamic_cast<ILEngineer::Ops::MSIL::BranchTrue *>(op)->getValue());
		*wout << L") 0x" << (void *) dynamic_cast<ILEngineer::Ops::MSIL::BranchTrue *>(op)->getTarget();

	} else if (type == typeid(ILEngineer::Ops::MSIL::BranchFalse)) {
		*wout << L"if not (";
		Formulate(dynamic_cast<ILEngineer::Ops::MSIL::BranchFalse *>(op)->getValue());
		*wout << L") 0x" << (void *) dynamic_cast<ILEngineer::Ops::MSIL::BranchFalse *>(op)->getTarget();

	} else if (type == typeid(ILEngineer::Ops::ILE::Break)) {
		*wout << L"break";

	} else if (type == typeid(ILEngineer::Ops::MSIL::Call)) {
        ILEngineer::Ops::MSIL::Call *call = dynamic_cast<ILEngineer::Ops::MSIL::Call *>(op);
		Metallurgy::Member *member = call->getMember();
        if (!member->getName().getFull().compare(0, 3, L"op_"))
            PrintOperator(call);
        else {
		    ILEngineer::OperationVector::iterator opI(op->getOperations().begin());
		    if (member->getSignature()->getHasThis()) {
			    Formulate(*(opI++));
			    if (member->getName().getFull() == L".ctor") {
				    *wout << L" = new ";
                    Formulate(member->getType()->getElement());
			    } else
				    *wout << L"." << member->getName().getFull();
		    } else {
			    const Metallurgy::IHasElement *type = member->getType();
			    if (type != NULL) {
				    Formulate(type->getElement());
				    *wout << L".";
			    }
			    *wout << member->getName().getFull();
		    }
		    *wout << L"(";
		    for (bool notFirst(false); opI != op->getOperations().end(); opI++, notFirst = true) {
			    if (notFirst)
				    *wout << L", ";
			    Formulate(*opI);
		    } *wout << L")";
        }

	} else if (type == typeid(ILEngineer::Ops::MSIL::CastClass)) {
		ILEngineer::Ops::MSIL::CastClass *cast = dynamic_cast<ILEngineer::Ops::MSIL::CastClass *>(op);
		*wout << L"(";
		Metallurgy::Element *element = new Metallurgy::Element(dynamic_cast<Metallurgy::IHasElement *>(import.ResolveToken(cast->getValueType())));
		Formulate(element);
		delete element;
		*wout << L") ";
		Formulate(cast->getValue());

	} else if (type == typeid(ILEngineer::Ops::MSIL::CompareGreaterThan)) {
		ILEngineer::Ops::MSIL::CompareGreaterThan *compare = dynamic_cast<ILEngineer::Ops::MSIL::CompareGreaterThan *>(op);
		Formulate(compare->getOperations()[0]);
		*wout << L" > ";
		Formulate(compare->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::ILE::CompareGreaterThanEqual)) {
		ILEngineer::Ops::ILE::CompareGreaterThanEqual *compare = dynamic_cast<ILEngineer::Ops::ILE::CompareGreaterThanEqual *>(op);
		Formulate(compare->getOperations()[0]);
		*wout << L" >= ";
		Formulate(compare->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::CompareLessThan)) {
		ILEngineer::Ops::MSIL::CompareLessThan *compare = dynamic_cast<ILEngineer::Ops::MSIL::CompareLessThan *>(op);
		Formulate(compare->getOperations()[0]);
		*wout << L" < ";
		Formulate(compare->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::ILE::CompareLessThanEqual)) {
		ILEngineer::Ops::ILE::CompareLessThanEqual *compare = dynamic_cast<ILEngineer::Ops::ILE::CompareLessThanEqual *>(op);
		Formulate(compare->getOperations()[0]);
		*wout << L" <= ";
		Formulate(compare->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Convert)) {
		ILEngineer::Ops::MSIL::Convert *conv = dynamic_cast<ILEngineer::Ops::MSIL::Convert *>(op);
		if (conv->getChecked())
			*wout << L"checked(";
		*wout << L"(";
		Formulate(conv->getType());
		*wout << L") ";
		Formulate(conv->getValue());
		if (conv->getChecked())
			*wout << L")";

	} else if (type == typeid(ILEngineer::Ops::ILE::CompareLessThanEqual)) {
		ILEngineer::Ops::ILE::CompareLessThanEqual *compare = dynamic_cast<ILEngineer::Ops::ILE::CompareLessThanEqual *>(op);
		Formulate(compare->getOperations()[0]);
		*wout << L" <= ";
		Formulate(compare->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::ILE::Continue)) {
		*wout << L"continue";

	} else if (type == typeid(ILEngineer::Ops::ILE::Goto)) {
		*wout << L"goto i" << dynamic_cast<ILEngineer::Ops::ILE::Goto *>(op)->getLabel();

	} else if (type == typeid(ILEngineer::Ops::ILE::OrEqualsField)) {
		ILEngineer::Ops::ILE::OrEqualsField *field = dynamic_cast<ILEngineer::Ops::ILE::OrEqualsField *>(op);
		Formulate(field->getObj());
		*wout << L"." << field->getMember().getName().getFull() << L" |= ";
		Formulate(field->getValue());

	} else if (type == typeid(ILEngineer::Ops::ILE::OrEqualsLocal)) {
		ILEngineer::Ops::ILE::OrEqualsLocal *local = dynamic_cast<ILEngineer::Ops::ILE::OrEqualsLocal *>(op);
		*wout << L"local" << local->getIndx();
		*wout << L" |= ";
		Formulate(local->getValue());

	} else if (type == typeid(ILEngineer::Ops::ILE::OrEqualsStaticField)) {
		ILEngineer::Ops::ILE::OrEqualsStaticField *ore = dynamic_cast<ILEngineer::Ops::ILE::OrEqualsStaticField *>(op);
		Metallurgy::Member &field = ore->getMember();
        Formulate(field.getType()->getElement());
		*wout << L"." << field.getName().getFull() << L" += ";
		Formulate(ore->getValue());

	} else if (type == typeid(ILEngineer::Ops::ILE::PlusEqualsField)) {
		ILEngineer::Ops::ILE::PlusEqualsField *field = dynamic_cast<ILEngineer::Ops::ILE::PlusEqualsField *>(op);
		Formulate(field->getObj());
		*wout << L"." << field->getField()->getName().getFull() << L" += ";
		Formulate(field->getValue());

	} else if (type == typeid(ILEngineer::Ops::ILE::PlusEqualsLocal)) {
		ILEngineer::Ops::ILE::PlusEqualsLocal *inc = dynamic_cast<ILEngineer::Ops::ILE::PlusEqualsLocal *>(op);
		*wout << L"local" << inc->getIndx();
		ILEngineer::Ops::MSIL::LoadI4Constant *constant = dynamic_cast<ILEngineer::Ops::MSIL::LoadI4Constant *>(inc->getValue());
		if (constant != NULL && constant->getConstant() == 1)
			*wout << L"++";
		else if (constant != NULL && constant->getConstant() == -1)
			*wout << L"--";
		else {
			*wout << L" += ";
			Formulate(inc->getValue());
		}

	} else if (type == typeid(ILEngineer::Ops::ILE::PlusEqualsStaticField)) {
		ILEngineer::Ops::ILE::PlusEqualsStaticField *inc = dynamic_cast<ILEngineer::Ops::ILE::PlusEqualsStaticField *>(op);
		Metallurgy::Field *field = dynamic_cast<Metallurgy::Field *>(inc->getField());
        Formulate(field->getType()->getElement());
		*wout << L"." << field->getName().getFull() << L" += ";
		Formulate(inc->getValue());

	} else if (type == typeid(ILEngineer::Ops::MSIL::Div)) {
		Formulate(op->getOperations()[0]);
		*wout << L" / ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::IsInstance)) {
		ILEngineer::Ops::MSIL::IsInstance *isinst = dynamic_cast<ILEngineer::Ops::MSIL::IsInstance *>(op);
		Formulate(isinst->getValue());
		*wout << L" as ";
		Metallurgy::Element *element = new Metallurgy::Element(isinst->getValueType());
		Formulate(element);
		delete element;

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadArgument)) {
		const Metallurgy::Method &method = op->getMethod()->getMethodDef();
		int num = dynamic_cast<ILEngineer::Ops::MSIL::LoadArgument *>(op)->getNum();
		*wout << ((method.getSignature()->getHasThis() && num == 0) ? L"this" : method.getArgName(num));

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadArgumentAddress)) {
		const Metallurgy::Method &method = op->getMethod()->getMethodDef();
		int num = dynamic_cast<ILEngineer::Ops::MSIL::LoadArgumentAddress *>(op)->getNum();
		*wout << ((method.getSignature()->getHasThis() && num == 0) ? L"this" : method.getArgName(num));

	} else if (type == typeid(ILEngineer::Ops::ILE::LoadBoolConstant)) {
		*wout << (dynamic_cast<ILEngineer::Ops::ILE::LoadBoolConstant *>(op)->getConstant() ? L"true" : L"false");

	} else if (type == typeid(ILEngineer::Ops::ILE::LoadCharConstant)) {
		*wout << L"'";
		Formulate(dynamic_cast<ILEngineer::Ops::ILE::LoadCharConstant *>(op)->getConstant());
		*wout << L"'";

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadElement)) {
		ILEngineer::Ops::MSIL::LoadElement *store = dynamic_cast<ILEngineer::Ops::MSIL::LoadElement *>(op);
		Formulate(store->getArray());
		*wout << L"[";
		Formulate(store->getIndex());
		*wout << L"]";

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadElementAddress)) {
		ILEngineer::Ops::MSIL::LoadElementAddress *store = dynamic_cast<ILEngineer::Ops::MSIL::LoadElementAddress *>(op);
		Formulate(store->getArray());
		*wout << L"[";
		Formulate(store->getIndex());
		*wout << L"]";

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadI4Constant)) {
		*wout << dynamic_cast<ILEngineer::Ops::MSIL::LoadI4Constant *>(op)->getConstant();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadI8Constant)) {
		*wout << (uint32_t) dynamic_cast<ILEngineer::Ops::MSIL::LoadI8Constant *>(op)->getConstant();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadR4Constant)) {
		*wout << dynamic_cast<ILEngineer::Ops::MSIL::LoadR4Constant *>(op)->getConstant();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadR8Constant)) {
		*wout << dynamic_cast<ILEngineer::Ops::MSIL::LoadR8Constant *>(op)->getConstant();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadU4Constant)) {
		*wout << dynamic_cast<ILEngineer::Ops::MSIL::LoadU4Constant *>(op)->getConstant();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadField)) {
		ILEngineer::Ops::MSIL::LoadField *field = dynamic_cast<ILEngineer::Ops::MSIL::LoadField *>(op);
		Formulate(field->getOperations()[0]);
		*wout << L"." << field->getMember().getName().getFull();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadFieldAddress)) {
		ILEngineer::Ops::MSIL::LoadFieldAddress *field = dynamic_cast<ILEngineer::Ops::MSIL::LoadFieldAddress *>(op);
		Formulate(field->getObj());
		*wout << L"." << field->getMember().getName().getFull();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadFunction)) {
		Metallurgy::Member *member = dynamic_cast<Metallurgy::Member *>(import.ResolveToken(dynamic_cast<ILEngineer::Ops::MSIL::LoadFunction *>(op)->getFunction()));
        if (!member->getSignature()->getHasThis()) {
            Formulate(member->getType()->getElement());
			*wout << L".";
        }
		*wout << member->getName().getFull();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadLength)) {
		Formulate(dynamic_cast<ILEngineer::Ops::MSIL::LoadLength *>(op)->getArray());
		*wout << L".Length";

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadLocal)) {
		*wout << L"local" << dynamic_cast<ILEngineer::Ops::MSIL::LoadLocal *>(op)->getIndx();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadLocalAddress)) {
		*wout << L"local" << dynamic_cast<ILEngineer::Ops::MSIL::LoadLocalAddress *>(op)->getIndx();

	} else if (type == typeid(ILEngineer::Ops::ILE::LoadProperty)) {
		ILEngineer::Ops::ILE::LoadProperty *property = dynamic_cast<ILEngineer::Ops::ILE::LoadProperty *>(op);
		Metallurgy::Member &member = property->getMember();
		if (member.getSignature()->getHasThis())
			Formulate(property->getOperations()[0]);
		else
			Formulate(member.getType()->getElement());
		*wout << L"." << member.getName().getFull().substr(4);

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadNull)) {
		*wout << L"null";

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadStaticField)) {
		/*Metallurgy::MetaField &field = import.openField(dynamic_cast<ILEngineer::Ops::MSIL::LoadStaticField *>(op)->getField());
		if (field.getTypeToken() != method.getTypeToken())
			*wout << field.getType()->getName().getSpace() << L".";
		*wout << field.getType()->getName().getShort() << L"." << field.getName();*/
		Metallurgy::Member *field = dynamic_cast<ILEngineer::Ops::MSIL::LoadStaticField *>(op)->getField();
		const Metallurgy::IHasElement *type = field->getType();
		if (type != NULL) {
            Formulate(type->getElement());
			*wout << L".";
		}
		*wout << field->getName().getFull();

	} else if (type == typeid(ILEngineer::Ops::MSIL::LoadString)) {
		*wout << L"\"";
		Formulate(import.getUserString(dynamic_cast<ILEngineer::Ops::MSIL::LoadString *>(op)->getString()));
		*wout << L"\"";

	} else if (type == typeid(ILEngineer::Ops::ILE::LogicAnd)) {
		ILEngineer::Ops::ILE::LogicAnd *logic = dynamic_cast<ILEngineer::Ops::ILE::LogicAnd *>(op);
		Formulate(logic->getOperations()[0]);
		*wout << L" && ";
		Formulate(logic->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::CompareEqual)) {
		ILEngineer::Ops::MSIL::CompareEqual *logic = dynamic_cast<ILEngineer::Ops::MSIL::CompareEqual *>(op);
		Formulate(logic->getOperations()[0]);
		*wout << L" == ";
		Formulate(logic->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::ILE::LogicOr)) {
		ILEngineer::Ops::ILE::LogicOr *logic = dynamic_cast<ILEngineer::Ops::ILE::LogicOr *>(op);
		Formulate(logic->getOperations()[0]);
		*wout << L" || ";
		Formulate(logic->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::ILE::LogicNot)) {
		*wout << L"!(";
		Formulate(dynamic_cast<ILEngineer::Ops::ILE::LogicNot *>(op)->getOperations()[0]);
		*wout << L")";

	} else if (type == typeid(ILEngineer::Ops::ILE::CompareNotEqual)) {
		ILEngineer::Ops::ILE::CompareNotEqual *logic = dynamic_cast<ILEngineer::Ops::ILE::CompareNotEqual *>(op);
		Formulate(logic->getOperations()[0]);
		*wout << L" != ";
		Formulate(logic->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Mul)) {
		Formulate(op->getOperations()[0]);
		*wout << L" * ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Neg)) {
		*wout << L"-";
		Formulate(op->getOperations()[0]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::NewArray)) {
		ILEngineer::Ops::MSIL::NewArray *newarr = dynamic_cast<ILEngineer::Ops::MSIL::NewArray *>(op);
		*wout << L"new ";
		Formulate(&Metallurgy::Element(dynamic_cast<Metallurgy::IHasElement *>(import.ResolveToken(newarr->getEType()))));
		*wout << L"[";
		Formulate(newarr->getNumElems());
		*wout << L"]";

	} else if (type == typeid(ILEngineer::Ops::MSIL::NewObject)) {
		*wout << L"new ";
		ILEngineer::Ops::MSIL::NewObject *newobj = dynamic_cast<ILEngineer::Ops::MSIL::NewObject *>(op);
		Metallurgy::Member *ctor = dynamic_cast<Metallurgy::Member *>(import.ResolveToken(newobj->getCtor()));
		Formulate(&Metallurgy::Element(ctor->getType()));
		*wout << L"(";

		bool notFirst(false);
		for (ILEngineer::OperationVector::iterator opI(op->getOperations().begin()); opI != op->getOperations().end(); opI++, notFirst = true) {
			if (notFirst)
				*wout << L", ";
			Formulate(*opI);
		} *wout << L")";

	} else if (type == typeid(ILEngineer::Ops::MSIL::Or)) {
		Formulate(op->getOperations()[0]);
		*wout << L" | ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Rem)) {
		Formulate(op->getOperations()[0]);
		*wout << L" % ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::ReThrow)) {
		*wout << L"throw";

	} else if (type == typeid(ILEngineer::Ops::MSIL::Return)) {
		*wout << L"return";

	} else if (type == typeid(ILEngineer::Ops::MSIL::ReturnValue)) {
		*wout << L"return ";
		Formulate(op->getOperations()[0]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::ShL)) {
		Formulate(op->getOperations()[0]);
		*wout << L" << ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::ShR)) {
		Formulate(op->getOperations()[0]);
		*wout << L" >> ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::StoreArgument)) {
		const Metallurgy::Method &method = op->getMethod()->getMethodDef();
		ILEngineer::Ops::MSIL::StoreArgument *store = dynamic_cast<ILEngineer::Ops::MSIL::StoreArgument *>(op);
		int num = store->getNum();
		*wout << ((method.getSignature()->getHasThis() && num == 0) ? L"this" : method.getArgName(num)) << L" = ";
		Formulate(store->getValue());

	} else if (type == typeid(ILEngineer::Ops::MSIL::StoreElement)) {
		ILEngineer::Ops::MSIL::StoreElement *store = dynamic_cast<ILEngineer::Ops::MSIL::StoreElement *>(op);
		Formulate(store->getArray());
		*wout << L"[";
		Formulate(store->getIndex());
		*wout << L"] = ";
		Formulate(store->getValue());

	} else if (type == typeid(ILEngineer::Ops::MSIL::StoreField)) {
		ILEngineer::Ops::MSIL::StoreField *store = dynamic_cast<ILEngineer::Ops::MSIL::StoreField *>(op);
		Formulate(store->getOperations()[0]);
		*wout << L"." << store->getMember()->getName().getFull() << L" = ";
		Formulate(store->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::ILE::StoreProperty)) {
		ILEngineer::Ops::ILE::StoreProperty *property = dynamic_cast<ILEngineer::Ops::ILE::StoreProperty *>(op);
		Metallurgy::Member *member = property->getMember();
		int i(0);
		if (member->getSignature()->getHasThis())
			Formulate(property->getOperations()[i++]);
		else
			Formulate(member->getType()->getElement());
		*wout << L"." << member->getName().getFull().substr(4) << L" = ";
		Formulate(property->getOperations()[i]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::StoreIndirectRef)) {
		ILEngineer::Ops::MSIL::StoreIndirectRef *store = dynamic_cast<ILEngineer::Ops::MSIL::StoreIndirectRef *>(op);
		Formulate(store->getAddr());
		*wout << L" = ";
		Formulate(store->getVal());

	} else if (type == typeid(ILEngineer::Ops::MSIL::StoreLocal)) {
		ILEngineer::Ops::MSIL::StoreLocal *store = dynamic_cast<ILEngineer::Ops::MSIL::StoreLocal *>(op);
		*wout << L"local" << store->getIndx() << L" = ";
		Formulate(store->getValue());

	} else if (type == typeid(ILEngineer::Ops::MSIL::StoreStaticField)) {
		ILEngineer::Ops::MSIL::StoreStaticField *store = dynamic_cast<ILEngineer::Ops::MSIL::StoreStaticField *>(op);
		Metallurgy::Member *field = store->getMember();
		const Metallurgy::IHasElement *type = field->getType();
		if (type != NULL) {
            Formulate(method.getType()->getElement());
            *wout << L".";
		}
		*wout << field->getName().getFull() << L" = ";
		Formulate(store->getValue());

	} else if (type == typeid(ILEngineer::Ops::ILE::StringConcat)) {
		ILEngineer::Ops::ILE::StringConcat *string = dynamic_cast<ILEngineer::Ops::ILE::StringConcat *>(op);
		bool notFirst(false);
		for (ILEngineer::OperationVector::iterator opI(string->getOperations().begin()); opI != string->getOperations().end(); opI++) {
			if (notFirst)
				*wout << L" + ";
			else
				notFirst = true;
			Formulate(*opI);
		}

	} else if (type == typeid(ILEngineer::Ops::ILE::StringEquals)) {
		ILEngineer::Ops::ILE::StringEquals *string = dynamic_cast<ILEngineer::Ops::ILE::StringEquals *>(op);
		Formulate(string->getOperations()[0]);
		*wout << L" == ";
		Formulate(string->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::ILE::StringNotEquals)) {
		ILEngineer::Ops::ILE::StringNotEquals *string = dynamic_cast<ILEngineer::Ops::ILE::StringNotEquals *>(op);
		Formulate(string->getOperations()[0]);
		*wout << L" != ";
		Formulate(string->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Sub)) {
		Formulate(op->getOperations()[0]);
		*wout << L" - ";
		Formulate(op->getOperations()[1]);

	} else if (type == typeid(ILEngineer::Ops::MSIL::Switch)) {
		ILEngineer::Ops::MSIL::Switch::TargetMap &targets = dynamic_cast<ILEngineer::Ops::MSIL::Switch *>(op)->getTargets();
		*wout << L"switch";
		for (ILEngineer::Ops::MSIL::Switch::TargetMap::iterator tgI(targets.begin()); tgI != targets.end(); tgI++)
			*wout << L" (" << tgI->first << L": " << tgI->second << L")";

	} else if (type == typeid(ILEngineer::Ops::MSIL::Throw)) {
		*wout << L"throw ";
		Formulate(dynamic_cast<ILEngineer::Ops::MSIL::Throw *>(op)->getObject());

	} else if (type == typeid(ILEngineer::Ops::ILE::TypeOf)) {
		ILEngineer::Ops::ILE::TypeOf *type = dynamic_cast<ILEngineer::Ops::ILE::TypeOf *>(op);
		*wout << L"typeof(";
		Formulate(&Metallurgy::Element(dynamic_cast<Metallurgy::IHasElement *>(import.ResolveToken(type->getToken()))));
		*wout << L")";

	} else if (type == typeid(ILEngineer::Ops::MSIL::Unbox)) {
		ILEngineer::Ops::MSIL::Unbox *unbox = dynamic_cast<ILEngineer::Ops::MSIL::Unbox *>(op);
		*wout << L"(";
		Formulate(&Metallurgy::Element(dynamic_cast<Metallurgy::IHasElement *>(import.ResolveToken(unbox->getValueType()))));
		*wout << L") ";
		Formulate(unbox->getValue());

	} else {
		wchar_t buff[1024];
		buff[1023] = '\0';
		_snwprintf(buff, 1023, L"<{ %S }>", type.name());
		*wout << buff;
	}

	if (op->isScope())
		*wout << L")";
}